Auto merge of #17783 - BorisChiou:stylo/animation/restrictions, r=nox

stylo: Bug 1374233 - Clamp interpolated values for properties which need to be restricted

Some properties only accept non-negative values, or values greater than or equal to one. It is possible to produce an negative interpolated values while using negative timing functions, so we have to apply a restriction to these values to avoid getting invalid values.

For example, line-height must be non-negative, but the output progress of some timing functions (e,g. cubic-bezier(0.25, -2, 0.75, 1)) may be a negative value, so the interpolated result of line-height is also negative.

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix Bug 1374233.
- [X] These changes do not require tests because we have tests in Gecko side already.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17783)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-08-07 11:05:17 -05:00 committed by GitHub
commit 016ea11cba
56 changed files with 1039 additions and 371 deletions

View file

@ -116,7 +116,7 @@ impl FontContext {
let layout_font_group_cache_key = LayoutFontGroupCacheKey { let layout_font_group_cache_key = LayoutFontGroupCacheKey {
pointer: style.clone(), pointer: style.clone(),
size: style.font_size, size: style.font_size.0,
}; };
if let Some(ref cached_font_group) = self.layout_font_group_cache.get( if let Some(ref cached_font_group) = self.layout_font_group_cache.get(
&layout_font_group_cache_key) { &layout_font_group_cache_key) {
@ -146,7 +146,7 @@ impl FontContext {
Some(ref cached_font_ref) => { Some(ref cached_font_ref) => {
let cached_font = (*cached_font_ref).borrow(); let cached_font = (*cached_font_ref).borrow();
if cached_font.descriptor == desc && if cached_font.descriptor == desc &&
cached_font.requested_pt_size == style.font_size && cached_font.requested_pt_size == style.font_size.0 &&
cached_font.variant == style.font_variant_caps { cached_font.variant == style.font_variant_caps {
fonts.push((*cached_font_ref).clone()); fonts.push((*cached_font_ref).clone());
cache_hit = true; cache_hit = true;
@ -164,7 +164,7 @@ impl FontContext {
Some(template_info) => { Some(template_info) => {
let layout_font = self.create_layout_font(template_info.font_template, let layout_font = self.create_layout_font(template_info.font_template,
desc.clone(), desc.clone(),
style.font_size, style.font_size.0,
style.font_variant_caps, style.font_variant_caps,
template_info.font_key template_info.font_key
.expect("No font key present!")); .expect("No font key present!"));
@ -198,7 +198,7 @@ impl FontContext {
for cached_font_entry in &self.fallback_font_cache { for cached_font_entry in &self.fallback_font_cache {
let cached_font = cached_font_entry.font.borrow(); let cached_font = cached_font_entry.font.borrow();
if cached_font.descriptor == desc && if cached_font.descriptor == desc &&
cached_font.requested_pt_size == style.font_size && cached_font.requested_pt_size == style.font_size.0 &&
cached_font.variant == style.font_variant_caps { cached_font.variant == style.font_variant_caps {
fonts.push(cached_font_entry.font.clone()); fonts.push(cached_font_entry.font.clone());
cache_hit = true; cache_hit = true;
@ -210,7 +210,7 @@ impl FontContext {
let template_info = self.font_cache_thread.last_resort_font_template(desc.clone()); let template_info = self.font_cache_thread.last_resort_font_template(desc.clone());
let layout_font = self.create_layout_font(template_info.font_template, let layout_font = self.create_layout_font(template_info.font_template,
desc.clone(), desc.clone(),
style.font_size, style.font_size.0,
style.font_variant_caps, style.font_variant_caps,
template_info.font_key.expect("No font key present!")); template_info.font_key.expect("No font key present!"));
match layout_font { match layout_font {

View file

@ -1860,10 +1860,10 @@ impl ComputedValueUtils for ComputedValues {
!padding.padding_right.is_definitely_zero() || !padding.padding_right.is_definitely_zero() ||
!padding.padding_bottom.is_definitely_zero() || !padding.padding_bottom.is_definitely_zero() ||
!padding.padding_left.is_definitely_zero() || !padding.padding_left.is_definitely_zero() ||
border.border_top_width != Au(0) || border.border_top_width.0 != Au(0) ||
border.border_right_width != Au(0) || border.border_right_width.0 != Au(0) ||
border.border_bottom_width != Au(0) || border.border_bottom_width.0 != Au(0) ||
border.border_left_width != Au(0) border.border_left_width.0 != Au(0)
} }
} }

View file

@ -1393,7 +1393,7 @@ impl FragmentDisplayListBuilding for Fragment {
box_shadow.base.horizontal, box_shadow.base.horizontal,
box_shadow.base.vertical, box_shadow.base.vertical,
)), )),
box_shadow.base.blur, box_shadow.base.blur.0,
box_shadow.spread, box_shadow.spread,
); );
@ -1408,7 +1408,7 @@ impl FragmentDisplayListBuilding for Fragment {
box_bounds: *absolute_bounds, box_bounds: *absolute_bounds,
color: style.resolve_color(box_shadow.base.color).to_gfx_color(), color: style.resolve_color(box_shadow.base.color).to_gfx_color(),
offset: Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical), offset: Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical),
blur_radius: box_shadow.base.blur, blur_radius: box_shadow.base.blur.0,
spread_radius: box_shadow.spread, spread_radius: box_shadow.spread,
border_radius: model::specified_border_radius(style.get_border() border_radius: model::specified_border_radius(style.get_border()
.border_top_left_radius, .border_top_left_radius,
@ -1577,7 +1577,7 @@ impl FragmentDisplayListBuilding for Fragment {
clip: &Rect<Au>) { clip: &Rect<Au>) {
use style::values::Either; use style::values::Either;
let width = style.get_outline().outline_width; let width = style.get_outline().outline_width.0;
if width == Au(0) { if width == Au(0) {
return return
} }
@ -2054,7 +2054,7 @@ impl FragmentDisplayListBuilding for Fragment {
let effects = self.style().get_effects(); let effects = self.style().get_effects();
let mut filters = effects.filter.0.clone(); let mut filters = effects.filter.0.clone();
if effects.opacity != 1.0 { if effects.opacity != 1.0 {
filters.push(Filter::Opacity(effects.opacity)) filters.push(Filter::Opacity(effects.opacity.into()))
} }
let context_type = match mode { let context_type = match mode {
@ -2129,7 +2129,7 @@ impl FragmentDisplayListBuilding for Fragment {
for shadow in text_shadows.iter().rev() { for shadow in text_shadows.iter().rev() {
state.add_display_item(DisplayItem::PushTextShadow(box PushTextShadowDisplayItem { state.add_display_item(DisplayItem::PushTextShadow(box PushTextShadowDisplayItem {
base: base.clone(), base: base.clone(),
blur_radius: shadow.blur, blur_radius: shadow.blur.0,
offset: Vector2D::new(shadow.horizontal, shadow.vertical), offset: Vector2D::new(shadow.horizontal, shadow.vertical),
color: self.style().resolve_color(shadow.color).to_gfx_color(), color: self.style().resolve_color(shadow.color).to_gfx_color(),
})); }));

View file

@ -137,8 +137,8 @@ impl FlexItem {
min_size: Au(0), min_size: Au(0),
max_size: MAX_AU, max_size: MAX_AU,
index: index, index: index,
flex_grow: flex_grow, flex_grow: flex_grow.into(),
flex_shrink: flex_shrink, flex_shrink: flex_shrink.into(),
order: order, order: order,
is_frozen: false, is_frozen: false,
is_strut: false is_strut: false

View file

@ -2570,13 +2570,13 @@ impl Fragment {
// Box shadows cause us to draw outside our border box. // Box shadows cause us to draw outside our border box.
for box_shadow in &self.style().get_effects().box_shadow.0 { for box_shadow in &self.style().get_effects().box_shadow.0 {
let offset = Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical); let offset = Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical);
let inflation = box_shadow.spread + box_shadow.base.blur * BLUR_INFLATION_FACTOR; let inflation = box_shadow.spread + box_shadow.base.blur.0 * BLUR_INFLATION_FACTOR;
overflow.paint = overflow.paint.union(&border_box.translate(&offset) overflow.paint = overflow.paint.union(&border_box.translate(&offset)
.inflate(inflation, inflation)) .inflate(inflation, inflation))
} }
// Outlines cause us to draw outside our border box. // Outlines cause us to draw outside our border box.
let outline_width = self.style.get_outline().outline_width; let outline_width = self.style.get_outline().outline_width.0;
if outline_width != Au(0) { if outline_width != Au(0) {
overflow.paint = overflow.paint.union(&border_box.inflate(outline_width, overflow.paint = overflow.paint.union(&border_box.inflate(outline_width,
outline_width)) outline_width))

View file

@ -98,20 +98,20 @@ impl Flow for MulticolFlow {
let column_style = self.block_flow.fragment.style.get_column(); let column_style = self.block_flow.fragment.style.get_column();
let column_gap = match column_style.column_gap { let column_gap = match column_style.column_gap {
Either::First(len) => len, Either::First(len) => len.0,
Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size, Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size.0,
}; };
let mut column_count; let mut column_count;
if let Either::First(column_width) = column_style.column_width { if let Either::First(column_width) = column_style.column_width {
column_count = column_count =
max(1, (content_inline_size + column_gap).0 / (column_width + column_gap).0); max(1, (content_inline_size + column_gap).0 / (column_width.0 + column_gap).0);
if let Either::First(specified_column_count) = column_style.column_count { if let Either::First(specified_column_count) = column_style.column_count {
column_count = min(column_count, specified_column_count as i32); column_count = min(column_count, specified_column_count.0 as i32);
} }
} else { } else {
column_count = match column_style.column_count { column_count = match column_style.column_count {
Either::First(n) => n, Either::First(n) => n.0,
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -450,10 +450,10 @@ impl FragmentBorderBoxIterator for FragmentLocatingFragmentIterator {
border_left_width: left_width, border_left_width: left_width,
.. ..
} = *fragment.style.get_border(); } = *fragment.style.get_border();
self.client_rect.origin.y = top_width.to_px(); self.client_rect.origin.y = top_width.0.to_px();
self.client_rect.origin.x = left_width.to_px(); self.client_rect.origin.x = left_width.0.to_px();
self.client_rect.size.width = (border_box.size.width - left_width - right_width).to_px(); self.client_rect.size.width = (border_box.size.width - left_width.0 - right_width.0).to_px();
self.client_rect.size.height = (border_box.size.height - top_width - bottom_width).to_px(); self.client_rect.size.height = (border_box.size.height - top_width.0 - bottom_width.0).to_px();
} }
fn should_process(&mut self, fragment: &Fragment) -> bool { fn should_process(&mut self, fragment: &Fragment) -> bool {
@ -476,10 +476,10 @@ impl FragmentBorderBoxIterator for UnioningFragmentScrollAreaIterator {
border_left_width: left_border, border_left_width: left_border,
.. ..
} = *fragment.style.get_border(); } = *fragment.style.get_border();
let right_padding = (border_box.size.width - right_border - left_border).to_px(); let right_padding = (border_box.size.width - right_border.0 - left_border.0).to_px();
let bottom_padding = (border_box.size.height - bottom_border - top_border).to_px(); let bottom_padding = (border_box.size.height - bottom_border.0 - top_border.0).to_px();
let top_padding = top_border.to_px(); let top_padding = top_border.0.to_px();
let left_padding = left_border.to_px(); let left_padding = left_border.0.to_px();
match self.level { match self.level {
Some(start_level) if level <= start_level => { self.is_child = false; } Some(start_level) if level <= start_level => { self.is_child = false; }

View file

@ -27,7 +27,7 @@ use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW}; use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
use style::values::CSSFloat; use style::values::CSSFloat;
use style::values::computed::LengthOrPercentageOrAuto; use style::values::computed::{LengthOrPercentageOrAuto, NonNegativeAu};
use table_row::{self, CellIntrinsicInlineSize, CollapsedBorder, CollapsedBorderProvenance}; use table_row::{self, CellIntrinsicInlineSize, CollapsedBorder, CollapsedBorderProvenance};
use table_row::TableRowFlow; use table_row::TableRowFlow;
use table_wrapper::TableLayout; use table_wrapper::TableLayout;
@ -190,8 +190,8 @@ impl TableFlow {
border_collapse::T::separate => style.get_inheritedtable().border_spacing, border_collapse::T::separate => style.get_inheritedtable().border_spacing,
border_collapse::T::collapse => { border_collapse::T::collapse => {
border_spacing::T { border_spacing::T {
horizontal: Au(0), horizontal: NonNegativeAu::zero(),
vertical: Au(0), vertical: NonNegativeAu::zero(),
} }
} }
} }
@ -202,7 +202,7 @@ impl TableFlow {
if num_columns == 0 { if num_columns == 0 {
return Au(0); return Au(0);
} }
self.spacing().horizontal * (num_columns as i32 + 1) self.spacing().horizontal.0 * (num_columns as i32 + 1)
} }
} }
@ -469,7 +469,7 @@ impl Flow for TableFlow {
fn assign_block_size(&mut self, _: &LayoutContext) { fn assign_block_size(&mut self, _: &LayoutContext) {
debug!("assign_block_size: assigning block_size for table"); debug!("assign_block_size: assigning block_size for table");
let vertical_spacing = self.spacing().vertical; let vertical_spacing = self.spacing().vertical.0;
self.block_flow.assign_block_size_for_table_like_flow(vertical_spacing) self.block_flow.assign_block_size_for_table_like_flow(vertical_spacing)
} }

View file

@ -25,7 +25,7 @@ use style::computed_values::{border_collapse, border_spacing, border_top_style};
use style::logical_geometry::{LogicalSize, PhysicalSide, WritingMode}; use style::logical_geometry::{LogicalSize, PhysicalSide, WritingMode};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW}; use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
use style::values::computed::{Color, LengthOrPercentageOrAuto}; use style::values::computed::{Color, LengthOrPercentageOrAuto, NonNegativeAu};
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, VecExt}; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, VecExt};
use table_cell::{CollapsedBordersForCell, TableCellFlow}; use table_cell::{CollapsedBordersForCell, TableCellFlow};
@ -93,8 +93,8 @@ impl TableRowFlow {
column_computed_inline_sizes: Vec::new(), column_computed_inline_sizes: Vec::new(),
incoming_rowspan: Vec::new(), incoming_rowspan: Vec::new(),
spacing: border_spacing::T { spacing: border_spacing::T {
horizontal: Au(0), horizontal: NonNegativeAu::zero(),
vertical: Au(0), vertical: NonNegativeAu::zero(),
}, },
table_writing_mode: writing_mode, table_writing_mode: writing_mode,
preliminary_collapsed_borders: CollapsedBordersForRow::new(), preliminary_collapsed_borders: CollapsedBordersForRow::new(),
@ -395,7 +395,7 @@ impl Flow for TableRowFlow {
None => break, None => break,
}; };
column_computed_inline_size.size = column_computed_inline_size.size + column_computed_inline_size.size = column_computed_inline_size.size +
extra_column_computed_inline_size.size + self.spacing.horizontal; extra_column_computed_inline_size.size + self.spacing.horizontal.0;
col += 1; col += 1;
} }
@ -616,7 +616,7 @@ impl CollapsedBorder {
-> CollapsedBorder { -> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_top_style, style: css_style.get_border().border_top_style,
width: css_style.get_border().border_top_width, width: css_style.get_border().border_top_width.0,
color: css_style.get_border().border_top_color, color: css_style.get_border().border_top_color,
provenance: provenance, provenance: provenance,
} }
@ -628,7 +628,7 @@ impl CollapsedBorder {
-> CollapsedBorder { -> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_right_style, style: css_style.get_border().border_right_style,
width: css_style.get_border().border_right_width, width: css_style.get_border().border_right_width.0,
color: css_style.get_border().border_right_color, color: css_style.get_border().border_right_color,
provenance: provenance, provenance: provenance,
} }
@ -640,7 +640,7 @@ impl CollapsedBorder {
-> CollapsedBorder { -> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_bottom_style, style: css_style.get_border().border_bottom_style,
width: css_style.get_border().border_bottom_width, width: css_style.get_border().border_bottom_width.0,
color: css_style.get_border().border_bottom_color, color: css_style.get_border().border_bottom_color,
provenance: provenance, provenance: provenance,
} }
@ -652,7 +652,7 @@ impl CollapsedBorder {
-> CollapsedBorder { -> CollapsedBorder {
CollapsedBorder { CollapsedBorder {
style: css_style.get_border().border_left_style, style: css_style.get_border().border_left_style,
width: css_style.get_border().border_left_width, width: css_style.get_border().border_left_width.0,
color: css_style.get_border().border_left_color, color: css_style.get_border().border_left_color,
provenance: provenance, provenance: provenance,
} }
@ -818,7 +818,7 @@ fn set_inline_position_of_child_flow(
let column_inline_size = column_computed_inline_sizes[*column_index].size; let column_inline_size = column_computed_inline_sizes[*column_index].size;
let border_inline_size = match *border_collapse_info { let border_inline_size = match *border_collapse_info {
Some(_) => Au(0), // FIXME: Make collapsed borders account for colspan/rowspan. Some(_) => Au(0), // FIXME: Make collapsed borders account for colspan/rowspan.
None => border_spacing.horizontal, None => border_spacing.horizontal.0,
}; };
if reverse_column_order { if reverse_column_order {
*inline_end_margin_edge += column_inline_size + border_inline_size; *inline_end_margin_edge += column_inline_size + border_inline_size;
@ -873,9 +873,9 @@ fn set_inline_position_of_child_flow(
None => { None => {
// Take spacing into account. // Take spacing into account.
if reverse_column_order { if reverse_column_order {
*inline_end_margin_edge += border_spacing.horizontal; *inline_end_margin_edge += border_spacing.horizontal.0;
} else { } else {
*inline_start_margin_edge += border_spacing.horizontal; *inline_start_margin_edge += border_spacing.horizontal.0;
} }
} }
} }

View file

@ -21,6 +21,7 @@ use std::iter::{IntoIterator, Iterator, Peekable};
use style::computed_values::{border_collapse, border_spacing}; use style::computed_values::{border_collapse, border_spacing};
use style::logical_geometry::LogicalSize; use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::NonNegativeAu;
use table::{ColumnIntrinsicInlineSize, InternalTable, TableLikeFlow}; use table::{ColumnIntrinsicInlineSize, InternalTable, TableLikeFlow};
/// A table formatting context. /// A table formatting context.
@ -55,8 +56,8 @@ impl TableRowGroupFlow {
block_flow: BlockFlow::from_fragment(fragment), block_flow: BlockFlow::from_fragment(fragment),
column_intrinsic_inline_sizes: Vec::new(), column_intrinsic_inline_sizes: Vec::new(),
spacing: border_spacing::T { spacing: border_spacing::T {
horizontal: Au(0), horizontal: NonNegativeAu::zero(),
vertical: Au(0), vertical: NonNegativeAu::zero(),
}, },
collapsed_inline_direction_border_widths_for_table: Vec::new(), collapsed_inline_direction_border_widths_for_table: Vec::new(),
collapsed_block_direction_border_widths_for_table: Vec::new(), collapsed_block_direction_border_widths_for_table: Vec::new(),
@ -161,7 +162,7 @@ impl Flow for TableRowGroupFlow {
fn assign_block_size(&mut self, _: &LayoutContext) { fn assign_block_size(&mut self, _: &LayoutContext) {
debug!("assign_block_size: assigning block_size for table_rowgroup"); debug!("assign_block_size: assigning block_size for table_rowgroup");
self.block_flow.assign_block_size_for_table_like_flow(self.spacing.vertical) self.block_flow.assign_block_size_for_table_like_flow(self.spacing.vertical.0)
} }
fn compute_absolute_position(&mut self, layout_context: &LayoutContext) { fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {

View file

@ -446,11 +446,11 @@ pub fn font_metrics_for_style(font_context: &mut FontContext, font_style: ::Serv
/// Returns the line block-size needed by the given computed style and font size. /// Returns the line block-size needed by the given computed style and font size.
pub fn line_height_from_style(style: &ComputedValues, metrics: &FontMetrics) -> Au { pub fn line_height_from_style(style: &ComputedValues, metrics: &FontMetrics) -> Au {
let font_size = style.get_font().font_size; let font_size = style.get_font().font_size.0;
match style.get_inheritedtext().line_height { match style.get_inheritedtext().line_height {
LineHeight::Normal => metrics.line_gap, LineHeight::Normal => metrics.line_gap,
LineHeight::Number(l) => font_size.scale_by(l), LineHeight::Number(l) => font_size.scale_by(l.0),
LineHeight::Length(l) => l LineHeight::Length(l) => l.0
} }
} }

View file

@ -190,15 +190,15 @@ impl ToFilterOps for Vec<Filter> {
let mut result = Vec::with_capacity(self.len()); let mut result = Vec::with_capacity(self.len());
for filter in self.iter() { for filter in self.iter() {
match *filter { match *filter {
GenericFilter::Blur(radius) => result.push(webrender_api::FilterOp::Blur(radius.to_f32_px())), GenericFilter::Blur(radius) => result.push(webrender_api::FilterOp::Blur(radius.0.to_f32_px())),
GenericFilter::Brightness(amount) => result.push(webrender_api::FilterOp::Brightness(amount)), GenericFilter::Brightness(amount) => result.push(webrender_api::FilterOp::Brightness(amount.0)),
GenericFilter::Contrast(amount) => result.push(webrender_api::FilterOp::Contrast(amount)), GenericFilter::Contrast(amount) => result.push(webrender_api::FilterOp::Contrast(amount.0)),
GenericFilter::Grayscale(amount) => result.push(webrender_api::FilterOp::Grayscale(amount)), GenericFilter::Grayscale(amount) => result.push(webrender_api::FilterOp::Grayscale(amount.0)),
GenericFilter::HueRotate(angle) => result.push(webrender_api::FilterOp::HueRotate(angle.radians())), GenericFilter::HueRotate(angle) => result.push(webrender_api::FilterOp::HueRotate(angle.radians())),
GenericFilter::Invert(amount) => result.push(webrender_api::FilterOp::Invert(amount)), GenericFilter::Invert(amount) => result.push(webrender_api::FilterOp::Invert(amount.0)),
GenericFilter::Opacity(amount) => result.push(webrender_api::FilterOp::Opacity(amount.into())), GenericFilter::Opacity(amount) => result.push(webrender_api::FilterOp::Opacity(amount.0.into())),
GenericFilter::Saturate(amount) => result.push(webrender_api::FilterOp::Saturate(amount)), GenericFilter::Saturate(amount) => result.push(webrender_api::FilterOp::Saturate(amount.0)),
GenericFilter::Sepia(amount) => result.push(webrender_api::FilterOp::Sepia(amount)), GenericFilter::Sepia(amount) => result.push(webrender_api::FilterOp::Sepia(amount.0)),
GenericFilter::DropShadow(ref shadow) => match *shadow {}, GenericFilter::DropShadow(ref shadow) => match *shadow {},
} }
} }

View file

@ -548,7 +548,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
shared_lock, shared_lock,
PropertyDeclaration::BorderSpacing( PropertyDeclaration::BorderSpacing(
Box::new(border_spacing::SpecifiedValue { Box::new(border_spacing::SpecifiedValue {
horizontal: width_value, horizontal: width_value.into(),
vertical: None, vertical: None,
})))); }))));
} }

View file

@ -69,7 +69,8 @@ impl Device {
Device { Device {
pres_context: pres_context, pres_context: pres_context,
default_values: ComputedValues::default_values(unsafe { &*pres_context }), default_values: ComputedValues::default_values(unsafe { &*pres_context }),
root_font_size: AtomicIsize::new(font_size::get_initial_value().0 as isize), // FIXME(bz): Seems dubious? // FIXME(bz): Seems dubious?
root_font_size: AtomicIsize::new(font_size::get_initial_value().value() as isize),
used_root_font_size: AtomicBool::new(false), used_root_font_size: AtomicBool::new(false),
used_viewport_size: AtomicBool::new(false), used_viewport_size: AtomicBool::new(false),
} }

View file

@ -19,8 +19,9 @@ use values::{Auto, Either, ExtremumLength, None_, Normal};
use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto}; use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto};
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage}; use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
use values::computed::{MaxLength, MozLength, Percentage}; use values::computed::{MaxLength, MozLength, Percentage};
use values::computed::{NonNegativeAu, NonNegativeLengthOrPercentage, NonNegativeNumber};
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
use values::generics::CounterStyleOrNone; use values::generics::{CounterStyleOrNone, NonNegative};
use values::generics::basic_shape::ShapeRadius; use values::generics::basic_shape::ShapeRadius;
use values::generics::gecko::ScrollSnapPoint; use values::generics::gecko::ScrollSnapPoint;
use values::generics::grid::{TrackBreadth, TrackKeyword}; use values::generics::grid::{TrackBreadth, TrackKeyword};
@ -121,6 +122,16 @@ impl GeckoStyleCoordConvertible for LengthOrPercentage {
} }
} }
impl GeckoStyleCoordConvertible for NonNegativeLengthOrPercentage {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
self.0.to_gecko_style_coord(coord);
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
LengthOrPercentage::from_gecko_style_coord(coord).map(NonNegative::<LengthOrPercentage>)
}
}
impl GeckoStyleCoordConvertible for Au { impl GeckoStyleCoordConvertible for Au {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
coord.set_value(CoordDataValue::Coord(self.0)); coord.set_value(CoordDataValue::Coord(self.0));
@ -134,6 +145,26 @@ impl GeckoStyleCoordConvertible for Au {
} }
} }
impl GeckoStyleCoordConvertible for NonNegativeAu {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
self.0.to_gecko_style_coord(coord);
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
Au::from_gecko_style_coord(coord).map(NonNegative::<Au>)
}
}
impl GeckoStyleCoordConvertible for NonNegativeNumber {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
self.0.to_gecko_style_coord(coord);
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
Number::from_gecko_style_coord(coord).map(NonNegative::<Number>)
}
}
impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto { impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
let value = match *self { let value = match *self {

View file

@ -27,7 +27,7 @@ impl nsCSSShadowItem {
color: Color::rgba(convert_nscolor_to_rgba(self.mColor)), color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
horizontal: Au(self.mXOffset), horizontal: Au(self.mXOffset),
vertical: Au(self.mYOffset), vertical: Au(self.mYOffset),
blur: Au(self.mRadius), blur: Au(self.mRadius).into(),
}, },
spread: Au(self.mSpread), spread: Au(self.mSpread),
inset: self.mInset, inset: self.mInset,
@ -39,7 +39,7 @@ impl nsCSSShadowItem {
pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) { pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) {
self.mXOffset = shadow.horizontal.0; self.mXOffset = shadow.horizontal.0;
self.mYOffset = shadow.vertical.0; self.mYOffset = shadow.vertical.0;
self.mRadius = shadow.blur.0; self.mRadius = shadow.blur.value();
self.mSpread = 0; self.mSpread = 0;
self.mInset = false; self.mInset = false;
if shadow.color.is_currentcolor() { if shadow.color.is_currentcolor() {
@ -62,7 +62,7 @@ impl nsCSSShadowItem {
color: Color::rgba(convert_nscolor_to_rgba(self.mColor)), color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
horizontal: Au(self.mXOffset), horizontal: Au(self.mXOffset),
vertical: Au(self.mYOffset), vertical: Au(self.mYOffset),
blur: Au(self.mRadius), blur: Au(self.mRadius).into(),
} }
} }
} }

View file

@ -534,7 +534,7 @@ pub trait MatchMethods : TElement {
if old_styles.primary.as_ref().map_or(true, |s| s.get_font().clone_font_size() != new_font_size) { if old_styles.primary.as_ref().map_or(true, |s| s.get_font().clone_font_size() != new_font_size) {
debug_assert!(self.owner_doc_matches_for_testing(device)); debug_assert!(self.owner_doc_matches_for_testing(device));
device.set_root_font_size(new_font_size); device.set_root_font_size(new_font_size.0);
// If the root font-size changed since last time, and something // If the root font-size changed since last time, and something
// in the document did use rem units, ensure we recascade the // in the document did use rem units, ensure we recascade the
// entire tree. // entire tree.

View file

@ -157,7 +157,7 @@ class Longhand(object):
allowed_in_keyframe_block=True, cast_type='u8', allowed_in_keyframe_block=True, cast_type='u8',
has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False, has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False,
flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False, flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False,
gecko_pref_ident=None, vector=False): gecko_pref_ident=None, vector=False, need_animatable=False):
self.name = name self.name = name
if not spec: if not spec:
raise TypeError("Spec should be specified for %s" % name) raise TypeError("Spec should be specified for %s" % name)

View file

@ -62,7 +62,7 @@ use std::mem::{forget, uninitialized, transmute, zeroed};
use std::{cmp, ops, ptr}; use std::{cmp, ops, ptr};
use stylesheets::{MallocSizeOfWithRepeats, SizeOfState}; use stylesheets::{MallocSizeOfWithRepeats, SizeOfState};
use values::{self, Auto, CustomIdent, Either, KeyframesName}; use values::{self, Auto, CustomIdent, Either, KeyframesName};
use values::computed::ToComputedValue; use values::computed::{NonNegativeAu, ToComputedValue};
use values::computed::effects::{BoxShadow, Filter, SimpleShadow}; use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
use values::computed::length::Percentage; use values::computed::length::Percentage;
use computed_values::border_style; use computed_values::border_style;
@ -397,14 +397,14 @@ impl ${style_struct.gecko_struct_name} {
<%def name="impl_simple_setter(ident, gecko_ffi_name)"> <%def name="impl_simple_setter(ident, gecko_ffi_name)">
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
${set_gecko_property(gecko_ffi_name, "v")} ${set_gecko_property(gecko_ffi_name, "From::from(v)")}
} }
</%def> </%def>
<%def name="impl_simple_clone(ident, gecko_ffi_name)"> <%def name="impl_simple_clone(ident, gecko_ffi_name)">
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
self.gecko.${gecko_ffi_name} From::from(self.gecko.${gecko_ffi_name})
} }
</%def> </%def>
@ -616,7 +616,7 @@ def set_gecko_property(ffi_name, expr):
}; };
match length { match length {
Either::First(number) => Either::First(number) =>
self.gecko.${gecko_ffi_name}.set_value(CoordDataValue::Factor(number)), self.gecko.${gecko_ffi_name}.set_value(CoordDataValue::Factor(From::from(number))),
Either::Second(lop) => self.gecko.${gecko_ffi_name}.set(lop), Either::Second(lop) => self.gecko.${gecko_ffi_name}.set(lop),
} }
} }
@ -641,10 +641,10 @@ def set_gecko_property(ffi_name, expr):
return SVGLength::ContextValue; return SVGLength::ContextValue;
} }
let length = match self.gecko.${gecko_ffi_name}.as_value() { let length = match self.gecko.${gecko_ffi_name}.as_value() {
CoordDataValue::Factor(number) => Either::First(number), CoordDataValue::Factor(number) => Either::First(From::from(number)),
CoordDataValue::Coord(coord) => Either::Second(LengthOrPercentage::Length(Au(coord))), CoordDataValue::Coord(coord) => Either::Second(From::from(LengthOrPercentage::Length(Au(coord)))),
CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(Percentage(p))), CoordDataValue::Percent(p) => Either::Second(From::from(LengthOrPercentage::Percentage(Percentage(p)))),
CoordDataValue::Calc(calc) => Either::Second(LengthOrPercentage::Calc(calc.into())), CoordDataValue::Calc(calc) => Either::Second(From::from(LengthOrPercentage::Calc(calc.into()))),
_ => unreachable!("Unexpected coordinate {:?} in ${ident}", _ => unreachable!("Unexpected coordinate {:?} in ${ident}",
self.gecko.${gecko_ffi_name}.as_value()), self.gecko.${gecko_ffi_name}.as_value()),
}; };
@ -803,15 +803,16 @@ def set_gecko_property(ffi_name, expr):
} }
</%def> </%def>
<%def name="impl_app_units(ident, gecko_ffi_name, need_clone, inherit_from=None, round_to_pixels=False)"> <%def name="impl_non_negative_app_units(ident, gecko_ffi_name, need_clone, inherit_from=None,
round_to_pixels=False)">
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
let value = { let value = {
% if round_to_pixels: % if round_to_pixels:
let au_per_device_px = Au(self.gecko.mTwipsPerPixel); let au_per_device_px = Au(self.gecko.mTwipsPerPixel);
round_border_to_device_pixels(v, au_per_device_px).0 round_border_to_device_pixels(v.0, au_per_device_px).0
% else: % else:
v.0 v.value()
% endif % endif
}; };
@ -847,7 +848,7 @@ def set_gecko_property(ffi_name, expr):
%if need_clone: %if need_clone:
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
Au(self.gecko.${gecko_ffi_name}) Au(self.gecko.${gecko_ffi_name}).into()
} }
% endif % endif
</%def> </%def>
@ -1088,6 +1089,9 @@ impl Clone for ${style_struct.gecko_struct_name} {
predefined_types = { predefined_types = {
"length::LengthOrAuto": impl_style_coord, "length::LengthOrAuto": impl_style_coord,
"length::LengthOrNormal": impl_style_coord, "length::LengthOrNormal": impl_style_coord,
"length::NonNegativeLengthOrAuto": impl_style_coord,
"length::NonNegativeLengthOrNormal": impl_style_coord,
"GreaterThanOrEqualToOneNumber": impl_simple,
"Length": impl_absolute_length, "Length": impl_absolute_length,
"Position": impl_position, "Position": impl_position,
"LengthOrPercentage": impl_style_coord, "LengthOrPercentage": impl_style_coord,
@ -1097,6 +1101,8 @@ impl Clone for ${style_struct.gecko_struct_name} {
"LengthOrNormal": impl_style_coord, "LengthOrNormal": impl_style_coord,
"MaxLength": impl_style_coord, "MaxLength": impl_style_coord,
"MozLength": impl_style_coord, "MozLength": impl_style_coord,
"NonNegativeLengthOrPercentage": impl_style_coord,
"NonNegativeNumber": impl_simple,
"Number": impl_simple, "Number": impl_simple,
"Integer": impl_simple, "Integer": impl_simple,
"Opacity": impl_simple, "Opacity": impl_simple,
@ -1105,6 +1111,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
"SVGLength": impl_svg_length, "SVGLength": impl_svg_length,
"SVGOpacity": impl_svg_opacity, "SVGOpacity": impl_svg_opacity,
"SVGPaint": impl_svg_paint, "SVGPaint": impl_svg_paint,
"SVGWidth": impl_svg_length,
"UrlOrNone": impl_css_url, "UrlOrNone": impl_css_url,
} }
@ -1310,11 +1317,11 @@ fn static_assert() {
<% impl_color("border_%s_color" % side.ident, "(mBorderColor)[%s]" % side.index, need_clone=True) %> <% impl_color("border_%s_color" % side.ident, "(mBorderColor)[%s]" % side.index, need_clone=True) %>
<% impl_app_units("border_%s_width" % side.ident, <% impl_non_negative_app_units("border_%s_width" % side.ident,
"mComputedBorder.%s" % side.ident, "mComputedBorder.%s" % side.ident,
inherit_from="mBorder.%s" % side.ident, inherit_from="mBorder.%s" % side.ident,
need_clone=True, need_clone=True,
round_to_pixels=True) %> round_to_pixels=True) %>
pub fn border_${side.ident}_has_nonzero_width(&self) -> bool { pub fn border_${side.ident}_has_nonzero_width(&self) -> bool {
self.gecko.mComputedBorder.${side.ident} != 0 self.gecko.mComputedBorder.${side.ident} != 0
@ -2052,9 +2059,9 @@ fn static_assert() {
} }
} }
<% impl_app_units("outline_width", "mActualOutlineWidth", <% impl_non_negative_app_units("outline_width", "mActualOutlineWidth",
inherit_from="mOutlineWidth", inherit_from="mOutlineWidth",
need_clone=True, round_to_pixels=True) %> need_clone=True, round_to_pixels=True) %>
% for corner in CORNERS: % for corner in CORNERS:
<% impl_corner_style_coord("_moz_outline_radius_%s" % corner.ident.replace("_", ""), <% impl_corner_style_coord("_moz_outline_radius_%s" % corner.ident.replace("_", ""),
@ -2263,15 +2270,15 @@ fn static_assert() {
} }
pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) { pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) {
self.gecko.mSize = v.0; self.gecko.mSize = v.value();
self.gecko.mScriptUnconstrainedSize = v.0; self.gecko.mScriptUnconstrainedSize = v.value();
} }
/// Set font size, taking into account scriptminsize and scriptlevel /// Set font size, taking into account scriptminsize and scriptlevel
/// Returns Some(size) if we have to recompute the script unconstrained size /// Returns Some(size) if we have to recompute the script unconstrained size
pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T,
parent: &Self, parent: &Self,
device: &Device) -> Option<Au> { device: &Device) -> Option<NonNegativeAu> {
let (adjusted_size, adjusted_unconstrained_size) = let (adjusted_size, adjusted_unconstrained_size) =
self.calculate_script_level_size(parent, device); self.calculate_script_level_size(parent, device);
// In this case, we have been unaffected by scriptminsize, ignore it // In this case, we have been unaffected by scriptminsize, ignore it
@ -2281,9 +2288,9 @@ fn static_assert() {
self.fixup_font_min_size(device); self.fixup_font_min_size(device);
None None
} else { } else {
self.gecko.mSize = v.0; self.gecko.mSize = v.value();
self.fixup_font_min_size(device); self.fixup_font_min_size(device);
Some(Au(parent.gecko.mScriptUnconstrainedSize)) Some(Au(parent.gecko.mScriptUnconstrainedSize).into())
} }
} }
@ -2291,8 +2298,8 @@ fn static_assert() {
unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, device.pres_context()) } unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, device.pres_context()) }
} }
pub fn apply_unconstrained_font_size(&mut self, v: Au) { pub fn apply_unconstrained_font_size(&mut self, v: NonNegativeAu) {
self.gecko.mScriptUnconstrainedSize = v.0; self.gecko.mScriptUnconstrainedSize = v.value();
} }
/// Calculates the constrained and unconstrained font sizes to be inherited /// Calculates the constrained and unconstrained font sizes to be inherited
@ -2402,7 +2409,7 @@ fn static_assert() {
/// ///
/// Returns true if the inherited keyword size was actually used /// Returns true if the inherited keyword size was actually used
pub fn inherit_font_size_from(&mut self, parent: &Self, pub fn inherit_font_size_from(&mut self, parent: &Self,
kw_inherited_size: Option<Au>, kw_inherited_size: Option<NonNegativeAu>,
device: &Device) -> bool { device: &Device) -> bool {
let (adjusted_size, adjusted_unconstrained_size) let (adjusted_size, adjusted_unconstrained_size)
= self.calculate_script_level_size(parent, device); = self.calculate_script_level_size(parent, device);
@ -2428,9 +2435,9 @@ fn static_assert() {
false false
} else if let Some(size) = kw_inherited_size { } else if let Some(size) = kw_inherited_size {
// Parent element was a keyword-derived size. // Parent element was a keyword-derived size.
self.gecko.mSize = size.0; self.gecko.mSize = size.value();
// MathML constraints didn't apply here, so we can ignore this. // MathML constraints didn't apply here, so we can ignore this.
self.gecko.mScriptUnconstrainedSize = size.0; self.gecko.mScriptUnconstrainedSize = size.value();
self.fixup_font_min_size(device); self.fixup_font_min_size(device);
true true
} else { } else {
@ -2444,7 +2451,7 @@ fn static_assert() {
} }
pub fn clone_font_size(&self) -> longhands::font_size::computed_value::T { pub fn clone_font_size(&self) -> longhands::font_size::computed_value::T {
Au(self.gecko.mSize) Au(self.gecko.mSize).into()
} }
pub fn set_font_weight(&mut self, v: longhands::font_weight::computed_value::T) { pub fn set_font_weight(&mut self, v: longhands::font_weight::computed_value::T) {
@ -4420,11 +4427,11 @@ fn static_assert() {
match servo { match servo {
% for func in FILTER_FUNCTIONS: % for func in FILTER_FUNCTIONS:
${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()}, ${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()},
CoordDataValue::Factor(factor), CoordDataValue::Factor(factor.0),
gecko_filter), gecko_filter),
% endfor % endfor
Blur(length) => fill_filter(NS_STYLE_FILTER_BLUR, Blur(length) => fill_filter(NS_STYLE_FILTER_BLUR,
CoordDataValue::Coord(length.0), CoordDataValue::Coord(length.value()),
gecko_filter), gecko_filter),
HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE, HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE,
@ -4492,7 +4499,7 @@ fn static_assert() {
}, },
% endfor % endfor
NS_STYLE_FILTER_BLUR => { NS_STYLE_FILTER_BLUR => {
filters.push(Filter::Blur(Au::from_gecko_style_coord( filters.push(Filter::Blur(NonNegativeAu::from_gecko_style_coord(
&filter.mFilterParameter).unwrap())); &filter.mFilterParameter).unwrap()));
}, },
NS_STYLE_FILTER_HUE_ROTATE => { NS_STYLE_FILTER_HUE_ROTATE => {
@ -4584,8 +4591,8 @@ fn static_assert() {
skip_longhands="border-spacing"> skip_longhands="border-spacing">
pub fn set_border_spacing(&mut self, v: longhands::border_spacing::computed_value::T) { pub fn set_border_spacing(&mut self, v: longhands::border_spacing::computed_value::T) {
self.gecko.mBorderSpacingCol = v.horizontal.0; self.gecko.mBorderSpacingCol = v.horizontal.value();
self.gecko.mBorderSpacingRow = v.vertical.0; self.gecko.mBorderSpacingRow = v.vertical.value();
} }
pub fn copy_border_spacing_from(&mut self, other: &Self) { pub fn copy_border_spacing_from(&mut self, other: &Self) {
@ -4599,8 +4606,8 @@ fn static_assert() {
pub fn clone_border_spacing(&self) -> longhands::border_spacing::computed_value::T { pub fn clone_border_spacing(&self) -> longhands::border_spacing::computed_value::T {
longhands::border_spacing::computed_value::T { longhands::border_spacing::computed_value::T {
horizontal: Au(self.gecko.mBorderSpacingCol), horizontal: Au(self.gecko.mBorderSpacingCol).into(),
vertical: Au(self.gecko.mBorderSpacingRow) vertical: Au(self.gecko.mBorderSpacingRow).into()
} }
} }
</%self:impl_trait> </%self:impl_trait>
@ -4645,8 +4652,8 @@ fn static_assert() {
// FIXME: Align binary representations and ditch |match| for cast + static_asserts // FIXME: Align binary representations and ditch |match| for cast + static_asserts
let en = match v { let en = match v {
LineHeight::Normal => CoordDataValue::Normal, LineHeight::Normal => CoordDataValue::Normal,
LineHeight::Length(val) => CoordDataValue::Coord(val.0), LineHeight::Length(val) => CoordDataValue::Coord(val.value()),
LineHeight::Number(val) => CoordDataValue::Factor(val), LineHeight::Number(val) => CoordDataValue::Factor(val.0),
LineHeight::MozBlockHeight => LineHeight::MozBlockHeight =>
CoordDataValue::Enumerated(structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT), CoordDataValue::Enumerated(structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT),
}; };
@ -4657,8 +4664,8 @@ fn static_assert() {
use values::generics::text::LineHeight; use values::generics::text::LineHeight;
return match self.gecko.mLineHeight.as_value() { return match self.gecko.mLineHeight.as_value() {
CoordDataValue::Normal => LineHeight::Normal, CoordDataValue::Normal => LineHeight::Normal,
CoordDataValue::Coord(coord) => LineHeight::Length(Au(coord)), CoordDataValue::Coord(coord) => LineHeight::Length(Au(coord).into()),
CoordDataValue::Factor(n) => LineHeight::Number(n), CoordDataValue::Factor(n) => LineHeight::Number(n.into()),
CoordDataValue::Enumerated(val) if val == structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT => CoordDataValue::Enumerated(val) if val == structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT =>
LineHeight::MozBlockHeight, LineHeight::MozBlockHeight,
_ => panic!("this should not happen"), _ => panic!("this should not happen"),
@ -4792,18 +4799,20 @@ fn static_assert() {
}) })
} }
<%call expr="impl_app_units('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth', need_clone=True)"></%call> <%call expr="impl_non_negative_app_units('_webkit_text_stroke_width',
'mWebkitTextStrokeWidth',
need_clone=True)"></%call>
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set__moz_tab_size(&mut self, v: longhands::_moz_tab_size::computed_value::T) { pub fn set__moz_tab_size(&mut self, v: longhands::_moz_tab_size::computed_value::T) {
use values::Either; use values::Either;
match v { match v {
Either::Second(number) => { Either::Second(non_negative_number) => {
self.gecko.mTabSize.set_value(CoordDataValue::Factor(number)); self.gecko.mTabSize.set_value(CoordDataValue::Factor(non_negative_number.0));
} }
Either::First(au) => { Either::First(non_negative_au) => {
self.gecko.mTabSize.set(au); self.gecko.mTabSize.set(non_negative_au.0);
} }
} }
} }
@ -4813,8 +4822,8 @@ fn static_assert() {
use values::Either; use values::Either;
match self.gecko.mTabSize.as_value() { match self.gecko.mTabSize.as_value() {
CoordDataValue::Coord(coord) => Either::First(Au(coord)), CoordDataValue::Coord(coord) => Either::First(Au(coord).into()),
CoordDataValue::Factor(number) => Either::Second(number), CoordDataValue::Factor(number) => Either::Second(From::from(number)),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -5151,7 +5160,7 @@ clip-path
} }
for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) { for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) {
match servo { match servo {
Either::First(number) => gecko.set_value(CoordDataValue::Factor(number)), Either::First(number) => gecko.set_value(CoordDataValue::Factor(number.into())),
Either::Second(lop) => gecko.set(lop), Either::Second(lop) => gecko.set(lop),
} }
} }
@ -5191,13 +5200,13 @@ clip-path
let mut vec = vec![]; let mut vec = vec![];
for gecko in self.gecko.mStrokeDasharray.iter() { for gecko in self.gecko.mStrokeDasharray.iter() {
match gecko.as_value() { match gecko.as_value() {
CoordDataValue::Factor(number) => vec.push(Either::First(number)), CoordDataValue::Factor(number) => vec.push(Either::First(number.into())),
CoordDataValue::Coord(coord) => CoordDataValue::Coord(coord) =>
vec.push(Either::Second(LengthOrPercentage::Length(Au(coord)))), vec.push(Either::Second(LengthOrPercentage::Length(Au(coord)).into())),
CoordDataValue::Percent(p) => CoordDataValue::Percent(p) =>
vec.push(Either::Second(LengthOrPercentage::Percentage(Percentage(p)))), vec.push(Either::Second(LengthOrPercentage::Percentage(Percentage(p)).into())),
CoordDataValue::Calc(calc) => CoordDataValue::Calc(calc) =>
vec.push(Either::Second(LengthOrPercentage::Calc(calc.into()))), vec.push(Either::Second(LengthOrPercentage::Calc(calc.into()).into())),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -5423,8 +5432,8 @@ clip-path
use gecko_bindings::structs::{NS_STYLE_COLUMN_COUNT_AUTO, nsStyleColumn_kMaxColumnCount}; use gecko_bindings::structs::{NS_STYLE_COLUMN_COUNT_AUTO, nsStyleColumn_kMaxColumnCount};
self.gecko.mColumnCount = match v { self.gecko.mColumnCount = match v {
Either::First(number) => unsafe { Either::First(integer) => unsafe {
cmp::min(number as u32, nsStyleColumn_kMaxColumnCount) cmp::min(integer.0 as u32, nsStyleColumn_kMaxColumnCount)
}, },
Either::Second(Auto) => NS_STYLE_COLUMN_COUNT_AUTO Either::Second(Auto) => NS_STYLE_COLUMN_COUNT_AUTO
}; };
@ -5437,14 +5446,14 @@ clip-path
if self.gecko.mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO { if self.gecko.mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO {
debug_assert!((self.gecko.mColumnCount as i32) >= 0 && debug_assert!((self.gecko.mColumnCount as i32) >= 0 &&
(self.gecko.mColumnCount as i32) < i32::max_value()); (self.gecko.mColumnCount as i32) < i32::max_value());
Either::First(self.gecko.mColumnCount as i32) Either::First((self.gecko.mColumnCount as i32).into())
} else { } else {
Either::Second(Auto) Either::Second(Auto)
} }
} }
<% impl_app_units("column_rule_width", "mColumnRuleWidth", need_clone=True, <% impl_non_negative_app_units("column_rule_width", "mColumnRuleWidth", need_clone=True,
round_to_pixels=True) %> round_to_pixels=True) %>
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="Counters" <%self:impl_trait style_struct_name="Counters"

View file

@ -76,8 +76,10 @@
We assume that the default/initial value is an empty vector for these. We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these. `initial_value` need not be defined for these.
</%doc> </%doc>
<%def name="vector_longhand(name, animation_value_type=None, allow_empty=False, separator='Comma', **kwargs)"> <%def name="vector_longhand(name, animation_value_type=None, allow_empty=False, separator='Comma',
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True, **kwargs)"> need_animatable=False, **kwargs)">
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
need_animatable=need_animatable, **kwargs)">
#[allow(unused_imports)] #[allow(unused_imports)]
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt; use std::fmt;
@ -127,7 +129,7 @@
% endif % endif
); );
% if animation_value_type == "ComputedValue": % if need_animatable or animation_value_type == "ComputedValue":
use properties::animated_properties::Animatable; use properties::animated_properties::Animatable;
use values::animated::ToAnimatedZero; use values::animated::ToAnimatedZero;

View file

@ -16,8 +16,11 @@ use euclid::{Point2D, Size2D};
#[cfg(feature = "gecko")] use gecko_string_cache::Atom; #[cfg(feature = "gecko")] use gecko_string_cache::Atom;
use properties::{CSSWideKeyword, PropertyDeclaration}; use properties::{CSSWideKeyword, PropertyDeclaration};
use properties::longhands; use properties::longhands;
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
use properties::longhands::border_spacing::computed_value::T as BorderSpacing;
use properties::longhands::font_weight::computed_value::T as FontWeight; use properties::longhands::font_weight::computed_value::T as FontWeight;
use properties::longhands::font_stretch::computed_value::T as FontStretch; use properties::longhands::font_stretch::computed_value::T as FontStretch;
use properties::longhands::line_height::computed_value::T as LineHeight;
use properties::longhands::transform::computed_value::ComputedMatrix; use properties::longhands::transform::computed_value::ComputedMatrix;
use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation; use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
use properties::longhands::transform::computed_value::T as TransformList; use properties::longhands::transform::computed_value::T as TransformList;
@ -43,6 +46,10 @@ use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone
use values::computed::{BorderCornerRadius, ClipRect}; use values::computed::{BorderCornerRadius, ClipRect};
use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified}; use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue}; use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue};
use values::computed::{NonNegativeAu, NonNegativeNumber, PositiveIntegerOrAuto};
use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
use values::computed::length::NonNegativeLengthOrPercentage;
use values::generics::{GreaterThanOrEqualToOne, NonNegative};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::effects::Filter; use values::generics::effects::Filter;
use values::generics::position as generic_position; use values::generics::position as generic_position;
@ -777,6 +784,7 @@ impl ToAnimatedZero for AnimationValue {
impl RepeatableListAnimatable for LengthOrPercentage {} impl RepeatableListAnimatable for LengthOrPercentage {}
impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {} impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
impl RepeatableListAnimatable for Either<NonNegativeNumber, NonNegativeLengthOrPercentage> {}
macro_rules! repeated_vec_impl { macro_rules! repeated_vec_impl {
($($ty:ty),*) => { ($($ty:ty),*) => {
@ -3191,7 +3199,7 @@ fn add_weighted_filter_function_impl(from: &AnimatedFilter,
&to_value, &to_value,
self_portion, self_portion,
other_portion, other_portion,
&0.0, &NonNegative::<CSSFloat>(0.0),
)?)) )?))
}, },
% endfor % endfor
@ -3202,7 +3210,7 @@ fn add_weighted_filter_function_impl(from: &AnimatedFilter,
&to_value, &to_value,
self_portion, self_portion,
other_portion, other_portion,
&1.0, &NonNegative::<CSSFloat>(1.0),
)?)) )?))
}, },
% endfor % endfor
@ -3373,3 +3381,49 @@ sorted_shorthands = [(p, position) for position, p in enumerate(sorted_shorthand
% endfor % endfor
} }
} }
impl<T> Animatable for NonNegative<T>
where T: Animatable + Clone
{
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
self.0.add_weighted(&other.0, self_portion, other_portion).map(NonNegative::<T>)
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.0.compute_distance(&other.0)
}
}
impl<T> ToAnimatedZero for NonNegative<T>
where T: ToAnimatedZero
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
self.0.to_animated_zero().map(NonNegative::<T>)
}
}
impl<T> Animatable for GreaterThanOrEqualToOne<T>
where T: Animatable + Clone
{
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
self.0.add_weighted(&other.0, self_portion, other_portion).map(GreaterThanOrEqualToOne::<T>)
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.0.compute_distance(&other.0)
}
}
impl<T> ToAnimatedZero for GreaterThanOrEqualToOne<T>
where T: ToAnimatedZero
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
self.0.to_animated_zero().map(GreaterThanOrEqualToOne::<T>)
}
}

View file

@ -167,7 +167,8 @@ ${helpers.predefined_type("background-size", "BackgroundSize",
initial_specified_value="specified::LengthOrPercentageOrAuto::Auto.into()", initial_specified_value="specified::LengthOrPercentageOrAuto::Auto.into()",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-size", spec="https://drafts.csswg.org/css-backgrounds/#the-background-size",
vector=True, vector=True,
animation_value_type="ComputedValue", animation_value_type="BackgroundSizeList",
need_animatable=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
extra_prefixes="webkit")} extra_prefixes="webkit")}

View file

@ -40,11 +40,11 @@
${helpers.predefined_type("border-%s-width" % side_name, ${helpers.predefined_type("border-%s-width" % side_name,
"BorderSideWidth", "BorderSideWidth",
"Au::from_px(3)", "::values::computed::NonNegativeAu::from_px(3)",
computed_type="::app_units::Au", computed_type="::values::computed::NonNegativeAu",
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"), alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
spec=maybe_logical_spec(side, "width"), spec=maybe_logical_spec(side, "width"),
animation_value_type="ComputedValue", animation_value_type="NonNegativeAu",
logical=is_logical, logical=is_logical,
flags="APPLIES_TO_FIRST_LETTER", flags="APPLIES_TO_FIRST_LETTER",
allow_quirks=not is_logical)} allow_quirks=not is_logical)}
@ -62,7 +62,7 @@ ${helpers.gecko_keyword_conversion(Keyword('border-style',
spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner, spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner,
boxed=True, boxed=True,
flags="APPLIES_TO_FIRST_LETTER", flags="APPLIES_TO_FIRST_LETTER",
animation_value_type="ComputedValue")} animation_value_type="BorderCornerRadius")}
% endfor % endfor
/// -moz-border-*-colors: color, string, enum, none, inherit/initial /// -moz-border-*-colors: color, string, enum, none, inherit/initial

View file

@ -7,33 +7,30 @@
<% data.new_style_struct("Column", inherited=False) %> <% data.new_style_struct("Column", inherited=False) %>
${helpers.predefined_type("column-width", ${helpers.predefined_type("column-width",
"length::LengthOrAuto", "length::NonNegativeLengthOrAuto",
"Either::Second(Auto)", "Either::Second(Auto)",
initial_specified_value="Either::Second(Auto)", initial_specified_value="Either::Second(Auto)",
parse_method="parse_non_negative_length",
extra_prefixes="moz", extra_prefixes="moz",
animation_value_type="ComputedValue", animation_value_type="NonNegativeLengthOrAuto",
experimental=True, experimental=True,
spec="https://drafts.csswg.org/css-multicol/#propdef-column-width")} spec="https://drafts.csswg.org/css-multicol/#propdef-column-width")}
${helpers.predefined_type("column-count", ${helpers.predefined_type("column-count",
"IntegerOrAuto", "PositiveIntegerOrAuto",
"Either::Second(Auto)", "Either::Second(Auto)",
parse_method="parse_positive",
initial_specified_value="Either::Second(Auto)", initial_specified_value="Either::Second(Auto)",
experimental="True", experimental="True",
animation_value_type="ComputedValue", animation_value_type="PositiveIntegerOrAuto",
extra_prefixes="moz", extra_prefixes="moz",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-count")} spec="https://drafts.csswg.org/css-multicol/#propdef-column-count")}
${helpers.predefined_type("column-gap", ${helpers.predefined_type("column-gap",
"length::LengthOrNormal", "length::NonNegativeLengthOrNormal",
"Either::Second(Normal)", "Either::Second(Normal)",
parse_method='parse_non_negative_length',
extra_prefixes="moz", extra_prefixes="moz",
experimental=True, experimental=True,
animation_value_type="ComputedValue", animation_value_type="NonNegativeLengthOrNormal",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap")} spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap")}
${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz", ${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
@ -42,12 +39,12 @@ ${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
${helpers.predefined_type("column-rule-width", ${helpers.predefined_type("column-rule-width",
"BorderSideWidth", "BorderSideWidth",
"Au::from_px(3)", "::values::computed::NonNegativeAu::from_px(3)",
initial_specified_value="specified::BorderSideWidth::Medium", initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::app_units::Au", computed_type="::values::computed::NonNegativeAu",
products="gecko", products="gecko",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width", spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width",
animation_value_type="ComputedValue", animation_value_type="NonNegativeAu",
extra_prefixes="moz")} extra_prefixes="moz")}
// https://drafts.csswg.org/css-multicol-1/#crc // https://drafts.csswg.org/css-multicol-1/#crc

View file

@ -591,7 +591,7 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
</%helpers:longhand> </%helpers:longhand>
<%helpers:longhand name="font-size" need_clone="True" animation_value_type="ComputedValue" <%helpers:longhand name="font-size" need_clone="True" animation_value_type="NonNegativeAu"
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER" flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER"
allow_quirks="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size"> allow_quirks="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size">
use app_units::Au; use app_units::Au;
@ -599,6 +599,7 @@ ${helpers.single_keyword_system("font-variant-caps",
use std::fmt; use std::fmt;
use style_traits::{HasViewportPercentage, ToCss}; use style_traits::{HasViewportPercentage, ToCss};
use values::FONT_MEDIUM_PX; use values::FONT_MEDIUM_PX;
use values::computed::NonNegativeAu;
use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage, NoCalcLength}; use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage, NoCalcLength};
use values::specified::length::FontBaseSize; use values::specified::length::FontBaseSize;
@ -646,8 +647,8 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
pub mod computed_value { pub mod computed_value {
use app_units::Au; use values::computed::NonNegativeAu;
pub type T = Au; pub type T = NonNegativeAu;
} }
/// CSS font keywords /// CSS font keywords
@ -722,7 +723,7 @@ ${helpers.single_keyword_system("font-variant-caps",
% if product == "servo": % if product == "servo":
impl ToComputedValue for KeywordSize { impl ToComputedValue for KeywordSize {
type ComputedValue = Au; type ComputedValue = NonNegativeAu;
#[inline] #[inline]
fn to_computed_value(&self, _: &Context) -> computed_value::T { fn to_computed_value(&self, _: &Context) -> computed_value::T {
// https://drafts.csswg.org/css-fonts-3/#font-size-prop // https://drafts.csswg.org/css-fonts-3/#font-size-prop
@ -736,7 +737,7 @@ ${helpers.single_keyword_system("font-variant-caps",
XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2, XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2,
XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2, XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2,
XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3, XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3,
} }.into()
} }
#[inline] #[inline]
@ -746,7 +747,7 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
% else: % else:
impl ToComputedValue for KeywordSize { impl ToComputedValue for KeywordSize {
type ComputedValue = Au; type ComputedValue = NonNegativeAu;
#[inline] #[inline]
fn to_computed_value(&self, cx: &Context) -> computed_value::T { fn to_computed_value(&self, cx: &Context) -> computed_value::T {
use gecko_bindings::structs::nsIAtom; use gecko_bindings::structs::nsIAtom;
@ -782,9 +783,9 @@ ${helpers.single_keyword_system("font-variant-caps",
let base_size_px = au_to_int_px(base_size as f32); let base_size_px = au_to_int_px(base_size as f32);
let html_size = self.html_size() as usize; let html_size = self.html_size() as usize;
if base_size_px >= 9 && base_size_px <= 16 { if base_size_px >= 9 && base_size_px <= 16 {
Au::from_px(FONT_SIZE_MAPPING[(base_size_px - 9) as usize][html_size]) NonNegativeAu::from_px(FONT_SIZE_MAPPING[(base_size_px - 9) as usize][html_size])
} else { } else {
Au(FONT_SIZE_FACTORS[html_size] * base_size / 100) Au(FONT_SIZE_FACTORS[html_size] * base_size / 100).into()
} }
} }
@ -843,37 +844,38 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
/// Compute it against a given base font size /// Compute it against a given base font size
pub fn to_computed_value_against(&self, context: &Context, base_size: FontBaseSize) -> Au { pub fn to_computed_value_against(&self, context: &Context, base_size: FontBaseSize)
-> NonNegativeAu {
use values::specified::length::FontRelativeLength; use values::specified::length::FontRelativeLength;
match *self { match *self {
SpecifiedValue::Length(LengthOrPercentage::Length( SpecifiedValue::Length(LengthOrPercentage::Length(
NoCalcLength::FontRelative(value))) => { NoCalcLength::FontRelative(value))) => {
value.to_computed_value(context, base_size) value.to_computed_value(context, base_size).into()
} }
SpecifiedValue::Length(LengthOrPercentage::Length( SpecifiedValue::Length(LengthOrPercentage::Length(
NoCalcLength::ServoCharacterWidth(value))) => { NoCalcLength::ServoCharacterWidth(value))) => {
value.to_computed_value(base_size.resolve(context)) value.to_computed_value(base_size.resolve(context)).into()
} }
SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => { SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => {
context.maybe_zoom_text(l.to_computed_value(context)) context.maybe_zoom_text(l.to_computed_value(context).into())
} }
SpecifiedValue::Length(LengthOrPercentage::Percentage(pc)) => { SpecifiedValue::Length(LengthOrPercentage::Percentage(pc)) => {
base_size.resolve(context).scale_by(pc.0) base_size.resolve(context).scale_by(pc.0).into()
} }
SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => { SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
let calc = calc.to_computed_value_zoomed(context); let calc = calc.to_computed_value_zoomed(context);
calc.to_used_value(Some(base_size.resolve(context))).unwrap() calc.to_used_value(Some(base_size.resolve(context))).unwrap().into()
} }
SpecifiedValue::Keyword(ref key, fraction) => { SpecifiedValue::Keyword(ref key, fraction) => {
context.maybe_zoom_text(key.to_computed_value(context).scale_by(fraction)) context.maybe_zoom_text(key.to_computed_value(context).scale_by(fraction))
} }
SpecifiedValue::Smaller => { SpecifiedValue::Smaller => {
FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO) FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO)
.to_computed_value(context, base_size) .to_computed_value(context, base_size).into()
} }
SpecifiedValue::Larger => { SpecifiedValue::Larger => {
FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO) FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO)
.to_computed_value(context, base_size) .to_computed_value(context, base_size).into()
} }
SpecifiedValue::System(_) => { SpecifiedValue::System(_) => {
@ -888,7 +890,7 @@ ${helpers.single_keyword_system("font-variant-caps",
#[inline] #[inline]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
Au::from_px(FONT_MEDIUM_PX) NonNegativeAu::from_px(FONT_MEDIUM_PX)
} }
#[inline] #[inline]
@ -908,7 +910,7 @@ ${helpers.single_keyword_system("font-variant-caps",
#[inline] #[inline]
fn from_computed_value(computed: &computed_value::T) -> Self { fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue::Length(LengthOrPercentage::Length( SpecifiedValue::Length(LengthOrPercentage::Length(
ToComputedValue::from_computed_value(computed) ToComputedValue::from_computed_value(&computed.0)
)) ))
} }
} }
@ -955,7 +957,7 @@ ${helpers.single_keyword_system("font-variant-caps",
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn cascade_specified_font_size(context: &mut Context, pub fn cascade_specified_font_size(context: &mut Context,
specified_value: &SpecifiedValue, specified_value: &SpecifiedValue,
mut computed: Au) { mut computed: NonNegativeAu) {
if let SpecifiedValue::Keyword(kw, fraction) = *specified_value { if let SpecifiedValue::Keyword(kw, fraction) = *specified_value {
context.builder.font_size_keyword = Some((kw, fraction)); context.builder.font_size_keyword = Some((kw, fraction));
} else if let Some(ratio) = specified_value.as_font_ratio() { } else if let Some(ratio) = specified_value.as_font_ratio() {
@ -1001,7 +1003,7 @@ ${helpers.single_keyword_system("font-variant-caps",
if let Some(parent) = parent_unconstrained { if let Some(parent) = parent_unconstrained {
let new_unconstrained = let new_unconstrained =
specified_value specified_value
.to_computed_value_against(context, FontBaseSize::Custom(parent)); .to_computed_value_against(context, FontBaseSize::Custom(parent.0));
context.builder context.builder
.mutate_font() .mutate_font()
.apply_unconstrained_font_size(new_unconstrained); .apply_unconstrained_font_size(new_unconstrained);
@ -1053,7 +1055,8 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
</%helpers:longhand> </%helpers:longhand>
<%helpers:longhand products="gecko" name="font-size-adjust" animation_value_type="ComputedValue" <%helpers:longhand products="gecko" name="font-size-adjust"
animation_value_type="longhands::font_size_adjust::computed_value::T"
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER" flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust"> spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust">
use properties::longhands::system_font::SystemFont; use properties::longhands::system_font::SystemFont;
@ -1107,7 +1110,7 @@ ${helpers.single_keyword_system("font-variant-caps",
pub mod computed_value { pub mod computed_value {
use properties::animated_properties::Animatable; use properties::animated_properties::Animatable;
use values::CSSFloat; use values::CSSFloat;
use values::animated::ToAnimatedZero; use values::animated::{ToAnimatedValue, ToAnimatedZero};
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Copy, Clone, Debug, PartialEq, ToCss)] #[derive(Copy, Clone, Debug, PartialEq, ToCss)]
@ -1150,6 +1153,23 @@ ${helpers.single_keyword_system("font-variant-caps",
#[inline] #[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
} }
impl ToAnimatedValue for T {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
match animated {
T::Number(number) => T::Number(number.max(0.)),
_ => animated
}
}
}
} }
#[inline] #[inline]
@ -2539,7 +2559,7 @@ ${helpers.single_keyword("-moz-math-variant",
let weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight); let weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight);
let ret = ComputedSystemFont { let ret = ComputedSystemFont {
font_family: longhands::font_family::computed_value::T(family), font_family: longhands::font_family::computed_value::T(family),
font_size: Au(system.size), font_size: Au(system.size).into(),
font_weight: weight, font_weight: weight,
font_size_adjust: longhands::font_size_adjust::computed_value font_size_adjust: longhands::font_size_adjust::computed_value
::T::from_gecko_adjust(system.sizeAdjust), ::T::from_gecko_adjust(system.sizeAdjust),

View file

@ -64,12 +64,11 @@ ${helpers.predefined_type(
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")} spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}
${helpers.predefined_type( ${helpers.predefined_type(
"stroke-width", "SVGLength", "stroke-width", "SVGWidth",
"Au::from_px(1).into()", "::values::computed::NonNegativeAu::from_px(1).into()",
"parse_non_negative",
products="gecko", products="gecko",
boxed="True", boxed="True",
animation_value_type="ComputedValue", animation_value_type="::values::computed::SVGWidth",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")} spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}
${helpers.single_keyword("stroke-linecap", "butt round square", ${helpers.single_keyword("stroke-linecap", "butt round square",
@ -80,9 +79,10 @@ ${helpers.single_keyword("stroke-linejoin", "miter round bevel",
products="gecko", animation_value_type="discrete", products="gecko", animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")} spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")}
${helpers.predefined_type("stroke-miterlimit", "Number", "4.0", ${helpers.predefined_type("stroke-miterlimit", "GreaterThanOrEqualToOneNumber",
"parse_at_least_one", products="gecko", "From::from(4.0)",
animation_value_type="ComputedValue", products="gecko",
animation_value_type="::values::computed::GreaterThanOrEqualToOneNumber",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")} spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}
${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()", ${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()",
@ -94,7 +94,7 @@ ${helpers.predefined_type(
"SVGStrokeDashArray", "SVGStrokeDashArray",
"Default::default()", "Default::default()",
products="gecko", products="gecko",
animation_value_type="ComputedValue", animation_value_type="::values::computed::SVGStrokeDashArray",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing", spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)} )}

View file

@ -20,21 +20,21 @@ ${helpers.single_keyword("caption-side", "top bottom",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-caption-side")} spec="https://drafts.csswg.org/css-tables/#propdef-caption-side")}
<%helpers:longhand name="border-spacing" animation_value_type="ComputedValue" boxed="True" <%helpers:longhand name="border-spacing" animation_value_type="BorderSpacing" boxed="True"
spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing"> spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing">
use app_units::Au;
use values::specified::{AllowQuirks, Length}; use values::specified::{AllowQuirks, Length};
use values::specified::length::NonNegativeLength;
pub mod computed_value { pub mod computed_value {
use app_units::Au;
use properties::animated_properties::Animatable; use properties::animated_properties::Animatable;
use values::animated::ToAnimatedZero; use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::NonNegativeAu;
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, ToCss)]
pub struct T { pub struct T {
pub horizontal: Au, pub horizontal: NonNegativeAu,
pub vertical: Au, pub vertical: NonNegativeAu,
} }
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list /// https://drafts.csswg.org/css-transitions/#animtype-simple-list
@ -66,20 +66,38 @@ ${helpers.single_keyword("caption-side", "top bottom",
#[inline] #[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
} }
impl ToAnimatedValue for T {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
T {
horizontal: ToAnimatedValue::from_animated_value(animated.horizontal),
vertical: ToAnimatedValue::from_animated_value(animated.vertical)
}
}
}
} }
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
pub struct SpecifiedValue { pub struct SpecifiedValue {
pub horizontal: Length, pub horizontal: NonNegativeLength,
pub vertical: Option<Length>, pub vertical: Option<NonNegativeLength>,
} }
#[inline] #[inline]
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
use values::computed::NonNegativeAu;
computed_value::T { computed_value::T {
horizontal: Au(0), horizontal: NonNegativeAu::zero(),
vertical: Au(0), vertical: NonNegativeAu::zero(),
} }
} }
@ -121,14 +139,14 @@ ${helpers.single_keyword("caption-side", "top bottom",
(None, None) => Err(StyleParseError::UnspecifiedError.into()), (None, None) => Err(StyleParseError::UnspecifiedError.into()),
(Some(length), None) => { (Some(length), None) => {
Ok(SpecifiedValue { Ok(SpecifiedValue {
horizontal: length, horizontal: length.into(),
vertical: None, vertical: None,
}) })
} }
(Some(horizontal), Some(vertical)) => { (Some(horizontal), Some(vertical)) => {
Ok(SpecifiedValue { Ok(SpecifiedValue {
horizontal: horizontal, horizontal: horizontal.into(),
vertical: Some(vertical), vertical: Some(vertical.into()),
}) })
} }
(None, Some(_)) => unreachable!(), (None, Some(_)) => unreachable!(),

View file

@ -9,7 +9,7 @@
${helpers.predefined_type("line-height", ${helpers.predefined_type("line-height",
"LineHeight", "LineHeight",
"computed::LineHeight::normal()", "computed::LineHeight::normal()",
animation_value_type="ComputedValue", animation_value_type="LineHeight",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height")} spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height")}
@ -714,10 +714,9 @@ ${helpers.predefined_type("text-emphasis-color", "Color",
${helpers.predefined_type( ${helpers.predefined_type(
"-moz-tab-size", "LengthOrNumber", "-moz-tab-size", "length::NonNegativeLengthOrNumber",
"::values::Either::Second(8.0)", "::values::Either::Second(From::from(8.0))",
"parse_non_negative", products="gecko", animation_value_type="::values::computed::length::NonNegativeLengthOrNumber",
products="gecko", animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-text-3/#tab-size-property")} spec="https://drafts.csswg.org/css-text-3/#tab-size-property")}
@ -742,9 +741,9 @@ ${helpers.predefined_type(
${helpers.predefined_type("-webkit-text-stroke-width", ${helpers.predefined_type("-webkit-text-stroke-width",
"BorderSideWidth", "BorderSideWidth",
"Au::from_px(0)", "::values::computed::NonNegativeAu::from_px(0)",
initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())", initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
computed_type="::app_units::Au", computed_type="::values::computed::NonNegativeAu",
products="gecko", products="gecko",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width", spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",

View file

@ -64,10 +64,10 @@ ${helpers.predefined_type("outline-color", "Color", "computed_value::T::currentc
${helpers.predefined_type("outline-width", ${helpers.predefined_type("outline-width",
"BorderSideWidth", "BorderSideWidth",
"Au::from_px(3)", "::values::computed::NonNegativeAu::from_px(3)",
initial_specified_value="specified::BorderSideWidth::Medium", initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::app_units::Au", computed_type="::values::computed::NonNegativeAu",
animation_value_type="ComputedValue", animation_value_type="NonNegativeAu",
spec="https://drafts.csswg.org/css-ui/#propdef-outline-width")} spec="https://drafts.csswg.org/css-ui/#propdef-outline-width")}
// The -moz-outline-radius-* properties are non-standard and not on a standards track. // The -moz-outline-radius-* properties are non-standard and not on a standards track.
@ -76,7 +76,7 @@ ${helpers.predefined_type("outline-width",
"computed::LengthOrPercentage::zero().into()", "computed::LengthOrPercentage::zero().into()",
products="gecko", products="gecko",
boxed=True, boxed=True,
animation_value_type="ComputedValue", animation_value_type="BorderCornerRadius",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)")} spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)")}
% endfor % endfor

View file

@ -14,11 +14,10 @@
if side[1]: if side[1]:
spec = "https://drafts.csswg.org/css-logical-props/#propdef-padding-%s" % side[1] spec = "https://drafts.csswg.org/css-logical-props/#propdef-padding-%s" % side[1]
%> %>
${helpers.predefined_type("padding-%s" % side[0], "LengthOrPercentage", ${helpers.predefined_type("padding-%s" % side[0], "NonNegativeLengthOrPercentage",
"computed::LengthOrPercentage::Length(Au(0))", "computed::NonNegativeLengthOrPercentage::zero()",
"parse_non_negative",
alias=maybe_moz_logical_alias(product, side, "-moz-padding-%s"), alias=maybe_moz_logical_alias(product, side, "-moz-padding-%s"),
animation_value_type="ComputedValue", animation_value_type="NonNegativeLengthOrPercentage",
logical = side[1], logical = side[1],
spec = spec, spec = spec,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER",

View file

@ -117,17 +117,17 @@ ${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse",
% endif % endif
// Flex item properties // Flex item properties
${helpers.predefined_type("flex-grow", "Number", ${helpers.predefined_type("flex-grow", "NonNegativeNumber",
"0.0", "parse_non_negative", "From::from(0.0)",
spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property", spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
extra_prefixes="webkit", extra_prefixes="webkit",
animation_value_type="ComputedValue")} animation_value_type="NonNegativeNumber")}
${helpers.predefined_type("flex-shrink", "Number", ${helpers.predefined_type("flex-shrink", "NonNegativeNumber",
"1.0", "parse_non_negative", "From::from(1.0)",
spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property", spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property",
extra_prefixes="webkit", extra_prefixes="webkit",
animation_value_type="ComputedValue")} animation_value_type="NonNegativeNumber")}
// https://drafts.csswg.org/css-align/#align-self-property // https://drafts.csswg.org/css-align/#align-self-property
% if product == "servo": % if product == "servo":
@ -166,7 +166,7 @@ ${helpers.predefined_type("order", "Integer", "0",
logical=False, logical=False,
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property", spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
extra_prefixes="webkit", extra_prefixes="webkit",
animation_value_type="ComputedValue")} animation_value_type="MozLength")}
% else: % else:
// FIXME: This property should be animatable. // FIXME: This property should be animatable.
${helpers.predefined_type("flex-basis", ${helpers.predefined_type("flex-basis",
@ -187,17 +187,17 @@ ${helpers.predefined_type("order", "Integer", "0",
${helpers.gecko_size_type("%s" % size, "MozLength", "auto()", ${helpers.gecko_size_type("%s" % size, "MozLength", "auto()",
logical, logical,
spec=spec % size, spec=spec % size,
animation_value_type="ComputedValue")} animation_value_type="MozLength")}
// min-width, min-height, min-block-size, min-inline-size, // min-width, min-height, min-block-size, min-inline-size,
// max-width, max-height, max-block-size, max-inline-size // max-width, max-height, max-block-size, max-inline-size
${helpers.gecko_size_type("min-%s" % size, "MozLength", "auto()", ${helpers.gecko_size_type("min-%s" % size, "MozLength", "auto()",
logical, logical,
spec=spec % size, spec=spec % size,
animation_value_type="ComputedValue")} animation_value_type="MozLength")}
${helpers.gecko_size_type("max-%s" % size, "MaxLength", "none()", ${helpers.gecko_size_type("max-%s" % size, "MaxLength", "none()",
logical, logical,
spec=spec % size, spec=spec % size,
animation_value_type="ComputedValue")} animation_value_type="MaxLength")}
% else: % else:
// servo versions (no keyword support) // servo versions (no keyword support)
${helpers.predefined_type("%s" % size, ${helpers.predefined_type("%s" % size,
@ -249,11 +249,10 @@ ${helpers.predefined_type("object-position",
% for kind in ["row", "column"]: % for kind in ["row", "column"]:
${helpers.predefined_type("grid-%s-gap" % kind, ${helpers.predefined_type("grid-%s-gap" % kind,
"LengthOrPercentage", "NonNegativeLengthOrPercentage",
"computed::LengthOrPercentage::Length(Au(0))", "computed::NonNegativeLengthOrPercentage::zero()",
"parse_non_negative",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind, spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind,
animation_value_type="ComputedValue", animation_value_type="NonNegativeLengthOrPercentage",
products="gecko")} products="gecko")}
% for range in ["start", "end"]: % for range in ["start", "end"]:

View file

@ -24,9 +24,9 @@ ${helpers.single_keyword("-moz-box-direction", "normal reverse",
alias="-webkit-box-direction", alias="-webkit-box-direction",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)")} spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)")}
${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative", ${helpers.predefined_type("-moz-box-flex", "NonNegativeNumber", "From::from(0.)",
products="gecko", gecko_ffi_name="mBoxFlex", products="gecko", gecko_ffi_name="mBoxFlex",
animation_value_type="ComputedValue", animation_value_type="NonNegativeNumber",
alias="-webkit-box-flex", alias="-webkit-box-flex",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")} spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")}

View file

@ -10,13 +10,13 @@
<%namespace name="helpers" file="/helpers.mako.rs" /> <%namespace name="helpers" file="/helpers.mako.rs" />
#[cfg(feature = "servo")] use app_units::Au;
use servo_arc::{Arc, UniqueArc}; use servo_arc::{Arc, UniqueArc};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashSet; use std::collections::HashSet;
use std::{fmt, mem, ops}; use std::{fmt, mem, ops};
#[cfg(feature = "gecko")] use std::ptr; #[cfg(feature = "gecko")] use std::ptr;
use app_units::Au;
#[cfg(feature = "servo")] use cssparser::RGBA; #[cfg(feature = "servo")] use cssparser::RGBA;
use cssparser::{Parser, TokenSerializationType, serialize_identifier}; use cssparser::{Parser, TokenSerializationType, serialize_identifier};
use cssparser::ParserInput; use cssparser::ParserInput;
@ -43,6 +43,7 @@ use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraDat
#[cfg(feature = "servo")] use values::Either; #[cfg(feature = "servo")] use values::Either;
use values::generics::text::LineHeight; use values::generics::text::LineHeight;
use values::computed; use values::computed;
use values::computed::NonNegativeAu;
use cascade_info::CascadeInfo; use cascade_info::CascadeInfo;
use rule_tree::{CascadeLevel, StrongRuleNode}; use rule_tree::{CascadeLevel, StrongRuleNode};
use self::computed_value_flags::ComputedValueFlags; use self::computed_value_flags::ComputedValueFlags;
@ -1646,12 +1647,12 @@ pub use gecko_properties::style_structs;
/// The module where all the style structs are defined. /// The module where all the style structs are defined.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub mod style_structs { pub mod style_structs {
use app_units::Au;
use fnv::FnvHasher; use fnv::FnvHasher;
use super::longhands; use super::longhands;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use logical_geometry::WritingMode; use logical_geometry::WritingMode;
use media_queries::Device; use media_queries::Device;
use values::computed::NonNegativeAu;
% for style_struct in data.active_style_structs(): % for style_struct in data.active_style_structs():
% if style_struct.name == "Font": % if style_struct.name == "Font":
@ -1751,7 +1752,7 @@ pub mod style_structs {
/// Whether the border-${side} property has nonzero width. /// Whether the border-${side} property has nonzero width.
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn border_${side}_has_nonzero_width(&self) -> bool { pub fn border_${side}_has_nonzero_width(&self) -> bool {
self.border_${side}_width != ::app_units::Au(0) self.border_${side}_width != NonNegativeAu::zero()
} }
% endfor % endfor
% elif style_struct.name == "Font": % elif style_struct.name == "Font":
@ -1769,7 +1770,8 @@ pub mod style_structs {
/// (Servo does not handle MathML, so this just calls copy_font_size_from) /// (Servo does not handle MathML, so this just calls copy_font_size_from)
pub fn inherit_font_size_from(&mut self, parent: &Self, pub fn inherit_font_size_from(&mut self, parent: &Self,
_: Option<Au>, _: &Device) -> bool { _: Option<NonNegativeAu>,
_: &Device) -> bool {
self.copy_font_size_from(parent); self.copy_font_size_from(parent);
false false
} }
@ -1777,19 +1779,19 @@ pub mod style_structs {
pub fn apply_font_size(&mut self, pub fn apply_font_size(&mut self,
v: longhands::font_size::computed_value::T, v: longhands::font_size::computed_value::T,
_: &Self, _: &Self,
_: &Device) -> Option<Au> { _: &Device) -> Option<NonNegativeAu> {
self.set_font_size(v); self.set_font_size(v);
None None
} }
/// (Servo does not handle MathML, so this does nothing) /// (Servo does not handle MathML, so this does nothing)
pub fn apply_unconstrained_font_size(&mut self, _: Au) { pub fn apply_unconstrained_font_size(&mut self, _: NonNegativeAu) {
} }
% elif style_struct.name == "Outline": % elif style_struct.name == "Outline":
/// Whether the outline-width property is non-zero. /// Whether the outline-width property is non-zero.
#[inline] #[inline]
pub fn outline_has_nonzero_width(&self) -> bool { pub fn outline_has_nonzero_width(&self) -> bool {
self.outline_width != ::app_units::Au(0) self.outline_width != NonNegativeAu::zero()
} }
% elif style_struct.name == "Text": % elif style_struct.name == "Text":
/// Whether the text decoration has an underline. /// Whether the text decoration has an underline.
@ -2189,10 +2191,10 @@ impl ComputedValuesInner {
pub fn logical_padding(&self) -> LogicalMargin<computed::LengthOrPercentage> { pub fn logical_padding(&self) -> LogicalMargin<computed::LengthOrPercentage> {
let padding_style = self.get_padding(); let padding_style = self.get_padding();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new( LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
padding_style.padding_top, padding_style.padding_top.0,
padding_style.padding_right, padding_style.padding_right.0,
padding_style.padding_bottom, padding_style.padding_bottom.0,
padding_style.padding_left, padding_style.padding_left.0,
)) ))
} }
@ -2201,10 +2203,10 @@ impl ComputedValuesInner {
pub fn border_width_for_writing_mode(&self, writing_mode: WritingMode) -> LogicalMargin<Au> { pub fn border_width_for_writing_mode(&self, writing_mode: WritingMode) -> LogicalMargin<Au> {
let border_style = self.get_border(); let border_style = self.get_border();
LogicalMargin::from_physical(writing_mode, SideOffsets2D::new( LogicalMargin::from_physical(writing_mode, SideOffsets2D::new(
border_style.border_top_width, border_style.border_top_width.0,
border_style.border_right_width, border_style.border_right_width.0,
border_style.border_bottom_width, border_style.border_bottom_width.0,
border_style.border_left_width, border_style.border_left_width.0,
)) ))
} }
@ -3359,7 +3361,7 @@ pub fn adjust_border_width(style: &mut StyleBuilder) {
// Like calling to_computed_value, which wouldn't type check. // Like calling to_computed_value, which wouldn't type check.
if style.get_border().clone_border_${side}_style().none_or_hidden() && if style.get_border().clone_border_${side}_style().none_or_hidden() &&
style.get_border().border_${side}_has_nonzero_width() { style.get_border().border_${side}_has_nonzero_width() {
style.set_border_${side}_width(Au(0)); style.set_border_${side}_width(NonNegativeAu::zero());
} }
% endfor % endfor
} }
@ -3383,7 +3385,7 @@ pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>,
PhysicalSide::Top => (border.border_top_width, border.border_top_style), PhysicalSide::Top => (border.border_top_width, border.border_top_style),
PhysicalSide::Bottom => (border.border_bottom_width, border.border_bottom_style), PhysicalSide::Bottom => (border.border_bottom_width, border.border_bottom_style),
}; };
if current_style == (Au(0), BorderStyle::none) { if current_style == (NonNegativeAu::zero(), BorderStyle::none) {
return; return;
} }
} }
@ -3391,19 +3393,19 @@ pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>,
let border = Arc::make_mut(&mut style.border); let border = Arc::make_mut(&mut style.border);
match side { match side {
PhysicalSide::Left => { PhysicalSide::Left => {
border.border_left_width = Au(0); border.border_left_width = NonNegativeAu::zero();
border.border_left_style = BorderStyle::none; border.border_left_style = BorderStyle::none;
} }
PhysicalSide::Right => { PhysicalSide::Right => {
border.border_right_width = Au(0); border.border_right_width = NonNegativeAu::zero();
border.border_right_style = BorderStyle::none; border.border_right_style = BorderStyle::none;
} }
PhysicalSide::Bottom => { PhysicalSide::Bottom => {
border.border_bottom_width = Au(0); border.border_bottom_width = NonNegativeAu::zero();
border.border_bottom_style = BorderStyle::none; border.border_bottom_style = BorderStyle::none;
} }
PhysicalSide::Top => { PhysicalSide::Top => {
border.border_top_width = Au(0); border.border_top_width = NonNegativeAu::zero();
border.border_top_style = BorderStyle::none; border.border_top_style = BorderStyle::none;
} }
} }

View file

@ -4,6 +4,6 @@
<%namespace name="helpers" file="/helpers.mako.rs" /> <%namespace name="helpers" file="/helpers.mako.rs" />
${helpers.four_sides_shorthand("padding", "padding-%s", "specified::LengthOrPercentage::parse_non_negative", ${helpers.four_sides_shorthand("padding", "padding-%s", "specified::NonNegativeLengthOrPercentage::parse",
spec="https://drafts.csswg.org/css-box-3/#propdef-padding", spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
allow_quirks=True)} allow_quirks=True)}

View file

@ -46,12 +46,13 @@
extra_prefixes="webkit" extra_prefixes="webkit"
derive_serialize="True" derive_serialize="True"
spec="https://drafts.csswg.org/css-flexbox/#flex-property"> spec="https://drafts.csswg.org/css-flexbox/#flex-property">
use values::specified::Number; use parser::Parse;
use values::specified::NonNegativeNumber;
fn parse_flexibility<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) fn parse_flexibility<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<(Number, Option<Number>),ParseError<'i>> { -> Result<(NonNegativeNumber, Option<NonNegativeNumber>),ParseError<'i>> {
let grow = Number::parse_non_negative(context, input)?; let grow = NonNegativeNumber::parse(context, input)?;
let shrink = input.try(|i| Number::parse_non_negative(context, i)).ok(); let shrink = input.try(|i| NonNegativeNumber::parse(context, i)).ok();
Ok((grow, shrink)) Ok((grow, shrink))
} }
@ -63,8 +64,8 @@
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(expanded! { return Ok(expanded! {
flex_grow: Number::new(0.0), flex_grow: NonNegativeNumber::new(0.0),
flex_shrink: Number::new(0.0), flex_shrink: NonNegativeNumber::new(0.0),
flex_basis: longhands::flex_basis::SpecifiedValue::auto(), flex_basis: longhands::flex_basis::SpecifiedValue::auto(),
}) })
} }
@ -89,8 +90,8 @@
return Err(StyleParseError::UnspecifiedError.into()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(expanded! { Ok(expanded! {
flex_grow: grow.unwrap_or(Number::new(1.0)), flex_grow: grow.unwrap_or(NonNegativeNumber::new(1.0)),
flex_shrink: shrink.unwrap_or(Number::new(1.0)), flex_shrink: shrink.unwrap_or(NonNegativeNumber::new(1.0)),
// Per spec, this should be SpecifiedValue::zero(), but all // Per spec, this should be SpecifiedValue::zero(), but all
// browsers currently agree on using `0%`. This is a spec // browsers currently agree on using `0%`. This is a spec
// change which hasn't been adopted by browsers: // change which hasn't been adopted by browsers:
@ -458,7 +459,7 @@
use properties::longhands::grid_auto_flow::computed_value::{AutoFlow, T as SpecifiedAutoFlow}; use properties::longhands::grid_auto_flow::computed_value::{AutoFlow, T as SpecifiedAutoFlow};
use values::{Either, None_}; use values::{Either, None_};
use values::generics::grid::{GridTemplateComponent, TrackListType}; use values::generics::grid::{GridTemplateComponent, TrackListType};
use values::specified::{GenericGridTemplateComponent, LengthOrPercentage, TrackSize}; use values::specified::{GenericGridTemplateComponent, NonNegativeLengthOrPercentage, TrackSize};
pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> { -> Result<Longhands, ParseError<'i>> {
@ -519,8 +520,8 @@
grid_auto_columns: auto_cols, grid_auto_columns: auto_cols,
grid_auto_flow: flow, grid_auto_flow: flow,
// This shorthand also resets grid gap // This shorthand also resets grid gap
grid_row_gap: LengthOrPercentage::zero(), grid_row_gap: NonNegativeLengthOrPercentage::zero(),
grid_column_gap: LengthOrPercentage::zero(), grid_column_gap: NonNegativeLengthOrPercentage::zero(),
}) })
} }
@ -538,8 +539,8 @@
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
// `grid` shorthand resets these properties. If they are not zero, that means they // `grid` shorthand resets these properties. If they are not zero, that means they
// are changed by longhands and in that case we should fail serializing `grid`. // are changed by longhands and in that case we should fail serializing `grid`.
if *self.grid_row_gap != LengthOrPercentage::zero() || if *self.grid_row_gap != NonNegativeLengthOrPercentage::zero() ||
*self.grid_column_gap != LengthOrPercentage::zero() { *self.grid_column_gap != NonNegativeLengthOrPercentage::zero() {
return Ok(()); return Ok(());
} }

View file

@ -60,7 +60,8 @@ impl Device {
media_type: media_type, media_type: media_type,
viewport_size: viewport_size, viewport_size: viewport_size,
device_pixel_ratio: device_pixel_ratio, device_pixel_ratio: device_pixel_ratio,
root_font_size: AtomicIsize::new(font_size::get_initial_value().0 as isize), // FIXME(bz): Seems dubious? // FIXME(bz): Seems dubious?
root_font_size: AtomicIsize::new(font_size::get_initial_value().value() as isize),
used_root_font_size: AtomicBool::new(false), used_root_font_size: AtomicBool::new(false),
} }
} }

View file

@ -242,7 +242,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
fn adjust_for_outline(&mut self) { fn adjust_for_outline(&mut self) {
if self.style.get_outline().clone_outline_style().none_or_hidden() && if self.style.get_outline().clone_outline_style().none_or_hidden() &&
self.style.get_outline().outline_has_nonzero_width() { self.style.get_outline().outline_has_nonzero_width() {
self.style.mutate_outline().set_outline_width(Au(0)); self.style.mutate_outline().set_outline_width(Au(0).into());
} }
} }

View file

@ -12,8 +12,8 @@ use std::cmp;
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use values::Impossible; use values::Impossible;
use values::animated::{ToAnimatedValue, ToAnimatedZero}; use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::{Angle, Number}; use values::computed::{Angle, NonNegativeNumber};
use values::computed::length::Length; use values::computed::length::{Length, NonNegativeLength};
use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter; use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow; use values::generics::effects::SimpleShadow as GenericSimpleShadow;
@ -32,7 +32,7 @@ pub type TextShadowList = ShadowList<SimpleShadow>;
pub struct ShadowList<Shadow>(Vec<Shadow>); pub struct ShadowList<Shadow>(Vec<Shadow>);
/// An animated value for a single `box-shadow`. /// An animated value for a single `box-shadow`.
pub type BoxShadow = GenericBoxShadow<IntermediateColor, Length, Length>; pub type BoxShadow = GenericBoxShadow<IntermediateColor, Length, NonNegativeLength, Length>;
/// An animated value for the `filter` property. /// An animated value for the `filter` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -41,14 +41,14 @@ pub struct FilterList(pub Vec<Filter>);
/// An animated value for a single `filter`. /// An animated value for a single `filter`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow>; pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow>;
/// An animated value for a single `filter`. /// An animated value for a single `filter`.
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Number, Length, Impossible>; pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible>;
/// An animated value for the `drop-shadow()` filter. /// An animated value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, Length>; pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, NonNegativeLength>;
impl ToAnimatedValue for ComputedBoxShadowList { impl ToAnimatedValue for ComputedBoxShadowList {
type AnimatedValue = BoxShadowList; type AnimatedValue = BoxShadowList;

View file

@ -9,7 +9,17 @@
//! module's raison d'être is to ultimately contain all these types. //! module's raison d'être is to ultimately contain all these types.
use app_units::Au; use app_units::Au;
use smallvec::SmallVec;
use std::cmp::max;
use values::computed::Angle as ComputedAngle; use values::computed::Angle as ComputedAngle;
use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use values::computed::GreaterThanOrEqualToOneNumber as ComputedGreaterThanOrEqualToOneNumber;
use values::computed::MaxLength as ComputedMaxLength;
use values::computed::MozLength as ComputedMozLength;
use values::computed::NonNegativeAu;
use values::computed::NonNegativeLengthOrPercentage as ComputedNonNegativeLengthOrPercentage;
use values::computed::NonNegativeNumber as ComputedNonNegativeNumber;
use values::computed::PositiveInteger as ComputedPositiveInteger;
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
pub mod effects; pub mod effects;
@ -62,6 +72,23 @@ where
} }
} }
impl<T> ToAnimatedValue for SmallVec<[T; 1]>
where
T: ToAnimatedValue,
{
type AnimatedValue = SmallVec<[T::AnimatedValue; 1]>;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
self.into_iter().map(T::to_animated_value).collect()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.into_iter().map(T::from_animated_value).collect()
}
}
/// Marker trait for computed values with the same representation during animations. /// Marker trait for computed values with the same representation during animations.
pub trait AnimatedValueAsComputed {} pub trait AnimatedValueAsComputed {}
@ -88,6 +115,149 @@ where
} }
} }
impl ToAnimatedValue for ComputedNonNegativeNumber {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.0.max(0.).into()
}
}
impl ToAnimatedValue for ComputedGreaterThanOrEqualToOneNumber {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.0.max(1.).into()
}
}
impl ToAnimatedValue for NonNegativeAu {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
max(animated.0, Au(0)).into()
}
}
impl ToAnimatedValue for ComputedPositiveInteger {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
max(animated.0, 0).into()
}
}
impl ToAnimatedValue for ComputedNonNegativeLengthOrPercentage {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.0.clamp_to_non_negative().into()
}
}
impl ToAnimatedValue for ComputedBorderCornerRadius {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedBorderCornerRadius::new(animated.0.width.clamp_to_non_negative(),
animated.0.height.clamp_to_non_negative())
}
}
impl ToAnimatedValue for ComputedMaxLength {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
use values::computed::{LengthOrPercentageOrNone, Percentage};
match animated {
ComputedMaxLength::LengthOrPercentageOrNone(lopn) => {
let result = match lopn {
LengthOrPercentageOrNone::Length(au) => {
LengthOrPercentageOrNone::Length(max(au, Au(0)))
},
LengthOrPercentageOrNone::Percentage(percentage) => {
LengthOrPercentageOrNone::Percentage(Percentage(percentage.0.max(0.)))
}
_ => lopn
};
ComputedMaxLength::LengthOrPercentageOrNone(result)
},
_ => animated
}
}
}
impl ToAnimatedValue for ComputedMozLength {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
use values::computed::{LengthOrPercentageOrAuto, Percentage};
match animated {
ComputedMozLength::LengthOrPercentageOrAuto(lopa) => {
let result = match lopa {
LengthOrPercentageOrAuto::Length(au) => {
LengthOrPercentageOrAuto::Length(max(au, Au(0)))
},
LengthOrPercentageOrAuto::Percentage(percentage) => {
LengthOrPercentageOrAuto::Percentage(Percentage(percentage.0.max(0.)))
}
_ => lopa
};
ComputedMozLength::LengthOrPercentageOrAuto(result)
},
_ => animated
}
}
}
/// Returns a value similar to `self` that represents zero. /// Returns a value similar to `self` that represents zero.
pub trait ToAnimatedZero: Sized { pub trait ToAnimatedZero: Sized {
/// Returns a value that, when added with an underlying value, will produce the underlying /// Returns a value that, when added with an underlying value, will produce the underlying

View file

@ -5,7 +5,8 @@
//! Computed types for CSS values related to backgrounds. //! Computed types for CSS values related to backgrounds.
use properties::animated_properties::{Animatable, RepeatableListAnimatable}; use properties::animated_properties::{Animatable, RepeatableListAnimatable};
use values::animated::ToAnimatedZero; use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::length::LengthOrPercentageOrAuto; use values::computed::length::LengthOrPercentageOrAuto;
use values::generics::background::BackgroundSize as GenericBackgroundSize; use values::generics::background::BackgroundSize as GenericBackgroundSize;
@ -56,3 +57,52 @@ impl ToAnimatedZero for BackgroundSize {
#[inline] #[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
} }
impl ToAnimatedValue for BackgroundSize {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
use app_units::Au;
use values::computed::Percentage;
let clamp_animated_value = |value: LengthOrPercentageOrAuto| -> LengthOrPercentageOrAuto {
match value {
LengthOrPercentageOrAuto::Length(len) => {
LengthOrPercentageOrAuto::Length(Au(::std::cmp::max(len.0, 0)))
},
LengthOrPercentageOrAuto::Percentage(percent) => {
LengthOrPercentageOrAuto::Percentage(Percentage(percent.0.max(0.)))
},
_ => value
}
};
match animated {
GenericBackgroundSize::Explicit { width, height } => {
GenericBackgroundSize::Explicit {
width: clamp_animated_value(width),
height: clamp_animated_value(height)
}
},
_ => animated
}
}
}
impl ToAnimatedValue for BackgroundSizeList {
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
BackgroundSizeList(ToAnimatedValue::from_animated_value(animated.0))
}
}

View file

@ -6,23 +6,23 @@
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use values::Impossible; use values::Impossible;
use values::computed::{Angle, Number}; use values::computed::{Angle, NonNegativeNumber};
use values::computed::color::Color; use values::computed::color::Color;
use values::computed::length::Length; use values::computed::length::{Length, NonNegativeLength};
use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter; use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow; use values::generics::effects::SimpleShadow as GenericSimpleShadow;
/// A computed value for a single shadow of the `box-shadow` property. /// A computed value for a single shadow of the `box-shadow` property.
pub type BoxShadow = GenericBoxShadow<Color, Length, Length>; pub type BoxShadow = GenericBoxShadow<Color, Length, NonNegativeLength, Length>;
/// A computed value for a single `filter`. /// A computed value for a single `filter`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow>; pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow>;
/// A computed value for a single `filter`. /// A computed value for a single `filter`.
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Number, Length, Impossible>; pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible>;
/// A computed value for the `drop-shadow()` filter. /// A computed value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>; pub type SimpleShadow = GenericSimpleShadow<Color, Length, NonNegativeLength>;

View file

@ -11,6 +11,8 @@ use style_traits::ToCss;
use style_traits::values::specified::AllowedLengthType; use style_traits::values::specified::AllowedLengthType;
use super::{Number, ToComputedValue, Context}; use super::{Number, ToComputedValue, Context};
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified}; use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
use values::computed::{NonNegativeAu, NonNegativeNumber};
use values::generics::NonNegative;
use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength}; use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
use values::specified::length::ViewportPercentageLength; use values::specified::length::ViewportPercentageLength;
@ -71,7 +73,7 @@ impl ToComputedValue for specified::NoCalcLength {
specified::NoCalcLength::ViewportPercentage(length) => specified::NoCalcLength::ViewportPercentage(length) =>
length.to_computed_value(context.viewport_size()), length.to_computed_value(context.viewport_size()),
specified::NoCalcLength::ServoCharacterWidth(length) => specified::NoCalcLength::ServoCharacterWidth(length) =>
length.to_computed_value(context.style().get_font().clone_font_size()), length.to_computed_value(context.style().get_font().clone_font_size().0),
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
specified::NoCalcLength::Physical(length) => specified::NoCalcLength::Physical(length) =>
length.to_computed_value(context), length.to_computed_value(context),
@ -265,7 +267,7 @@ impl specified::CalcLengthOrPercentage {
/// Compute font-size or line-height taking into account text-zoom if necessary. /// Compute font-size or line-height taking into account text-zoom if necessary.
pub fn to_computed_value_zoomed(&self, context: &Context) -> CalcLengthOrPercentage { pub fn to_computed_value_zoomed(&self, context: &Context) -> CalcLengthOrPercentage {
self.to_computed_value_with_zoom(context, |abs| context.maybe_zoom_text(abs)) self.to_computed_value_with_zoom(context, |abs| context.maybe_zoom_text(abs.into()).0)
} }
} }
@ -349,6 +351,20 @@ impl LengthOrPercentage {
}, },
} }
} }
/// Returns the clamped non-negative values.
#[inline]
pub fn clamp_to_non_negative(self) -> Self {
match self {
LengthOrPercentage::Length(length) => {
LengthOrPercentage::Length(Au(::std::cmp::max(length.0, 0)))
},
LengthOrPercentage::Percentage(percentage) => {
LengthOrPercentage::Percentage(Percentage(percentage.0.max(0.)))
},
_ => self
}
}
} }
impl fmt::Debug for LengthOrPercentage { impl fmt::Debug for LengthOrPercentage {
@ -550,6 +566,43 @@ impl ToComputedValue for specified::LengthOrPercentageOrNone {
} }
} }
/// A wrapper of LengthOrPercentage, whose value must be >= 0.
pub type NonNegativeLengthOrPercentage = NonNegative<LengthOrPercentage>;
impl From<NonNegativeAu> for NonNegativeLengthOrPercentage {
#[inline]
fn from(length: NonNegativeAu) -> Self {
LengthOrPercentage::Length(length.0).into()
}
}
impl From<LengthOrPercentage> for NonNegativeLengthOrPercentage {
#[inline]
fn from(lop: LengthOrPercentage) -> Self {
NonNegative::<LengthOrPercentage>(lop)
}
}
impl NonNegativeLengthOrPercentage {
/// Get zero value.
#[inline]
pub fn zero() -> Self {
NonNegative::<LengthOrPercentage>(LengthOrPercentage::zero())
}
/// Returns true if the computed value is absolute 0 or 0%.
#[inline]
pub fn is_definitely_zero(&self) -> bool {
self.0.is_definitely_zero()
}
/// Returns the used value.
#[inline]
pub fn to_used_value(&self, containing_length: Au) -> Au {
self.0.to_used_value(containing_length)
}
}
/// A computed `<length>` value. /// A computed `<length>` value.
pub type Length = Au; pub type Length = Au;
@ -573,6 +626,18 @@ impl LengthOrNumber {
/// Either a computed `<length>` or the `normal` keyword. /// Either a computed `<length>` or the `normal` keyword.
pub type LengthOrNormal = Either<Length, Normal>; pub type LengthOrNormal = Either<Length, Normal>;
/// A wrapper of Length, whose value must be >= 0.
pub type NonNegativeLength = NonNegativeAu;
/// Either a computed NonNegativeLength or the `auto` keyword.
pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
/// Either a computed NonNegativeLength or the `normal` keyword.
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
/// Either a computed NonNegativeLength or a NonNegativeNumber value.
pub type NonNegativeLengthOrNumber = Either<NonNegativeLength, NonNegativeNumber>;
/// A value suitable for a `min-width`, `min-height`, `width` or `height` property. /// A value suitable for a `min-width`, `min-height`, `width` or `height` property.
/// See values/specified/length.rs for more details. /// See values/specified/length.rs for more details.
#[allow(missing_docs)] #[allow(missing_docs)]

View file

@ -18,6 +18,7 @@ use std::f64::consts::PI;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::ToCss;
use super::{CSSFloat, CSSInteger}; use super::{CSSFloat, CSSInteger};
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize}; use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
use super::generics::grid::TrackList as GenericTrackList; use super::generics::grid::TrackList as GenericTrackList;
@ -43,8 +44,9 @@ pub use super::generics::grid::GridLine;
pub use super::specified::url::SpecifiedUrl; pub use super::specified::url::SpecifiedUrl;
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNumber, LengthOrPercentage}; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNumber, LengthOrPercentage};
pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength, Percentage}; pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength, Percentage};
pub use self::length::NonNegativeLengthOrPercentage;
pub use self::position::Position; pub use self::position::Position;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::{TimingFunction, TransformOrigin}; pub use self::transform::{TimingFunction, TransformOrigin};
@ -136,12 +138,12 @@ impl<'a> Context<'a> {
/// Apply text-zoom if enabled /// Apply text-zoom if enabled
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn maybe_zoom_text(&self, size: Au) -> Au { pub fn maybe_zoom_text(&self, size: NonNegativeAu) -> NonNegativeAu {
// We disable zoom for <svg:text> by unsetting the // We disable zoom for <svg:text> by unsetting the
// -x-text-zoom property, which leads to a false value // -x-text-zoom property, which leads to a false value
// in mAllowZoom // in mAllowZoom
if self.style().get_font().gecko.mAllowZoom { if self.style().get_font().gecko.mAllowZoom {
self.device().zoom_text(size) self.device().zoom_text(size.0).into()
} else { } else {
size size
} }
@ -149,7 +151,7 @@ impl<'a> Context<'a> {
/// (Servo doesn't do text-zoom) /// (Servo doesn't do text-zoom)
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn maybe_zoom_text(&self, size: Au) -> Au { pub fn maybe_zoom_text(&self, size: NonNegativeAu) -> NonNegativeAu {
size size
} }
} }
@ -425,6 +427,40 @@ impl ComputedValueAsSpecified for specified::BorderStyle {}
/// A `<number>` value. /// A `<number>` value.
pub type Number = CSSFloat; pub type Number = CSSFloat;
/// A wrapper of Number, but the value >= 0.
pub type NonNegativeNumber = NonNegative<CSSFloat>;
impl From<CSSFloat> for NonNegativeNumber {
#[inline]
fn from(number: CSSFloat) -> NonNegativeNumber {
NonNegative::<CSSFloat>(number)
}
}
impl From<NonNegativeNumber> for CSSFloat {
#[inline]
fn from(number: NonNegativeNumber) -> CSSFloat {
number.0
}
}
/// A wrapper of Number, but the value >= 1.
pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
impl From<CSSFloat> for GreaterThanOrEqualToOneNumber {
#[inline]
fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber {
GreaterThanOrEqualToOne::<CSSFloat>(number)
}
}
impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
#[inline]
fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
number.0
}
}
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, ToCss)]
@ -476,9 +512,25 @@ impl IntegerOrAuto {
} }
} }
/// A wrapper of Integer, but only accept a value >= 1.
pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>;
impl From<CSSInteger> for PositiveInteger {
#[inline]
fn from(int: CSSInteger) -> PositiveInteger {
GreaterThanOrEqualToOne::<CSSInteger>(int)
}
}
/// PositiveInteger | auto
pub type PositiveIntegerOrAuto = Either<PositiveInteger, Auto>;
/// <length> | <percentage> | <number> /// <length> | <percentage> | <number>
pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>; pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
/// NonNegativeLengthOrPercentage | NonNegativeNumber
pub type NonNegativeLengthOrPercentageOrNumber = Either<NonNegativeNumber, NonNegativeLengthOrPercentage>;
#[derive(Clone, PartialEq, Eq, Copy, Debug)] #[derive(Clone, PartialEq, Eq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)] #[allow(missing_docs)]
@ -556,3 +608,40 @@ impl ClipRectOrAuto {
/// <color> | auto /// <color> | auto
pub type ColorOrAuto = Either<Color, Auto>; pub type ColorOrAuto = Either<Color, Auto>;
/// A wrapper of Au, but the value >= 0.
pub type NonNegativeAu = NonNegative<Au>;
impl NonNegativeAu {
/// Return a zero value.
#[inline]
pub fn zero() -> Self {
NonNegative::<Au>(Au(0))
}
/// Return a NonNegativeAu from pixel.
#[inline]
pub fn from_px(px: i32) -> Self {
NonNegative::<Au>(Au::from_px(::std::cmp::max(px, 0)))
}
/// Get the inner value of |NonNegativeAu.0|.
#[inline]
pub fn value(self) -> i32 {
(self.0).0
}
/// Scale this NonNegativeAu.
#[inline]
pub fn scale_by(self, factor: f32) -> Self {
// scale this by zero if factor is negative.
NonNegative::<Au>(self.0.scale_by(factor.max(0.)))
}
}
impl From<Au> for NonNegativeAu {
#[inline]
fn from(au: Au) -> NonNegativeAu {
NonNegative::<Au>(au)
}
}

View file

@ -7,6 +7,7 @@
use app_units::Au; use app_units::Au;
use values::{Either, RGBA}; use values::{Either, RGBA};
use values::computed::{LengthOrPercentageOrNumber, Opacity}; use values::computed::{LengthOrPercentageOrNumber, Opacity};
use values::computed::{NonNegativeAu, NonNegativeLengthOrPercentageOrNumber};
use values::generics::svg as generic; use values::generics::svg as generic;
/// Computed SVG Paint value /// Computed SVG Paint value
@ -43,8 +44,17 @@ impl From<Au> for SVGLength {
} }
} }
/// An non-negative wrapper of SVGLength.
pub type SVGWidth = generic::SVGLength<NonNegativeLengthOrPercentageOrNumber>;
impl From<NonNegativeAu> for SVGWidth {
fn from(length: NonNegativeAu) -> Self {
generic::SVGLength::Length(Either::Second(length.into()))
}
}
/// [ <length> | <percentage> | <number> ]# | context-value /// [ <length> | <percentage> | <number> ]# | context-value
pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<LengthOrPercentageOrNumber>; pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeLengthOrPercentageOrNumber>;
impl Default for SVGStrokeDashArray { impl Default for SVGStrokeDashArray {
fn default() -> Self { fn default() -> Self {

View file

@ -4,10 +4,10 @@
//! Computed types for text properties. //! Computed types for text properties.
use app_units::Au;
use properties::animated_properties::Animatable; use properties::animated_properties::Animatable;
use values::{CSSInteger, CSSFloat}; use values::{CSSInteger, CSSFloat};
use values::animated::ToAnimatedZero; use values::animated::ToAnimatedZero;
use values::computed::{NonNegativeAu, NonNegativeNumber};
use values::computed::length::{Length, LengthOrPercentage}; use values::computed::length::{Length, LengthOrPercentage};
use values::generics::text::InitialLetter as GenericInitialLetter; use values::generics::text::InitialLetter as GenericInitialLetter;
use values::generics::text::LineHeight as GenericLineHeight; use values::generics::text::LineHeight as GenericLineHeight;
@ -23,7 +23,7 @@ pub type LetterSpacing = Spacing<Length>;
pub type WordSpacing = Spacing<LengthOrPercentage>; pub type WordSpacing = Spacing<LengthOrPercentage>;
/// A computed value for the `line-height` property. /// A computed value for the `line-height` property.
pub type LineHeight = GenericLineHeight<CSSFloat, Au>; pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeAu>;
impl Animatable for LineHeight { impl Animatable for LineHeight {
#[inline] #[inline]

View file

@ -12,9 +12,9 @@ use values::specified::url::SpecifiedUrl;
/// A generic value for a single `box-shadow`. /// A generic value for a single `box-shadow`.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)] #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
pub struct BoxShadow<Color, SizeLength, ShapeLength> { pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// The base shadow. /// The base shadow.
pub base: SimpleShadow<Color, SizeLength, ShapeLength>, pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
/// The spread radius. /// The spread radius.
pub spread: ShapeLength, pub spread: ShapeLength,
/// Whether this is an inset box shadow. /// Whether this is an inset box shadow.
@ -77,10 +77,14 @@ pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
pub blur: ShapeLength, pub blur: ShapeLength,
} }
impl<Color, SizeLength, ShapeLength> ToCss for BoxShadow<Color, SizeLength, ShapeLength> impl<Color, SizeLength, BlurShapeLength, ShapeLength> ToCss for BoxShadow<Color,
SizeLength,
BlurShapeLength,
ShapeLength>
where where
Color: ToCss, Color: ToCss,
SizeLength: ToCss, SizeLength: ToCss,
BlurShapeLength: ToCss,
ShapeLength: ToCss, ShapeLength: ToCss,
{ {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result fn to_css<W>(&self, dest: &mut W) -> fmt::Result

View file

@ -252,3 +252,13 @@ impl ToCss for FontSettingTagFloat {
self.0.to_css(dest) self.0.to_css(dest)
} }
} }
/// A wrapper of Non-negative values.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct NonNegative<T>(pub T);
/// A wrapper of greater-than-or-equal-to-one values.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct GreaterThanOrEqualToOne<T>(pub T);

View file

@ -98,7 +98,7 @@ impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
/// An SVG length value supports `context-value` in addition to length. /// An SVG length value supports `context-value` in addition to length.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, HasViewportPercentage, ToComputedValue, ToCss)] #[derive(Clone, Copy, Debug, PartialEq, HasViewportPercentage, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum SVGLength<LengthType> { pub enum SVGLength<LengthType> {
/// `<length> | <percentage> | <number>` /// `<length> | <percentage> | <number>`
Length(LengthType), Length(LengthType),
@ -108,7 +108,7 @@ pub enum SVGLength<LengthType> {
/// Generic value for stroke-dasharray. /// Generic value for stroke-dasharray.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, HasViewportPercentage, ToComputedValue)] #[derive(Clone, Debug, PartialEq, HasViewportPercentage, ToAnimatedValue, ToComputedValue)]
pub enum SVGStrokeDashArray<LengthType> { pub enum SVGStrokeDashArray<LengthType> {
/// `[ <length> | <percentage> | <number> ]#` /// `[ <length> | <percentage> | <number> ]#`
Values(Vec<LengthType>), Values(Vec<LengthType>),

View file

@ -104,7 +104,7 @@ where
/// A generic value for the `line-height` property. /// A generic value for the `line-height` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToCss)] #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue, ToCss)]
pub enum LineHeight<Number, LengthOrPercentage> { pub enum LineHeight<Number, LengthOrPercentage> {
/// `normal` /// `normal`
Normal, Normal,

View file

@ -4,11 +4,10 @@
//! Specified types for CSS values related to borders. //! Specified types for CSS values related to borders.
use app_units::Au;
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::ParseError; use style_traits::ParseError;
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, NonNegativeAu, ToComputedValue};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use values::generics::border::BorderImageSlice as GenericBorderImageSlice; use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
@ -72,7 +71,7 @@ impl Parse for BorderSideWidth {
} }
impl ToComputedValue for BorderSideWidth { impl ToComputedValue for BorderSideWidth {
type ComputedValue = Au; type ComputedValue = NonNegativeAu;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
@ -84,12 +83,12 @@ impl ToComputedValue for BorderSideWidth {
BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context), BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context),
BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context), BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context),
BorderSideWidth::Length(ref length) => length.to_computed_value(context) BorderSideWidth::Length(ref length) => length.to_computed_value(context)
} }.into()
} }
#[inline] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { fn from_computed_value(computed: &Self::ComputedValue) -> Self {
BorderSideWidth::Length(ToComputedValue::from_computed_value(computed)) BorderSideWidth::Length(ToComputedValue::from_computed_value(&computed.0))
} }
} }

View file

@ -9,28 +9,29 @@ use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseError}; use style_traits::{ParseError, StyleParseError};
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use values::Impossible; use values::Impossible;
use values::computed::{Context, Number as ComputedNumber, ToComputedValue}; use values::computed::{Context, NonNegativeNumber as ComputedNonNegativeNumber, ToComputedValue};
use values::computed::effects::BoxShadow as ComputedBoxShadow; use values::computed::effects::BoxShadow as ComputedBoxShadow;
use values::computed::effects::SimpleShadow as ComputedSimpleShadow; use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
use values::generics::NonNegative;
use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter; use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow; use values::generics::effects::SimpleShadow as GenericSimpleShadow;
use values::specified::{Angle, NumberOrPercentage}; use values::specified::{Angle, NumberOrPercentage};
use values::specified::color::Color; use values::specified::color::Color;
use values::specified::length::Length; use values::specified::length::{Length, NonNegativeLength};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
/// A specified value for a single shadow of the `box-shadow` property. /// A specified value for a single shadow of the `box-shadow` property.
pub type BoxShadow = GenericBoxShadow<Option<Color>, Length, Option<Length>>; pub type BoxShadow = GenericBoxShadow<Option<Color>, Length, Option<NonNegativeLength>, Option<Length>>;
/// A specified value for a single `filter`. /// A specified value for a single `filter`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Factor, Length, SimpleShadow>; pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow>;
/// A specified value for a single `filter`. /// A specified value for a single `filter`.
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Factor, Length, Impossible>; pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible>;
/// A value for the `<factor>` parts in `Filter`. /// A value for the `<factor>` parts in `Filter`.
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
@ -48,25 +49,25 @@ impl Parse for Factor {
} }
impl ToComputedValue for Factor { impl ToComputedValue for Factor {
type ComputedValue = ComputedNumber; type ComputedValue = ComputedNonNegativeNumber;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
use values::computed::NumberOrPercentage; use values::computed::NumberOrPercentage;
match self.0.to_computed_value(context) { match self.0.to_computed_value(context) {
NumberOrPercentage::Number(n) => n, NumberOrPercentage::Number(n) => n.into(),
NumberOrPercentage::Percentage(p) => p.0, NumberOrPercentage::Percentage(p) => p.0.into(),
} }
} }
#[inline] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(computed))) Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(&computed.0)))
} }
} }
/// A specified value for the `drop-shadow()` filter. /// A specified value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<Length>>; pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<NonNegativeLength>>;
impl Parse for BoxShadow { impl Parse for BoxShadow {
fn parse<'i, 't>( fn parse<'i, 't>(
@ -91,7 +92,7 @@ impl Parse for BoxShadow {
let (blur, spread) = match i.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i)) { let (blur, spread) = match i.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i)) {
Ok(blur) => { Ok(blur) => {
let spread = i.try(|i| Length::parse(context, i)).ok(); let spread = i.try(|i| Length::parse(context, i)).ok();
(Some(blur), spread) (Some(blur.into()), spread)
}, },
Err(_) => (None, None), Err(_) => (None, None),
}; };
@ -162,7 +163,7 @@ impl Parse for Filter {
let function = input.expect_function()?.clone(); let function = input.expect_function()?.clone();
input.parse_nested_block(|i| { input.parse_nested_block(|i| {
try_match_ident_ignore_ascii_case! { function, try_match_ident_ignore_ascii_case! { function,
"blur" => Ok(GenericFilter::Blur(Length::parse_non_negative(context, i)?)), "blur" => Ok(GenericFilter::Blur((Length::parse_non_negative(context, i)?).into())),
"brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)), "brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)),
"contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)), "contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)),
"grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)), "grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)),
@ -192,7 +193,7 @@ impl Parse for SimpleShadow {
color: color, color: color,
horizontal: horizontal, horizontal: horizontal,
vertical: vertical, vertical: vertical,
blur: blur, blur: blur.map(NonNegative::<Length>),
}) })
} }
} }
@ -208,7 +209,7 @@ impl ToComputedValue for SimpleShadow {
horizontal: self.horizontal.to_computed_value(context), horizontal: self.horizontal.to_computed_value(context),
vertical: self.vertical.to_computed_value(context), vertical: self.vertical.to_computed_value(context),
blur: blur:
self.blur.as_ref().unwrap_or(&Length::zero()).to_computed_value(context), self.blur.as_ref().unwrap_or(&NonNegativeLength::zero()).to_computed_value(context),
} }
} }

View file

@ -21,6 +21,8 @@ use super::{AllowQuirks, Number, ToComputedValue};
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, None_, Normal}; use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, None_, Normal};
use values::ExtremumLength; use values::ExtremumLength;
use values::computed::{self, Context}; use values::computed::{self, Context};
use values::generics::NonNegative;
use values::specified::NonNegativeNumber;
use values::specified::calc::CalcNode; use values::specified::calc::CalcNode;
pub use values::specified::calc::CalcLengthOrPercentage; pub use values::specified::calc::CalcLengthOrPercentage;
@ -92,8 +94,8 @@ impl FontBaseSize {
pub fn resolve(&self, context: &Context) -> Au { pub fn resolve(&self, context: &Context) -> Au {
match *self { match *self {
FontBaseSize::Custom(size) => size, FontBaseSize::Custom(size) => size,
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size(), FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().0,
FontBaseSize::InheritedStyle => context.style().get_parent_font().clone_font_size(), FontBaseSize::InheritedStyle => context.style().get_parent_font().clone_font_size().0,
} }
} }
} }
@ -703,6 +705,57 @@ impl<T: Parse> Either<Length, T> {
} }
} }
/// A wrapper of Length, whose value must be >= 0.
pub type NonNegativeLength = NonNegative<Length>;
impl From<NoCalcLength> for NonNegativeLength {
#[inline]
fn from(len: NoCalcLength) -> Self {
NonNegative::<Length>(Length::NoCalc(len))
}
}
impl From<Length> for NonNegativeLength {
#[inline]
fn from(len: Length) -> Self {
NonNegative::<Length>(len)
}
}
impl<T: Parse> Parse for Either<NonNegativeLength, T> {
#[inline]
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(v) = input.try(|input| T::parse(context, input)) {
return Ok(Either::Second(v));
}
Length::parse_internal(context, input, AllowedLengthType::NonNegative, AllowQuirks::No)
.map(NonNegative::<Length>).map(Either::First)
}
}
impl NonNegativeLength {
/// Returns a `zero` length.
#[inline]
pub fn zero() -> Self {
Length::zero().into()
}
/// Get an absolute length from a px value.
#[inline]
pub fn from_px(px_value: CSSFloat) -> Self {
Length::from_px(px_value.max(0.)).into()
}
}
/// Either a NonNegativeLength or the `normal` keyword.
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
/// Either a NonNegativeLength or the `auto` keyword.
pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
/// Either a NonNegativeLength or a NonNegativeNumber value.
pub type NonNegativeLengthOrNumber = Either<NonNegativeLength, NonNegativeNumber>;
/// A percentage value. /// A percentage value.
#[derive(Clone, Copy, Debug, Default, PartialEq)] #[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -1185,6 +1238,41 @@ impl Parse for LengthOrPercentageOrNone {
} }
} }
/// A wrapper of LengthOrPercentage, whose value must be >= 0.
pub type NonNegativeLengthOrPercentage = NonNegative<LengthOrPercentage>;
impl From<NoCalcLength> for NonNegativeLengthOrPercentage {
#[inline]
fn from(len: NoCalcLength) -> Self {
NonNegative::<LengthOrPercentage>(LengthOrPercentage::from(len))
}
}
impl Parse for NonNegativeLengthOrPercentage {
#[inline]
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
LengthOrPercentage::parse_non_negative(context, input).map(NonNegative::<LengthOrPercentage>)
}
}
impl NonNegativeLengthOrPercentage {
#[inline]
/// Returns a `zero` length.
pub fn zero() -> Self {
NonNegative::<LengthOrPercentage>(LengthOrPercentage::zero())
}
/// Parses a length or a percentage, allowing the unitless length quirk.
/// https://quirks.spec.whatwg.org/#the-unitless-length-quirk
#[inline]
pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) -> Result<Self, ParseError<'i>> {
LengthOrPercentage::parse_non_negative_quirky(context, input, allow_quirks)
.map(NonNegative::<LengthOrPercentage>)
}
}
/// Either a `<length>` or the `none` keyword. /// Either a `<length>` or the `none` keyword.
pub type LengthOrNone = Either<Length, None_>; pub type LengthOrNone = Either<Length, None_>;

View file

@ -18,6 +18,7 @@ use style_traits::{ToCss, ParseError, StyleParseError};
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use super::{Auto, CSSFloat, CSSInteger, Either, None_}; use super::{Auto, CSSFloat, CSSInteger, Either, None_};
use super::computed::{self, Context, ToComputedValue}; use super::computed::{self, Context, ToComputedValue};
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize}; use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
use super::generics::grid::TrackList as GenericTrackList; use super::generics::grid::TrackList as GenericTrackList;
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
@ -41,9 +42,10 @@ pub use self::length::{FontRelativeLength, Length, LengthOrNone, LengthOrNumber}
pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto};
pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength}; pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength};
pub use self::length::{NoCalcLength, Percentage, ViewportPercentageLength}; pub use self::length::{NoCalcLength, Percentage, ViewportPercentageLength};
pub use self::length::NonNegativeLengthOrPercentage;
pub use self::rect::LengthOrNumberRect; pub use self::rect::LengthOrNumberRect;
pub use self::position::{Position, PositionComponent}; pub use self::position::{Position, PositionComponent};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::{TimingFunction, TransformOrigin}; pub use self::transform::{TimingFunction, TransformOrigin};
pub use super::generics::grid::GridLine; pub use super::generics::grid::GridLine;
@ -533,6 +535,33 @@ impl ToCss for Number {
} }
} }
/// A Number which is >= 0.0.
pub type NonNegativeNumber = NonNegative<Number>;
impl Parse for NonNegativeNumber {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
parse_number_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
.map(NonNegative::<Number>)
}
}
impl NonNegativeNumber {
/// Returns a new non-negative number with the value `val`.
pub fn new(val: CSSFloat) -> Self {
NonNegative::<Number>(Number::new(val.max(0.)))
}
}
/// A Number which is >= 1.0.
pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<Number>;
impl Parse for GreaterThanOrEqualToOneNumber {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
parse_number_with_clamping_mode(context, input, AllowedNumericType::AtLeastOne)
.map(GreaterThanOrEqualToOne::<Number>)
}
}
/// <number> | <percentage> /// <number> | <percentage>
/// ///
/// Accepts only non-negative numbers. /// Accepts only non-negative numbers.
@ -713,6 +742,19 @@ impl IntegerOrAuto {
} }
} }
/// A wrapper of Integer, with value >= 1.
pub type PositiveInteger = GreaterThanOrEqualToOne<Integer>;
impl Parse for PositiveInteger {
#[inline]
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Integer::parse_positive(context, input).map(GreaterThanOrEqualToOne::<Integer>)
}
}
/// PositiveInteger | auto
pub type PositiveIntegerOrAuto = Either<PositiveInteger, Auto>;
#[allow(missing_docs)] #[allow(missing_docs)]
pub type UrlOrNone = Either<SpecifiedUrl, None_>; pub type UrlOrNone = Either<SpecifiedUrl, None_>;
@ -732,19 +774,8 @@ pub type GridTemplateComponent = GenericGridTemplateComponent<LengthOrPercentage
/// <length> | <percentage> | <number> /// <length> | <percentage> | <number>
pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>; pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
impl LengthOrPercentageOrNumber { /// NonNegativeLengthOrPercentage | NonNegativeNumber
/// parse a <length-percentage> | <number> enforcing that the contents aren't negative pub type NonNegativeLengthOrPercentageOrNumber = Either<NonNegativeNumber, NonNegativeLengthOrPercentage>;
pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
// NB: Parse numbers before Lengths so we are consistent about how to
// recognize and serialize "0".
if let Ok(num) = input.try(|i| Number::parse_non_negative(context, i)) {
return Ok(Either::First(num))
}
LengthOrPercentage::parse_non_negative(context, input).map(Either::Second)
}
}
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] #[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]

View file

@ -8,7 +8,7 @@ use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::{CommaWithSpace, ParseError, Separator, StyleParseError}; use style_traits::{CommaWithSpace, ParseError, Separator, StyleParseError};
use values::generics::svg as generic; use values::generics::svg as generic;
use values::specified::{LengthOrPercentageOrNumber, Opacity}; use values::specified::{LengthOrPercentageOrNumber, NonNegativeLengthOrPercentageOrNumber, Opacity};
use values::specified::color::RGBAColor; use values::specified::color::RGBAColor;
/// Specified SVG Paint value /// Specified SVG Paint value
@ -54,30 +54,38 @@ impl Parse for SVGLength {
} }
} }
impl SVGLength {
/// parse a non-negative SVG length
pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
input.try(|i| LengthOrPercentageOrNumber::parse_non_negative(context, i))
.map(Into::into)
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
}
}
impl From<LengthOrPercentageOrNumber> for SVGLength { impl From<LengthOrPercentageOrNumber> for SVGLength {
fn from(length: LengthOrPercentageOrNumber) -> Self { fn from(length: LengthOrPercentageOrNumber) -> Self {
generic::SVGLength::Length(length) generic::SVGLength::Length(length)
} }
} }
/// A non-negative version of SVGLength.
pub type SVGWidth = generic::SVGLength<NonNegativeLengthOrPercentageOrNumber>;
impl Parse for SVGWidth {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
input.try(|i| NonNegativeLengthOrPercentageOrNumber::parse(context, i))
.map(Into::into)
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
}
}
impl From<NonNegativeLengthOrPercentageOrNumber> for SVGWidth {
fn from(length: NonNegativeLengthOrPercentageOrNumber) -> Self {
generic::SVGLength::Length(length)
}
}
/// [ <length> | <percentage> | <number> ]# | context-value /// [ <length> | <percentage> | <number> ]# | context-value
pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<LengthOrPercentageOrNumber>; pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeLengthOrPercentageOrNumber>;
impl Parse for SVGStrokeDashArray { impl Parse for SVGStrokeDashArray {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> { -> Result<Self, ParseError<'i>> {
if let Ok(values) = input.try(|i| CommaWithSpace::parse(i, |i| { if let Ok(values) = input.try(|i| CommaWithSpace::parse(i, |i| {
LengthOrPercentageOrNumber::parse_non_negative(context, i) NonNegativeLengthOrPercentageOrNumber::parse(context, i)
})) { })) {
Ok(generic::SVGStrokeDashArray::Values(values)) Ok(generic::SVGStrokeDashArray::Values(values))
} else if let Ok(_) = input.try(|i| i.expect_ident_matching("none")) { } else if let Ok(_) = input.try(|i| i.expect_ident_matching("none")) {

View file

@ -14,8 +14,9 @@ use values::computed::text::LineHeight as ComputedLineHeight;
use values::generics::text::InitialLetter as GenericInitialLetter; use values::generics::text::InitialLetter as GenericInitialLetter;
use values::generics::text::LineHeight as GenericLineHeight; use values::generics::text::LineHeight as GenericLineHeight;
use values::generics::text::Spacing; use values::generics::text::Spacing;
use values::specified::{AllowQuirks, Integer, Number}; use values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number};
use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength}; use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength};
use values::specified::length::NonNegativeLengthOrPercentage;
/// A specified type for the `initial-letter` property. /// A specified type for the `initial-letter` property.
pub type InitialLetter = GenericInitialLetter<Number, Integer>; pub type InitialLetter = GenericInitialLetter<Number, Integer>;
@ -27,7 +28,7 @@ pub type LetterSpacing = Spacing<Length>;
pub type WordSpacing = Spacing<LengthOrPercentage>; pub type WordSpacing = Spacing<LengthOrPercentage>;
/// A specified value for the `line-height` property. /// A specified value for the `line-height` property.
pub type LineHeight = GenericLineHeight<Number, LengthOrPercentage>; pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLengthOrPercentage>;
impl Parse for InitialLetter { impl Parse for InitialLetter {
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>> {
@ -58,11 +59,11 @@ impl Parse for WordSpacing {
impl Parse for LineHeight { impl Parse for LineHeight {
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>> {
if let Ok(number) = input.try(|i| Number::parse_non_negative(context, i)) { if let Ok(number) = input.try(|i| NonNegativeNumber::parse(context, i)) {
return Ok(GenericLineHeight::Number(number)) return Ok(GenericLineHeight::Number(number))
} }
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { if let Ok(nlop) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) {
return Ok(GenericLineHeight::Length(lop)) return Ok(GenericLineHeight::Length(nlop))
} }
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match ident { match ident {
@ -94,24 +95,29 @@ impl ToComputedValue for LineHeight {
GenericLineHeight::Number(number) => { GenericLineHeight::Number(number) => {
GenericLineHeight::Number(number.to_computed_value(context)) GenericLineHeight::Number(number.to_computed_value(context))
}, },
GenericLineHeight::Length(LengthOrPercentage::Length(ref length)) => { GenericLineHeight::Length(ref non_negative_lop) => {
GenericLineHeight::Length(context.maybe_zoom_text(length.to_computed_value(context))) let result = match non_negative_lop.0 {
}, LengthOrPercentage::Length(ref length) => {
GenericLineHeight::Length(LengthOrPercentage::Percentage(p)) => { context.maybe_zoom_text(length.to_computed_value(context).into())
let font_relative_length = },
Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(p.0))); LengthOrPercentage::Percentage(ref p) => {
GenericLineHeight::Length(font_relative_length.to_computed_value(context)) let font_relative_length =
}, Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(p.0)));
GenericLineHeight::Length(LengthOrPercentage::Calc(ref calc)) => { font_relative_length.to_computed_value(context).into()
let computed_calc = calc.to_computed_value_zoomed(context); }
let font_relative_length = LengthOrPercentage::Calc(ref calc) => {
Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(computed_calc.percentage()))); let computed_calc = calc.to_computed_value_zoomed(context);
let absolute_length = computed_calc.unclamped_length(); let font_relative_length =
let computed_length = computed_calc.clamping_mode.clamp( Length::NoCalc(NoCalcLength::FontRelative(
absolute_length + font_relative_length.to_computed_value(context) FontRelativeLength::Em(computed_calc.percentage())));
); let absolute_length = computed_calc.unclamped_length();
GenericLineHeight::Length(computed_length) computed_calc.clamping_mode.clamp(
}, absolute_length + font_relative_length.to_computed_value(context)
).into()
}
};
GenericLineHeight::Length(result)
}
} }
} }
@ -126,12 +132,10 @@ impl ToComputedValue for LineHeight {
GenericLineHeight::MozBlockHeight GenericLineHeight::MozBlockHeight
}, },
GenericLineHeight::Number(ref number) => { GenericLineHeight::Number(ref number) => {
GenericLineHeight::Number(Number::from_computed_value(number)) GenericLineHeight::Number(NonNegativeNumber::from_computed_value(number))
}, },
GenericLineHeight::Length(ref length) => { GenericLineHeight::Length(ref length) => {
GenericLineHeight::Length(LengthOrPercentage::Length( GenericLineHeight::Length(NoCalcLength::from_computed_value(&length.0).into())
NoCalcLength::from_computed_value(length)
))
} }
} }
} }

View file

@ -268,10 +268,12 @@ mod shorthand_serialization {
#[test] #[test]
fn padding_should_serialize_correctly() { fn padding_should_serialize_correctly() {
use style::values::specified::NonNegativeLengthOrPercentage;
let mut properties = Vec::new(); let mut properties = Vec::new();
let px_10 = LengthOrPercentage::Length(NoCalcLength::from_px(10f32)); let px_10: NonNegativeLengthOrPercentage = NoCalcLength::from_px(10f32).into();
let px_15 = LengthOrPercentage::Length(NoCalcLength::from_px(15f32)); let px_15: NonNegativeLengthOrPercentage = NoCalcLength::from_px(15f32).into();
properties.push(PropertyDeclaration::PaddingTop(px_10.clone())); properties.push(PropertyDeclaration::PaddingTop(px_10.clone()));
properties.push(PropertyDeclaration::PaddingRight(px_15.clone())); properties.push(PropertyDeclaration::PaddingRight(px_15.clone()));
properties.push(PropertyDeclaration::PaddingBottom(px_10)); properties.push(PropertyDeclaration::PaddingBottom(px_10));
@ -556,12 +558,12 @@ mod shorthand_serialization {
#[test] #[test]
fn flex_should_serialize_all_available_properties() { fn flex_should_serialize_all_available_properties() {
use style::values::specified::{Number, Percentage}; use style::values::specified::{NonNegativeNumber, Percentage};
let mut properties = Vec::new(); let mut properties = Vec::new();
let grow = Number::new(2f32); let grow = NonNegativeNumber::new(2f32);
let shrink = Number::new(3f32); let shrink = NonNegativeNumber::new(3f32);
let basis = let basis =
FlexBasis::Length(Percentage::new(0.5f32).into()); FlexBasis::Length(Percentage::new(0.5f32).into());
@ -1239,13 +1241,15 @@ mod shorthand_serialization {
#[test] #[test]
fn box_shadow_should_serialize_correctly() { fn box_shadow_should_serialize_correctly() {
use style::values::specified::length::NonNegativeLength;
let mut properties = Vec::new(); let mut properties = Vec::new();
let shadow_val = BoxShadow { let shadow_val = BoxShadow {
base: SimpleShadow { base: SimpleShadow {
color: None, color: None,
horizontal: Length::from_px(1f32), horizontal: Length::from_px(1f32),
vertical: Length::from_px(2f32), vertical: Length::from_px(2f32),
blur: Some(Length::from_px(3f32)), blur: Some(NonNegativeLength::from_px(3f32)),
}, },
spread: Some(Length::from_px(4f32)), spread: Some(Length::from_px(4f32)),
inset: false, inset: false,