Auto merge of #17122 - servo:derive-all-the-things, r=emilio

Continue to slim down the code for CSS properties

<!-- 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/17122)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-06-02 01:53:55 -07:00 committed by GitHub
commit 028908ee26
26 changed files with 549 additions and 597 deletions

View file

@ -23,11 +23,12 @@ use std::borrow::ToOwned;
use std::collections::LinkedList;
use std::mem;
use std::sync::Arc;
use style::computed_values::{line_height, text_rendering, text_transform};
use style::computed_values::{text_rendering, text_transform};
use style::computed_values::{word_break, white_space};
use style::logical_geometry::{LogicalSize, WritingMode};
use style::properties::ServoComputedValues;
use style::properties::style_structs;
use style::values::generics::text::LineHeight;
use unicode_bidi as bidi;
use unicode_script::{Script, get_script};
@ -165,8 +166,8 @@ impl TextRunScanner {
white_space::T::pre_line => CompressionMode::CompressWhitespace,
};
text_transform = inherited_text_style.text_transform;
letter_spacing = inherited_text_style.letter_spacing.0;
word_spacing = inherited_text_style.word_spacing.0
letter_spacing = inherited_text_style.letter_spacing;
word_spacing = inherited_text_style.word_spacing.value()
.map(|lop| lop.to_hash_key())
.unwrap_or((Au(0), NotNaN::new(0.0).unwrap()));
text_rendering = inherited_text_style.text_rendering;
@ -288,8 +289,8 @@ impl TextRunScanner {
// example, `finally` with a wide `letter-spacing` renders as `f i n a l l y` and not
// `fi n a l l y`.
let mut flags = ShapingFlags::empty();
match letter_spacing {
Some(Au(0)) | None => {}
match letter_spacing.value() {
Some(&Au(0)) | None => {}
Some(_) => flags.insert(IGNORE_LIGATURES_SHAPING_FLAG),
}
if text_rendering == text_rendering::T::optimizespeed {
@ -300,7 +301,7 @@ impl TextRunScanner {
flags.insert(KEEP_ALL_FLAG);
}
let options = ShapingOptions {
letter_spacing: letter_spacing,
letter_spacing: letter_spacing.value().cloned(),
word_spacing: word_spacing,
script: Script::Common,
flags: flags,
@ -447,9 +448,9 @@ pub fn font_metrics_for_style(font_context: &mut FontContext, font_style: ::Styl
pub fn line_height_from_style(style: &ServoComputedValues, metrics: &FontMetrics) -> Au {
let font_size = style.get_font().font_size;
match style.get_inheritedtext().line_height {
line_height::T::Normal => metrics.line_gap,
line_height::T::Number(l) => font_size.scale_by(l),
line_height::T::Length(l) => l
LineHeight::Normal => metrics.line_gap,
LineHeight::Number(l) => font_size.scale_by(l),
LineHeight::Length(l) => l
}
}

View file

@ -646,7 +646,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
};
if let Some(border) = border {
let width_value = specified::BorderWidth::from_length(specified::Length::from_px(border as f32));
let width_value = specified::BorderSideWidth::Length(specified::Length::from_px(border as f32));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderTopWidth(width_value.clone())));

View file

@ -998,17 +998,17 @@ fn static_assert() {
}
pub fn set_border_image_width(&mut self, v: longhands::border_image_width::computed_value::T) {
use values::generics::border::BorderImageWidthSide;
use values::generics::border::BorderImageSideWidth;
% for side in SIDES:
match v.${side.index} {
BorderImageWidthSide::Auto => {
BorderImageSideWidth::Auto => {
self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Auto)
},
BorderImageWidthSide::Length(l) => {
BorderImageSideWidth::Length(l) => {
l.to_gecko_style_coord(&mut self.gecko.mBorderImageWidth.data_at_mut(${side.index}))
},
BorderImageWidthSide::Number(n) => {
BorderImageSideWidth::Number(n) => {
self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Factor(n))
},
}
@ -3637,65 +3637,64 @@ fn static_assert() {
}
pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {
use properties::longhands::line_height::computed_value::T;
use values::generics::text::LineHeight;
// FIXME: Align binary representations and ditch |match| for cast + static_asserts
let en = match v {
T::Normal => CoordDataValue::Normal,
T::Length(val) => CoordDataValue::Coord(val.0),
T::Number(val) => CoordDataValue::Factor(val),
T::MozBlockHeight =>
LineHeight::Normal => CoordDataValue::Normal,
LineHeight::Length(val) => CoordDataValue::Coord(val.0),
LineHeight::Number(val) => CoordDataValue::Factor(val),
LineHeight::MozBlockHeight =>
CoordDataValue::Enumerated(structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT),
};
self.gecko.mLineHeight.set_value(en);
}
pub fn clone_line_height(&self) -> longhands::line_height::computed_value::T {
use properties::longhands::line_height::computed_value::T;
use values::generics::text::LineHeight;
return match self.gecko.mLineHeight.as_value() {
CoordDataValue::Normal => T::Normal,
CoordDataValue::Coord(coord) => T::Length(Au(coord)),
CoordDataValue::Factor(n) => T::Number(n),
CoordDataValue::Normal => LineHeight::Normal,
CoordDataValue::Coord(coord) => LineHeight::Length(Au(coord)),
CoordDataValue::Factor(n) => LineHeight::Number(n),
CoordDataValue::Enumerated(val) if val == structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT =>
T::MozBlockHeight,
_ => {
debug_assert!(false);
T::MozBlockHeight
}
LineHeight::MozBlockHeight,
_ => panic!("this should not happen"),
}
}
<%call expr="impl_coord_copy('line_height', 'mLineHeight')"></%call>
pub fn set_letter_spacing(&mut self, v: longhands::letter_spacing::computed_value::T) {
match v.0 {
Some(au) => self.gecko.mLetterSpacing.set(au),
None => self.gecko.mLetterSpacing.set_value(CoordDataValue::Normal)
use values::generics::text::Spacing;
match v {
Spacing::Value(value) => self.gecko.mLetterSpacing.set(value),
Spacing::Normal => self.gecko.mLetterSpacing.set_value(CoordDataValue::Normal)
}
}
pub fn clone_letter_spacing(&self) -> longhands::letter_spacing::computed_value::T {
use properties::longhands::letter_spacing::computed_value::T;
use values::generics::text::Spacing;
debug_assert!(
matches!(self.gecko.mLetterSpacing.as_value(),
CoordDataValue::Normal |
CoordDataValue::Coord(_)),
"Unexpected computed value for letter-spacing");
T(Au::from_gecko_style_coord(&self.gecko.mLetterSpacing))
Au::from_gecko_style_coord(&self.gecko.mLetterSpacing).map_or(Spacing::Normal, Spacing::Value)
}
<%call expr="impl_coord_copy('letter_spacing', 'mLetterSpacing')"></%call>
pub fn set_word_spacing(&mut self, v: longhands::word_spacing::computed_value::T) {
match v.0 {
Some(lop) => self.gecko.mWordSpacing.set(lop),
use values::generics::text::Spacing;
match v {
Spacing::Value(lop) => self.gecko.mWordSpacing.set(lop),
// https://drafts.csswg.org/css-text-3/#valdef-word-spacing-normal
None => self.gecko.mWordSpacing.set_value(CoordDataValue::Coord(0)),
Spacing::Normal => self.gecko.mWordSpacing.set_value(CoordDataValue::Coord(0)),
}
}
pub fn clone_word_spacing(&self) -> longhands::word_spacing::computed_value::T {
use properties::longhands::word_spacing::computed_value::T;
use values::computed::LengthOrPercentage;
use values::generics::text::Spacing;
debug_assert!(
matches!(self.gecko.mWordSpacing.as_value(),
CoordDataValue::Normal |
@ -3703,7 +3702,7 @@ fn static_assert() {
CoordDataValue::Percent(_) |
CoordDataValue::Calc(_)),
"Unexpected computed value for word-spacing");
T(LengthOrPercentage::from_gecko_style_coord(&self.gecko.mWordSpacing))
LengthOrPercentage::from_gecko_style_coord(&self.gecko.mWordSpacing).map_or(Spacing::Normal, Spacing::Value)
}
<%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"></%call>

View file

@ -18,7 +18,6 @@ use properties::longhands;
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
use properties::longhands::font_weight::computed_value::T as FontWeight;
use properties::longhands::font_stretch::computed_value::T as FontStretch;
use properties::longhands::line_height::computed_value::T as LineHeight;
use properties::longhands::text_shadow::computed_value::T as TextShadowList;
use properties::longhands::text_shadow::computed_value::TextShadow;
use properties::longhands::box_shadow::computed_value::T as BoxShadowList;
@ -1300,43 +1299,6 @@ impl Animatable for MaxLength {
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
/// https://drafts.csswg.org/css-transitions/#animtype-length
impl Animatable for LineHeight {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(LineHeight::Length(ref this),
LineHeight::Length(ref other)) => {
this.add_weighted(other, self_portion, other_portion).map(LineHeight::Length)
}
(LineHeight::Number(ref this),
LineHeight::Number(ref other)) => {
this.add_weighted(other, self_portion, other_portion).map(LineHeight::Number)
}
(LineHeight::Normal, LineHeight::Normal) => {
Ok(LineHeight::Normal)
}
_ => Err(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
(LineHeight::Length(ref this),
LineHeight::Length(ref other)) => {
this.compute_distance(other)
},
(LineHeight::Number(ref this),
LineHeight::Number(ref other)) => {
this.compute_distance(other)
},
_ => Err(()),
}
}
}
/// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight
impl Animatable for FontWeight {
#[inline]

View file

@ -32,7 +32,9 @@
spec=maybe_logical_spec(side, "style"),
animation_value_type="none", logical=side[1])}
${helpers.predefined_type("border-%s-width" % side[0], "BorderWidth", "Au::from_px(3)",
${helpers.predefined_type("border-%s-width" % side[0],
"BorderSideWidth",
"Au::from_px(3)",
computed_type="::app_units::Au",
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
spec=maybe_logical_spec(side, "width"),
@ -287,8 +289,8 @@ ${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
</%helpers:longhand>
${helpers.predefined_type("border-image-width", "BorderImageWidth",
initial_value="computed::BorderImageWidthSide::one().into()",
initial_specified_value="specified::BorderImageWidthSide::one().into()",
initial_value="computed::BorderImageSideWidth::one().into()",
initial_specified_value="specified::BorderImageSideWidth::one().into()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
animation_value_type="none",
boxed=True)}

View file

@ -40,11 +40,15 @@ ${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")}
${helpers.predefined_type("column-rule-width", "BorderWidth", "Au::from_px(3)",
initial_specified_value="specified::BorderWidth::Medium",
products="gecko", computed_type="::app_units::Au",
${helpers.predefined_type("column-rule-width",
"BorderSideWidth",
"Au::from_px(3)",
initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::app_units::Au",
products="gecko",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width",
animation_value_type="ComputedValue", extra_prefixes="moz")}
animation_value_type="ComputedValue",
extra_prefixes="moz")}
// https://drafts.csswg.org/css-multicol-1/#crc
${helpers.predefined_type("column-rule-color", "CSSColor",

View file

@ -6,148 +6,11 @@
<% from data import Keyword %>
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>
<%helpers:longhand name="line-height" animation_value_type="ComputedValue"
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height">
use std::fmt;
use style_traits::ToCss;
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SpecifiedValue {
Normal,
% if product == "gecko":
MozBlockHeight,
% endif
Number(specified::Number),
LengthOrPercentage(specified::LengthOrPercentage),
}
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SpecifiedValue::Normal => dest.write_str("normal"),
% if product == "gecko":
SpecifiedValue::MozBlockHeight => dest.write_str("-moz-block-height"),
% endif
SpecifiedValue::LengthOrPercentage(ref value) => value.to_css(dest),
SpecifiedValue::Number(number) => number.to_css(dest),
}
}
}
/// normal | <number> | <length> | <percentage>
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
use cssparser::Token;
use std::ascii::AsciiExt;
// We try to parse as a Number first because, for 'line-height', we want
// "0" to be parsed as a plain Number rather than a Length (0px); this
// matches the behaviour of all major browsers
if let Ok(number) = input.try(|i| specified::Number::parse_non_negative(context, i)) {
return Ok(SpecifiedValue::Number(number))
}
if let Ok(lop) = input.try(|i| specified::LengthOrPercentage::parse_non_negative(context, i)) {
return Ok(SpecifiedValue::LengthOrPercentage(lop))
}
match try!(input.next()) {
Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => {
Ok(SpecifiedValue::Normal)
}
% if product == "gecko":
Token::Ident(ref value) if value.eq_ignore_ascii_case("-moz-block-height") => {
Ok(SpecifiedValue::MozBlockHeight)
}
% endif
_ => Err(()),
}
}
pub mod computed_value {
use app_units::Au;
use values::CSSFloat;
#[derive(PartialEq, Copy, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum T {
Normal,
% if product == "gecko":
MozBlockHeight,
% endif
Length(Au),
Number(CSSFloat),
}
}
impl ToCss for computed_value::T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
computed_value::T::Normal => dest.write_str("normal"),
% if product == "gecko":
computed_value::T::MozBlockHeight => dest.write_str("-moz-block-height"),
% endif
computed_value::T::Length(length) => length.to_css(dest),
computed_value::T::Number(number) => write!(dest, "{}", number),
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T { computed_value::T::Normal }
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue::Normal
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
match *self {
SpecifiedValue::Normal => computed_value::T::Normal,
% if product == "gecko":
SpecifiedValue::MozBlockHeight => computed_value::T::MozBlockHeight,
% endif
SpecifiedValue::Number(value) => computed_value::T::Number(value.to_computed_value(context)),
SpecifiedValue::LengthOrPercentage(ref value) => {
match *value {
specified::LengthOrPercentage::Length(ref value) =>
computed_value::T::Length(value.to_computed_value(context)),
specified::LengthOrPercentage::Percentage(specified::Percentage(value)) => {
let fr = specified::Length::NoCalc(specified::NoCalcLength::FontRelative(
specified::FontRelativeLength::Em(value)));
computed_value::T::Length(fr.to_computed_value(context))
},
specified::LengthOrPercentage::Calc(ref calc) => {
let calc = calc.to_computed_value(context);
let fr = specified::FontRelativeLength::Em(calc.percentage());
let fr = specified::Length::NoCalc(specified::NoCalcLength::FontRelative(fr));
let length = calc.unclamped_length();
computed_value::T::Length(calc.clamping_mode.clamp(length + fr.to_computed_value(context)))
}
}
}
}
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
match *computed {
computed_value::T::Normal => SpecifiedValue::Normal,
% if product == "gecko":
computed_value::T::MozBlockHeight => SpecifiedValue::MozBlockHeight,
% endif
computed_value::T::Number(ref value) => {
SpecifiedValue::Number(specified::Number::from_computed_value(value))
},
computed_value::T::Length(au) => {
SpecifiedValue::LengthOrPercentage(specified::LengthOrPercentage::Length(
ToComputedValue::from_computed_value(&au)
))
}
}
}
}
</%helpers:longhand>
${helpers.predefined_type("line-height",
"LineHeight",
"computed::LineHeight::normal()",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height")}
// CSS Text Module Level 3
@ -395,157 +258,17 @@ ${helpers.single_keyword("text-align-last",
% endif
</%helpers:longhand>
<%helpers:longhand name="letter-spacing" animation_value_type="ComputedValue"
spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing">
use std::fmt;
use style_traits::ToCss;
use values::specified::AllowQuirks;
${helpers.predefined_type("letter-spacing",
"LetterSpacing",
"computed::LetterSpacing::normal()",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing")}
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SpecifiedValue {
Normal,
Specified(specified::Length),
}
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SpecifiedValue::Normal => dest.write_str("normal"),
SpecifiedValue::Specified(ref l) => l.to_css(dest),
}
}
}
pub mod computed_value {
use app_units::Au;
use properties::animated_properties::Animatable;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Option<Au>);
${helpers.impl_animatable_for_option_tuple('Au(0)')}
}
impl ToCss for computed_value::T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.0 {
None => dest.write_str("normal"),
Some(l) => l.to_css(dest),
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T(None)
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
match *self {
SpecifiedValue::Normal => computed_value::T(None),
SpecifiedValue::Specified(ref l) =>
computed_value::T(Some(l.to_computed_value(context)))
}
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
computed.0.map(|ref au| {
SpecifiedValue::Specified(ToComputedValue::from_computed_value(au))
}).unwrap_or(SpecifiedValue::Normal)
}
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
Ok(SpecifiedValue::Normal)
} else {
specified::Length::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue::Specified)
}
}
</%helpers:longhand>
<%helpers:longhand name="word-spacing" animation_value_type="ComputedValue"
spec="https://drafts.csswg.org/css-text/#propdef-word-spacing">
use std::fmt;
use style_traits::ToCss;
use values::specified::AllowQuirks;
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SpecifiedValue {
Normal,
Specified(specified::LengthOrPercentage),
}
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
SpecifiedValue::Normal => dest.write_str("normal"),
SpecifiedValue::Specified(ref l) => l.to_css(dest),
}
}
}
pub mod computed_value {
use properties::animated_properties::Animatable;
use values::computed::LengthOrPercentage;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Option<LengthOrPercentage>);
${helpers.impl_animatable_for_option_tuple('LengthOrPercentage::zero()')}
}
impl ToCss for computed_value::T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.0 {
None => dest.write_str("normal"),
Some(l) => l.to_css(dest),
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T(None)
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
match *self {
SpecifiedValue::Normal => computed_value::T(None),
SpecifiedValue::Specified(ref l) =>
computed_value::T(Some(l.to_computed_value(context))),
}
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
computed.0.map(|ref lop| {
SpecifiedValue::Specified(ToComputedValue::from_computed_value(lop))
}).unwrap_or(SpecifiedValue::Normal)
}
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
Ok(SpecifiedValue::Normal)
} else {
specified::LengthOrPercentage::parse_quirky(context, input, AllowQuirks::Yes)
.map(SpecifiedValue::Specified)
}
}
</%helpers:longhand>
${helpers.predefined_type("word-spacing",
"WordSpacing",
"computed::WordSpacing::normal()",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-text/#propdef-word-spacing")}
<%helpers:longhand name="-servo-text-decorations-in-effect"
derived_from="display text-decoration"
@ -1149,13 +872,15 @@ ${helpers.predefined_type(
ignored_when_colors_disabled=True,
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")}
${helpers.predefined_type("-webkit-text-stroke-width", "BorderWidth", "Au::from_px(0)",
initial_specified_value="specified::BorderWidth::from_length(specified::Length::zero())",
computed_type="::app_units::Au", products="gecko",
${helpers.predefined_type("-webkit-text-stroke-width",
"BorderSideWidth",
"Au::from_px(0)",
initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
computed_type="::app_units::Au",
products="gecko",
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
animation_value_type="none")}
// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword("ruby-align", "space-around start center space-between",

View file

@ -61,50 +61,13 @@ ${helpers.predefined_type("outline-color", "CSSColor", "computed::CSSColor::Curr
}
</%helpers:longhand>
<%helpers:longhand name="outline-width" animation_value_type="ComputedValue"
spec="https://drafts.csswg.org/css-ui/#propdef-outline-width">
use std::fmt;
use style_traits::ToCss;
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.0.to_css(dest)
}
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
specified::parse_border_width(context, input).map(SpecifiedValue)
}
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedValue(pub specified::Length);
pub mod computed_value {
use app_units::Au;
pub type T = Au;
}
pub use super::border_top_width::get_initial_value;
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(specified::Length::NoCalc(specified::NoCalcLength::medium()))
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
self.0.to_computed_value(context)
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue(ToComputedValue::from_computed_value(computed))
}
}
</%helpers:longhand>
${helpers.predefined_type("outline-width",
"BorderSideWidth",
"Au::from_px(3)",
initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::app_units::Au",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-ui/#propdef-outline-width")}
// The -moz-outline-radius-* properties are non-standard and not on a standards track.
// TODO: Should they animate?

View file

@ -38,8 +38,9 @@ use shared_lock::StylesheetGuards;
use style_traits::{HasViewportPercentage, ToCss};
use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData};
#[cfg(feature = "servo")] use values::Either;
use values::specified::Color;
use values::generics::text::LineHeight;
use values::computed;
use values::specified::Color;
use cascade_info::CascadeInfo;
use rule_tree::{CascadeLevel, StrongRuleNode};
use style_adjuster::StyleAdjuster;
@ -1262,11 +1263,9 @@ impl PropertyDeclaration {
}
/// Is it the default value of line-height?
///
/// (using match because it generates less code than)
pub fn is_default_line_height(&self) -> bool {
match *self {
PropertyDeclaration::LineHeight(longhands::line_height::SpecifiedValue::Normal) => true,
PropertyDeclaration::LineHeight(LineHeight::Normal) => true,
_ => false
}
}

View file

@ -18,11 +18,11 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style",
for side in PHYSICAL_SIDES)}"
spec="https://drafts.csswg.org/css-backgrounds/#border-width">
use values::generics::rect::Rect;
use values::specified::{AllowQuirks, BorderWidth};
use values::specified::{AllowQuirks, BorderSideWidth};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let rect = Rect::parse_with(context, input, |_, i| {
BorderWidth::parse_quirky(context, i, AllowQuirks::Yes)
BorderSideWidth::parse_quirky(context, i, AllowQuirks::Yes)
})?;
Ok(expanded! {
border_top_width: rect.0,
@ -46,8 +46,8 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style",
pub fn parse_border(context: &ParserContext, input: &mut Parser)
-> Result<(specified::CSSColor,
specified::BorderStyle,
specified::BorderWidth), ()> {
use values::specified::{CSSColor, BorderStyle, BorderWidth};
specified::BorderSideWidth), ()> {
use values::specified::{CSSColor, BorderStyle, BorderSideWidth};
let _unused = context;
let mut color = None;
let mut style = None;
@ -69,7 +69,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
}
}
if width.is_none() {
if let Ok(value) = input.try(|i| BorderWidth::parse(context, i)) {
if let Ok(value) = input.try(|i| BorderSideWidth::parse(context, i)) {
width = Some(value);
any = true;
continue
@ -80,7 +80,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
if any {
Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
style.unwrap_or(BorderStyle::none),
width.unwrap_or(BorderWidth::Medium)))
width.unwrap_or(BorderSideWidth::Medium)))
} else {
Err(())
}

View file

@ -18,10 +18,12 @@
${'font-language-override' if product == 'gecko' or data.testing else ''}
${'font-feature-settings' if product == 'gecko' or data.testing else ''}"
spec="https://drafts.csswg.org/css-fonts-3/#propdef-font">
use parser::Parse;
use properties::longhands::{font_family, font_style, font_weight, font_stretch};
use properties::longhands::{font_size, line_height, font_variant_caps};
use properties::longhands::{font_size, font_variant_caps};
#[cfg(feature = "gecko")]
use properties::longhands::system_font::SystemFont;
use values::specified::text::LineHeight;
<%
gecko_sub_properties = "kerning language_override size_adjust \
@ -50,7 +52,7 @@
${name}: ${name}::SpecifiedValue::system_font(sys),
% endfor
// line-height is just reset to initial
line_height: line_height::get_initial_specified_value(),
line_height: LineHeight::normal(),
})
}
% endif
@ -98,7 +100,7 @@
return Err(())
}
let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
Some(try!(line_height::parse(context, input)))
Some(try!(LineHeight::parse(context, input)))
} else {
None
};
@ -107,7 +109,7 @@
% for name in "style weight stretch size variant_caps".split():
font_${name}: unwrap_or_initial!(font_${name}, ${name}),
% endfor
line_height: unwrap_or_initial!(line_height),
line_height: line_height.unwrap_or(LineHeight::normal()),
font_family: family,
% if product == "gecko" or data.testing:
% for name in gecko_sub_properties:
@ -169,13 +171,10 @@
self.font_size.to_css(dest)?;
match *self.line_height {
line_height::SpecifiedValue::Normal => {},
_ => {
if *self.line_height != LineHeight::normal() {
dest.write_str("/")?;
self.line_height.to_css(dest)?;
}
}
dest.write_str(" ")?;
self.font_family.to_css(dest)?;
@ -197,7 +196,7 @@
all = false;
}
% endfor
if self.line_height != &line_height::get_initial_specified_value() {
if self.line_height != &LineHeight::normal() {
all = false
}
if all {

View file

@ -7,16 +7,16 @@
use values::computed::{Number, NumberOrPercentage};
use values::computed::length::LengthOrPercentage;
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide;
use values::generics::border::BorderRadius as GenericBorderRadius;
use values::generics::rect::Rect;
/// A computed value for the `border-image-width` property.
pub type BorderImageWidth = Rect<BorderImageWidthSide>;
pub type BorderImageWidth = Rect<BorderImageSideWidth>;
/// A computed value for a single side of a `border-image-width` property.
pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>;
pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>;
/// A computed value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>;
@ -27,10 +27,10 @@ pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>;
/// A computed value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>;
impl BorderImageWidthSide {
impl BorderImageSideWidth {
/// Returns `1`.
#[inline]
pub fn one() -> Self {
GenericBorderImageWidthSide::Number(1.)
GenericBorderImageSideWidth::Number(1.)
}
}

View file

@ -222,6 +222,13 @@ pub enum LengthOrPercentage {
Calc(CalcLengthOrPercentage),
}
impl From<Au> for LengthOrPercentage {
#[inline]
fn from(length: Au) -> Self {
LengthOrPercentage::Length(length)
}
}
impl LengthOrPercentage {
#[inline]
#[allow(missing_docs)]

View file

@ -24,7 +24,7 @@ use super::specified;
pub use app_units::Au;
pub use cssparser::Color as CSSColor;
pub use self::background::BackgroundSize;
pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageWidthSide};
pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth};
pub use self::border::{BorderRadius, BorderCornerRadius};
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
pub use self::rect::LengthOrNumberRect;
@ -38,6 +38,7 @@ pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrP
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
pub use self::length::{MaxLength, MozLength};
pub use self::position::Position;
pub use self::text::{LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::TransformOrigin;
pub mod background;
@ -47,6 +48,7 @@ pub mod image;
pub mod length;
pub mod position;
pub mod rect;
pub mod text;
pub mod transform;
/// A `Context` is all the data a specified value could ever need to compute

View file

@ -0,0 +1,58 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Computed types for text properties.
use app_units::Au;
use properties::animated_properties::Animatable;
use values::CSSFloat;
use values::computed::length::{Length, LengthOrPercentage};
use values::generics::text::{LineHeight as GenericLineHeight, Spacing};
/// A computed value for the `letter-spacing` property.
pub type LetterSpacing = Spacing<Length>;
/// A computed value for the `word-spacing` property.
pub type WordSpacing = Spacing<LengthOrPercentage>;
/// A computed value for the `line-height` property.
pub type LineHeight = GenericLineHeight<CSSFloat, Au>;
impl Animatable for LineHeight {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(GenericLineHeight::Length(ref this), GenericLineHeight::Length(ref other)) => {
this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Length)
},
(GenericLineHeight::Number(ref this), GenericLineHeight::Number(ref other)) => {
this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Number)
},
(GenericLineHeight::Normal, GenericLineHeight::Normal) => {
Ok(GenericLineHeight::Normal)
},
#[cfg(feature = "gecko")]
(GenericLineHeight::MozBlockHeight, GenericLineHeight::MozBlockHeight) => {
Ok(GenericLineHeight::MozBlockHeight)
},
_ => Err(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
(GenericLineHeight::Length(ref this), GenericLineHeight::Length(ref other)) => {
this.compute_distance(other)
},
(GenericLineHeight::Number(ref this), GenericLineHeight::Number(ref other)) => {
this.compute_distance(other)
},
(GenericLineHeight::Normal, GenericLineHeight::Normal) => Ok(0.),
#[cfg(feature = "gecko")]
(GenericLineHeight::MozBlockHeight, GenericLineHeight::MozBlockHeight) => Ok(0.),
_ => Err(()),
}
}
}

View file

@ -12,7 +12,7 @@ use values::generics::rect::Rect;
/// A generic value for a single side of a `border-image-width` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
pub enum BorderImageWidthSide<LengthOrPercentage, Number> {
pub enum BorderImageSideWidth<LengthOrPercentage, Number> {
/// `<length-or-percentage>`
Length(LengthOrPercentage),
/// `<number>`
@ -52,16 +52,16 @@ pub struct BorderRadius<LengthOrPercentage> {
/// A generic value for `border-*-radius` longhand properties.
pub struct BorderCornerRadius<L>(pub Size2D<L>);
impl<L, N> ToCss for BorderImageWidthSide<L, N>
impl<L, N> ToCss for BorderImageSideWidth<L, N>
where L: ToCss, N: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write
{
match *self {
BorderImageWidthSide::Length(ref length) => length.to_css(dest),
BorderImageWidthSide::Number(ref number) => number.to_css(dest),
BorderImageWidthSide::Auto => dest.write_str("auto"),
BorderImageSideWidth::Length(ref length) => length.to_css(dest),
BorderImageSideWidth::Number(ref number) => number.to_css(dest),
BorderImageSideWidth::Auto => dest.write_str("auto"),
}
}
}

View file

@ -19,6 +19,7 @@ pub mod grid;
pub mod image;
pub mod position;
pub mod rect;
pub mod text;
pub mod transform;
// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type

View file

@ -0,0 +1,129 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Generic types for text properties.
use app_units::Au;
use cssparser::Parser;
use parser::ParserContext;
use properties::animated_properties::Animatable;
use std::fmt;
use style_traits::ToCss;
/// A generic spacing value for the `letter-spacing` and `word-spacing` properties.alloc
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
pub enum Spacing<Value> {
/// `normal`
Normal,
/// `<value>`
Value(Value),
}
impl<Value> Spacing<Value> {
/// Returns `normal`.
#[inline]
pub fn normal() -> Self {
Spacing::Normal
}
/// Parses.
#[inline]
pub fn parse_with<F>(
context: &ParserContext,
input: &mut Parser,
parse: F)
-> Result<Self, ()>
where F: FnOnce(&ParserContext, &mut Parser) -> Result<Value, ()>
{
if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
return Ok(Spacing::Normal);
}
parse(context, input).map(Spacing::Value)
}
/// Returns the spacing value, if not `normal`.
#[inline]
pub fn value(&self) -> Option<&Value> {
match *self {
Spacing::Normal => None,
Spacing::Value(ref value) => Some(value),
}
}
}
impl<Value> Animatable for Spacing<Value>
where Value: Animatable + From<Au>,
{
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
if let (&Spacing::Normal, &Spacing::Normal) = (self, other) {
return Ok(Spacing::Normal);
}
let zero = Value::from(Au(0));
let this = self.value().unwrap_or(&zero);
let other = other.value().unwrap_or(&zero);
this.add_weighted(other, self_portion, other_portion).map(Spacing::Value)
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
let zero = Value::from(Au(0));
let this = self.value().unwrap_or(&zero);
let other = other.value().unwrap_or(&zero);
this.compute_distance(other)
}
}
impl<Value> ToCss for Spacing<Value>
where Value: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write
{
match *self {
Spacing::Normal => dest.write_str("normal"),
Spacing::Value(ref value) => value.to_css(dest),
}
}
}
/// A generic value for the `line-height` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
pub enum LineHeight<Number, LengthOrPercentage> {
/// `normal`
Normal,
/// `-moz-block-height`
#[cfg(feature = "gecko")]
MozBlockHeight,
/// `<number>`
Number(Number),
/// `<length-or-percentage>`
Length(LengthOrPercentage),
}
impl<N, L> LineHeight<N, L> {
/// Returns `normal`.
#[inline]
pub fn normal() -> Self {
LineHeight::Normal
}
}
impl<N, L> ToCss for LineHeight<N, L>
where N: ToCss, L: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
match *self {
LineHeight::Normal => dest.write_str("normal"),
#[cfg(feature = "gecko")]
LineHeight::MozBlockHeight => dest.write_str("-moz-block-height"),
LineHeight::Number(ref number) => number.to_css(dest),
LineHeight::Length(ref value) => value.to_css(dest),
}
}
}

View file

@ -4,21 +4,39 @@
//! Specified types for CSS values related to borders.
use app_units::Au;
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
use values::computed::{Context, ToComputedValue};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide;
use values::generics::border::BorderRadius as GenericBorderRadius;
use values::generics::rect::Rect;
use values::specified::{Number, NumberOrPercentage};
use values::specified::length::LengthOrPercentage;
use values::specified::{AllowQuirks, Number, NumberOrPercentage};
use values::specified::length::{Length, LengthOrPercentage};
/// A specified value for a single side of the `border-width` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
pub enum BorderSideWidth {
/// `thin`
Thin,
/// `medium`
Medium,
/// `thick`
Thick,
/// `<length>`
Length(Length),
}
/// A specified value for the `border-image-width` property.
pub type BorderImageWidth = Rect<BorderImageWidthSide>;
pub type BorderImageWidth = Rect<BorderImageSideWidth>;
/// A specified value for a single side of a `border-image-width` property.
pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>;
pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>;
/// A specified value for the `border-image-slice` property.
pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>;
@ -29,26 +47,85 @@ pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>;
/// A specified value for the `border-*-radius` longhand properties.
pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>;
impl BorderImageWidthSide {
/// Returns `1`.
#[inline]
pub fn one() -> Self {
GenericBorderImageWidthSide::Number(Number::new(1.))
impl BorderSideWidth {
/// Parses, with quirks.
pub fn parse_quirky(
context: &ParserContext,
input: &mut Parser,
allow_quirks: AllowQuirks)
-> Result<Self, ()>
{
if let Ok(length) = input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) {
return Ok(BorderSideWidth::Length(length));
}
match_ignore_ascii_case! { &input.expect_ident()?,
"thin" => Ok(BorderSideWidth::Thin),
"medium" => Ok(BorderSideWidth::Medium),
"thick" => Ok(BorderSideWidth::Thick),
_ => Err(())
}
}
}
impl Parse for BorderImageWidthSide {
impl Parse for BorderSideWidth {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Self::parse_quirky(context, input, AllowQuirks::No)
}
}
impl ToCss for BorderSideWidth {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
BorderSideWidth::Thin => dest.write_str("thin"),
BorderSideWidth::Medium => dest.write_str("medium"),
BorderSideWidth::Thick => dest.write_str("thick"),
BorderSideWidth::Length(ref length) => length.to_css(dest)
}
}
}
impl ToComputedValue for BorderSideWidth {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
// We choose the pixel length of the keyword values the same as both spec and gecko.
// Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
// Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
match *self {
BorderSideWidth::Thin => Length::from_px(1.).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::Length(ref length) => length.to_computed_value(context)
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
BorderSideWidth::Length(ToComputedValue::from_computed_value(computed))
}
}
impl BorderImageSideWidth {
/// Returns `1`.
#[inline]
pub fn one() -> Self {
GenericBorderImageSideWidth::Number(Number::new(1.))
}
}
impl Parse for BorderImageSideWidth {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(GenericBorderImageWidthSide::Auto);
return Ok(GenericBorderImageSideWidth::Auto);
}
if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
return Ok(GenericBorderImageWidthSide::Length(len));
return Ok(GenericBorderImageSideWidth::Length(len));
}
let num = Number::parse_non_negative(context, input)?;
Ok(GenericBorderImageWidthSide::Number(num))
Ok(GenericBorderImageSideWidth::Number(num))
}
}

View file

@ -7,7 +7,6 @@
//! TODO(emilio): Enhance docs.
use Namespace;
use app_units::Au;
use context::QuirksMode;
use cssparser::{self, Parser, Token, serialize_identifier};
use itoa;
@ -32,7 +31,7 @@ use values::specified::calc::CalcNode;
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use self::background::BackgroundSize;
pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth};
pub use self::border::{BorderImageWidthSide, BorderRadius};
pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth};
pub use self::color::Color;
pub use self::rect::LengthOrNumberRect;
pub use super::generics::grid::GridLine;
@ -44,6 +43,7 @@ pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercent
pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength};
pub use self::length::{MaxLength, MozLength};
pub use self::position::{Position, PositionComponent};
pub use self::text::{LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::TransformOrigin;
#[cfg(feature = "gecko")]
@ -58,6 +58,7 @@ pub mod image;
pub mod length;
pub mod position;
pub mod rect;
pub mod text;
pub mod transform;
/// Common handling for the specified value CSS url() values.
@ -432,92 +433,6 @@ impl Angle {
}
}
#[allow(missing_docs)]
pub fn parse_border_width(context: &ParserContext, input: &mut Parser) -> Result<Length, ()> {
input.try(|i| Length::parse_non_negative(context, i)).or_else(|()| {
match_ignore_ascii_case! { &try!(input.expect_ident()),
"thin" => Ok(Length::from_px(1.)),
"medium" => Ok(Length::from_px(3.)),
"thick" => Ok(Length::from_px(5.)),
_ => Err(())
}
})
}
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum BorderWidth {
Thin,
Medium,
Thick,
Width(Length),
}
impl Parse for BorderWidth {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<BorderWidth, ()> {
Self::parse_quirky(context, input, AllowQuirks::No)
}
}
impl BorderWidth {
/// Parses a border width, allowing quirks.
pub fn parse_quirky(context: &ParserContext,
input: &mut Parser,
allow_quirks: AllowQuirks)
-> Result<BorderWidth, ()> {
match input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) {
Ok(length) => Ok(BorderWidth::Width(length)),
Err(_) => match_ignore_ascii_case! { &try!(input.expect_ident()),
"thin" => Ok(BorderWidth::Thin),
"medium" => Ok(BorderWidth::Medium),
"thick" => Ok(BorderWidth::Thick),
_ => Err(())
}
}
}
}
impl BorderWidth {
#[allow(missing_docs)]
pub fn from_length(length: Length) -> Self {
BorderWidth::Width(length)
}
}
impl ToCss for BorderWidth {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
BorderWidth::Thin => dest.write_str("thin"),
BorderWidth::Medium => dest.write_str("medium"),
BorderWidth::Thick => dest.write_str("thick"),
BorderWidth::Width(ref length) => length.to_css(dest)
}
}
}
impl ToComputedValue for BorderWidth {
type ComputedValue = Au;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
// We choose the pixel length of the keyword values the same as both spec and gecko.
// Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
// Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
match *self {
BorderWidth::Thin => Length::from_px(1.).to_computed_value(context),
BorderWidth::Medium => Length::from_px(3.).to_computed_value(context),
BorderWidth::Thick => Length::from_px(5.).to_computed_value(context),
BorderWidth::Width(ref length) => length.to_computed_value(context)
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
BorderWidth::Width(ToComputedValue::from_computed_value(computed))
}
}
// The integer values here correspond to the border conflict resolution rules in CSS 2.1 §
// 17.6.2.1. Higher values override lower values.
define_numbered_css_keyword_enum! { BorderStyle:

View file

@ -0,0 +1,119 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Specified types for text properties.
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use values::computed::{Context, ToComputedValue};
use values::computed::text::LineHeight as ComputedLineHeight;
use values::generics::text::{LineHeight as GenericLineHeight, Spacing};
use values::specified::{AllowQuirks, Number};
use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength};
/// A specified value for the `letter-spacing` property.
pub type LetterSpacing = Spacing<Length>;
/// A specified value for the `word-spacing` property.
pub type WordSpacing = Spacing<LengthOrPercentage>;
/// A specified value for the `line-height` property.
pub type LineHeight = GenericLineHeight<Number, LengthOrPercentage>;
impl Parse for LetterSpacing {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Spacing::parse_with(context, input, |c, i| {
Length::parse_quirky(c, i, AllowQuirks::Yes)
})
}
}
impl Parse for WordSpacing {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Spacing::parse_with(context, input, |c, i| {
LengthOrPercentage::parse_quirky(c, i, AllowQuirks::Yes)
})
}
}
impl Parse for LineHeight {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(number) = input.try(|i| Number::parse_non_negative(context, i)) {
return Ok(GenericLineHeight::Number(number))
}
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
return Ok(GenericLineHeight::Length(lop))
}
match &input.expect_ident()? {
ident if ident.eq_ignore_ascii_case("normal") => {
Ok(GenericLineHeight::Normal)
},
#[cfg(feature = "gecko")]
ident if ident.eq_ignore_ascii_case("-moz-block-height") => {
Ok(GenericLineHeight::MozBlockHeight)
},
_ => Err(()),
}
}
}
impl ToComputedValue for LineHeight {
type ComputedValue = ComputedLineHeight;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
GenericLineHeight::Normal => {
GenericLineHeight::Normal
},
#[cfg(feature = "gecko")]
GenericLineHeight::MozBlockHeight => {
GenericLineHeight::MozBlockHeight
},
GenericLineHeight::Number(number) => {
GenericLineHeight::Number(number.to_computed_value(context))
},
GenericLineHeight::Length(LengthOrPercentage::Length(ref length)) => {
GenericLineHeight::Length(length.to_computed_value(context))
},
GenericLineHeight::Length(LengthOrPercentage::Percentage(p)) => {
let font_relative_length =
Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(p.0)));
GenericLineHeight::Length(font_relative_length.to_computed_value(context))
},
GenericLineHeight::Length(LengthOrPercentage::Calc(ref calc)) => {
let computed_calc = calc.to_computed_value(context);
let font_relative_length =
Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(computed_calc.percentage())));
let absolute_length = computed_calc.unclamped_length();
let computed_length = computed_calc.clamping_mode.clamp(
absolute_length + font_relative_length.to_computed_value(context)
);
GenericLineHeight::Length(computed_length)
},
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
GenericLineHeight::Normal => {
GenericLineHeight::Normal
},
#[cfg(feature = "gecko")]
GenericLineHeight::MozBlockHeight => {
GenericLineHeight::MozBlockHeight
},
GenericLineHeight::Number(ref number) => {
GenericLineHeight::Number(Number::from_computed_value(number))
},
GenericLineHeight::Length(ref length) => {
GenericLineHeight::Length(LengthOrPercentage::Length(
NoCalcLength::from_computed_value(length)
))
}
}
}
}

View file

@ -1946,7 +1946,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
use style::properties::longhands::height::SpecifiedValue as Height;
use style::properties::longhands::width::SpecifiedValue as Width;
use style::values::specified::BorderWidth;
use style::values::specified::BorderSideWidth;
use style::values::specified::MozLength;
use style::values::specified::length::{NoCalcLength, LengthOrPercentage};
@ -1956,10 +1956,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
let prop = match_wrap_declared! { long,
Height => Height(MozLength::LengthOrPercentageOrAuto(nocalc.into())),
Width => Width(MozLength::LengthOrPercentageOrAuto(nocalc.into())),
BorderTopWidth => BorderWidth::Width(nocalc.into()),
BorderRightWidth => BorderWidth::Width(nocalc.into()),
BorderBottomWidth => BorderWidth::Width(nocalc.into()),
BorderLeftWidth => BorderWidth::Width(nocalc.into()),
BorderTopWidth => BorderSideWidth::Length(nocalc.into()),
BorderRightWidth => BorderSideWidth::Length(nocalc.into()),
BorderBottomWidth => BorderSideWidth::Length(nocalc.into()),
BorderLeftWidth => BorderSideWidth::Length(nocalc.into()),
MarginTop => nocalc.into(),
MarginRight => nocalc.into(),
MarginBottom => nocalc.into(),

View file

@ -3,27 +3,27 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use parsing::parse;
use style::values::generics::text::Spacing;
#[test]
fn negative_letter_spacing_should_parse_properly() {
use style::properties::longhands::letter_spacing;
use style::properties::longhands::letter_spacing::SpecifiedValue;
use style::values::specified::length::{Length, NoCalcLength, FontRelativeLength};
let negative_value = parse_longhand!(letter_spacing, "-0.5em");
let expected = SpecifiedValue::Specified(Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(-0.5))));
let expected = Spacing::Value(Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(-0.5))));
assert_eq!(negative_value, expected);
}
#[test]
fn negative_word_spacing_should_parse_properly() {
use style::properties::longhands::word_spacing;
use style::properties::longhands::word_spacing::SpecifiedValue;
use style::values::specified::length::{NoCalcLength, LengthOrPercentage, FontRelativeLength};
let negative_value = parse_longhand!(word_spacing, "-0.5em");
let expected = SpecifiedValue::Specified(LengthOrPercentage::Length(NoCalcLength::FontRelative(
FontRelativeLength::Em(-0.5))));
let expected = Spacing::Value(LengthOrPercentage::Length(
NoCalcLength::FontRelative(FontRelativeLength::Em(-0.5))
));
assert_eq!(negative_value, expected);
}

View file

@ -9,7 +9,7 @@ use style::properties::longhands::outline_color::computed_value::T as ComputedCo
use style::properties::parse_property_declaration_list;
use style::values::{RGBA, Auto};
use style::values::CustomIdent;
use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length, LengthOrPercentage};
use style::values::specified::{BorderStyle, BorderSideWidth, CSSColor, Length, LengthOrPercentage};
use style::values::specified::{LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
use style::values::specified::{NoCalcLength, PositionComponent};
use style::values::specified::position::Y;
@ -221,8 +221,8 @@ mod shorthand_serialization {
properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone()));
let px_30 = BorderWidth::from_length(Length::from_px(30f32));
let px_10 = BorderWidth::from_length(Length::from_px(10f32));
let px_30 = BorderSideWidth::Length(Length::from_px(30f32));
let px_10 = BorderSideWidth::Length(Length::from_px(10f32));
properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
@ -255,7 +255,7 @@ mod shorthand_serialization {
properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone()));
properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone()));
let px_30 = BorderWidth::from_length(Length::from_px(30f32));
let px_30 = BorderSideWidth::Length(Length::from_px(30f32));
properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
@ -295,11 +295,11 @@ mod shorthand_serialization {
fn border_width_should_serialize_correctly() {
let mut properties = Vec::new();
let top_px = BorderWidth::from_length(Length::from_px(10f32));
let bottom_px = BorderWidth::from_length(Length::from_px(10f32));
let top_px = BorderSideWidth::Length(Length::from_px(10f32));
let bottom_px = BorderSideWidth::Length(Length::from_px(10f32));
let right_px = BorderWidth::from_length(Length::from_px(15f32));
let left_px = BorderWidth::from_length(Length::from_px(15f32));
let right_px = BorderSideWidth::Length(Length::from_px(15f32));
let left_px = BorderSideWidth::Length(Length::from_px(15f32));
properties.push(PropertyDeclaration::BorderTopWidth(top_px));
properties.push(PropertyDeclaration::BorderRightWidth(right_px));
@ -314,10 +314,10 @@ mod shorthand_serialization {
fn border_width_with_keywords_should_serialize_correctly() {
let mut properties = Vec::new();
let top_px = BorderWidth::Thin;
let right_px = BorderWidth::Medium;
let bottom_px = BorderWidth::Thick;
let left_px = BorderWidth::from_length(Length::from_px(15f32));
let top_px = BorderSideWidth::Thin;
let right_px = BorderSideWidth::Medium;
let bottom_px = BorderSideWidth::Thick;
let left_px = BorderSideWidth::Length(Length::from_px(15f32));
properties.push(PropertyDeclaration::BorderTopWidth(top_px));
properties.push(PropertyDeclaration::BorderRightWidth(right_px));
@ -403,7 +403,7 @@ mod shorthand_serialization {
fn directional_border_should_show_all_properties_when_values_are_set() {
let mut properties = Vec::new();
let width = BorderWidth::from_length(Length::from_px(4f32));
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = BorderStyle::solid;
let color = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
@ -418,8 +418,8 @@ mod shorthand_serialization {
assert_eq!(serialization, "border-top: 4px solid rgb(255, 0, 0);");
}
fn get_border_property_values() -> (BorderWidth, BorderStyle, CSSColor) {
(BorderWidth::from_length(Length::from_px(4f32)),
fn get_border_property_values() -> (BorderSideWidth, BorderStyle, CSSColor) {
(BorderSideWidth::Length(Length::from_px(4f32)),
BorderStyle::solid,
CSSColor::currentcolor())
}
@ -523,7 +523,6 @@ mod shorthand_serialization {
}
mod outline {
use style::properties::longhands::outline_width::SpecifiedValue as WidthContainer;
use style::values::Either;
use super::*;
@ -531,7 +530,7 @@ mod shorthand_serialization {
fn outline_should_show_all_properties_when_set() {
let mut properties = Vec::new();
let width = WidthContainer(Length::from_px(4f32));
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = Either::Second(BorderStyle::solid);
let color = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
@ -550,7 +549,7 @@ mod shorthand_serialization {
fn outline_should_serialize_correctly_when_style_is_auto() {
let mut properties = Vec::new();
let width = WidthContainer(Length::from_px(4f32));
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = Either::First(Auto);
let color = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),

View file

@ -4,22 +4,22 @@
use app_units::Au;
use style::properties::PropertyDeclaration;
use style::properties::longhands::border_top_width;
use style::values::specified::{AbsoluteLength, Length, NoCalcLength, ViewportPercentageLength};
use style::values::specified::border::BorderSideWidth;
use style_traits::HasViewportPercentage;
#[test]
fn has_viewport_percentage_for_specified_value() {
//TODO: test all specified value with a HasViewportPercentage impl
let pvw = PropertyDeclaration::BorderTopWidth(
border_top_width::SpecifiedValue::from_length(
BorderSideWidth::Length(
Length::NoCalc(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(100.)))
)
);
assert!(pvw.has_viewport_percentage());
let pabs = PropertyDeclaration::BorderTopWidth(
border_top_width::SpecifiedValue::from_length(
BorderSideWidth::Length(
Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(Au(100).to_f32_px())))
)
);

View file

@ -45,15 +45,6 @@
[outline-color: invert]
expected: FAIL
[outline-width: thin]
expected: FAIL
[outline-width: medium]
expected: FAIL
[outline-width: thick]
expected: FAIL
[page-break-after: auto]
expected: FAIL