diff options
-rw-r--r-- | components/layout/inline.rs | 9 | ||||
-rw-r--r-- | components/style/properties/gecko.mako.rs | 21 | ||||
-rw-r--r-- | components/style/properties/longhand/text.mako.rs | 127 | ||||
-rw-r--r-- | components/style/values/computed/mod.rs | 2 | ||||
-rw-r--r-- | components/style/values/computed/text.rs | 46 | ||||
-rw-r--r-- | components/style/values/specified/mod.rs | 2 | ||||
-rw-r--r-- | components/style/values/specified/text.rs | 90 |
7 files changed, 160 insertions, 137 deletions
diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 429ee7fc14e..afe770f06bb 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -33,9 +33,10 @@ use std::sync::Arc; use style::computed_values::{display, overflow_x, position, text_align, text_justify}; use style::computed_values::{vertical_align, white_space}; use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; -use style::properties::{longhands, ComputedValues}; +use style::properties::ComputedValues; use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT}; use style::values::generics::box_::VerticalAlign; +use style::values::specified::text::TextOverflowSide; use text; use traversal::PreorderFlowTraversal; use unicode_bidi as bidi; @@ -714,15 +715,15 @@ impl LineBreaker { let ellipsis = match (&fragment.style().get_text().text_overflow.second, fragment.style().get_box().overflow_x) { - (&longhands::text_overflow::Side::Clip, _) | (_, overflow_x::T::visible) => None, - (&longhands::text_overflow::Side::Ellipsis, _) => { + (&TextOverflowSide::Clip, _) | (_, overflow_x::T::visible) => None, + (&TextOverflowSide::Ellipsis, _) => { if fragment.margin_box_inline_size() > available_inline_size { Some("…".to_string()) } else { None } }, - (&longhands::text_overflow::Side::String(ref string), _) => { + (&TextOverflowSide::String(ref string), _) => { if fragment.margin_box_inline_size() > available_inline_size { Some(string.to_string()) } else { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index cb0866df0c4..a612a386ed0 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -4729,13 +4729,13 @@ fn static_assert() { pub fn set_text_overflow(&mut self, v: longhands::text_overflow::computed_value::T) { use gecko_bindings::structs::nsStyleTextOverflowSide; - use properties::longhands::text_overflow::Side; + use values::specified::text::TextOverflowSide; - fn set(side: &mut nsStyleTextOverflowSide, value: &Side) { + fn set(side: &mut nsStyleTextOverflowSide, value: &TextOverflowSide) { let ty = match *value { - Side::Clip => structs::NS_STYLE_TEXT_OVERFLOW_CLIP, - Side::Ellipsis => structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS, - Side::String(ref s) => { + TextOverflowSide::Clip => structs::NS_STYLE_TEXT_OVERFLOW_CLIP, + TextOverflowSide::Ellipsis => structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS, + TextOverflowSide::String(ref s) => { side.mString.assign_utf8(s); structs::NS_STYLE_TEXT_OVERFLOW_STRING } @@ -4770,13 +4770,14 @@ fn static_assert() { pub fn clone_text_overflow(&self) -> longhands::text_overflow::computed_value::T { use gecko_bindings::structs::nsStyleTextOverflowSide; - use properties::longhands::text_overflow::Side; + use values::specified::text::TextOverflowSide; - fn to_servo(side: &nsStyleTextOverflowSide) -> Side { + fn to_servo(side: &nsStyleTextOverflowSide) -> TextOverflowSide { match side.mType as u32 { - structs::NS_STYLE_TEXT_OVERFLOW_CLIP => Side::Clip, - structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS => Side::Ellipsis, - structs::NS_STYLE_TEXT_OVERFLOW_STRING => Side::String(side.mString.to_string().into_boxed_str()), + structs::NS_STYLE_TEXT_OVERFLOW_CLIP => TextOverflowSide::Clip, + structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS => TextOverflowSide::Ellipsis, + structs::NS_STYLE_TEXT_OVERFLOW_STRING => + TextOverflowSide::String(side.mString.to_string().into_boxed_str()), x => panic!("Found unexpected value in style struct for text_overflow property: {:?}", x), } } diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs index a88d5199797..798c098ea02 100644 --- a/components/style/properties/longhand/text.mako.rs +++ b/components/style/properties/longhand/text.mako.rs @@ -12,126 +12,13 @@ Method("has_overline", "bool"), Method("has_line_through", "bool")]) %> -<%helpers:longhand name="text-overflow" animation_value_type="discrete" boxed="True" - flags="APPLIES_TO_PLACEHOLDER" - spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow"> - use std::fmt; - use style_traits::ToCss; - - - #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] - pub enum Side { - Clip, - Ellipsis, - String(Box<str>), - } - - #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] - pub struct SpecifiedValue { - pub first: Side, - pub second: Option<Side> - } - - pub mod computed_value { - pub use super::Side; - - #[derive(Clone, Debug, MallocSizeOf, PartialEq)] - pub struct T { - // When the specified value only has one side, that's the "second" - // side, and the sides are logical, so "second" means "end". The - // start side is Clip in that case. - // - // When the specified value has two sides, those are our "first" - // and "second" sides, and they are physical sides ("left" and - // "right"). - pub first: Side, - pub second: Side, - pub sides_are_logical: bool - } - } - - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if self.sides_are_logical { - assert!(self.first == Side::Clip); - self.second.to_css(dest)?; - } else { - self.first.to_css(dest)?; - dest.write_str(" ")?; - self.second.to_css(dest)?; - } - Ok(()) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue { - if let Some(ref second) = self.second { - Self::ComputedValue { first: self.first.clone(), - second: second.clone(), - sides_are_logical: false } - } else { - Self::ComputedValue { first: Side::Clip, - second: self.first.clone(), - sides_are_logical: true } - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - if computed.sides_are_logical { - assert!(computed.first == Side::Clip); - SpecifiedValue { first: computed.second.clone(), - second: None } - } else { - SpecifiedValue { first: computed.first.clone(), - second: Some(computed.second.clone()) } - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T { - first: Side::Clip, - second: Side::Clip, - sides_are_logical: true, - } - } - pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result<SpecifiedValue, ParseError<'i>> { - let first = Side::parse(context, input)?; - let second = input.try(|input| Side::parse(context, input)).ok(); - Ok(SpecifiedValue { - first: first, - second: second, - }) - } - impl Parse for Side { - fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result<Side, ParseError<'i>> { - let location = input.current_source_location(); - match *input.next()? { - Token::Ident(ref ident) => { - match_ignore_ascii_case! { ident, - "clip" => Ok(Side::Clip), - "ellipsis" => Ok(Side::Ellipsis), - _ => Err(location.new_custom_error( - SelectorParseErrorKind::UnexpectedIdent(ident.clone()) - )) - } - } - Token::QuotedString(ref v) => { - Ok(Side::String(v.as_ref().to_owned().into_boxed_str())) - } - ref t => Err(location.new_unexpected_token_error(t.clone())), - } - } - } -</%helpers:longhand> +${helpers.predefined_type("text-overflow", + "TextOverflow", + "computed::TextOverflow::get_initial_value()", + animation_value_type="discrete", + boxed=True, + flags="APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow")} ${helpers.single_keyword("unicode-bidi", "normal embed isolate bidi-override isolate-override plaintext", diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 4a74cabf72c..94f9c4f4135 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -54,7 +54,7 @@ pub use self::percentage::Percentage; pub use self::position::Position; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth}; pub use self::table::XSpan; -pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; +pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextOverflow, WordSpacing}; pub use self::time::Time; pub use self::transform::{TimingFunction, TransformOrigin}; diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index ec55d27399b..4c724f7e418 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -4,6 +4,8 @@ //! Computed types for text properties. +use std::fmt; +use style_traits::ToCss; use values::{CSSInteger, CSSFloat}; use values::animated::ToAnimatedZero; use values::computed::{NonNegativeLength, NonNegativeNumber}; @@ -11,6 +13,7 @@ use values::computed::length::{Length, LengthOrPercentage}; use values::generics::text::InitialLetter as GenericInitialLetter; use values::generics::text::LineHeight as GenericLineHeight; use values::generics::text::Spacing; +use values::specified::text::TextOverflowSide; /// A computed value for the `initial-letter` property. pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>; @@ -28,3 +31,46 @@ impl ToAnimatedZero for LineHeight { #[inline] fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } } + +#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +/// text-overflow. +/// When the specified value only has one side, that's the "second" +/// side, and the sides are logical, so "second" means "end". The +/// start side is Clip in that case. +/// +/// When the specified value has two sides, those are our "first" +/// and "second" sides, and they are physical sides ("left" and +/// "right"). +pub struct TextOverflow { + /// First side + pub first: TextOverflowSide, + /// Second side + pub second: TextOverflowSide, + /// True if the specified value only has one side. + pub sides_are_logical: bool, +} + +impl TextOverflow { + /// Returns the initial `text-overflow` value + pub fn get_initial_value() -> TextOverflow { + TextOverflow { + first: TextOverflowSide::Clip, + second: TextOverflowSide::Clip, + sides_are_logical: true, + } + } +} + +impl ToCss for TextOverflow { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.sides_are_logical { + debug_assert!(self.first == TextOverflowSide::Clip); + self.second.to_css(dest)?; + } else { + self.first.to_css(dest)?; + dest.write_str(" ")?; + self.second.to_css(dest)?; + } + Ok(()) + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 2f01f66029e..7e12767db77 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -50,7 +50,7 @@ pub use self::percentage::Percentage; pub use self::position::{Position, PositionComponent}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth}; pub use self::table::XSpan; -pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; +pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextOverflow, WordSpacing}; pub use self::time::Time; pub use self::transform::{TimingFunction, TransformOrigin}; pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index ee39060b959..355cbc18960 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -4,13 +4,14 @@ //! Specified types for text properties. -use cssparser::Parser; +use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; use selectors::parser::SelectorParseErrorKind; use std::ascii::AsciiExt; use style_traits::ParseError; use values::computed::{Context, ToComputedValue}; use values::computed::text::LineHeight as ComputedLineHeight; +use values::computed::text::TextOverflow as ComputedTextOverflow; use values::generics::text::InitialLetter as GenericInitialLetter; use values::generics::text::LineHeight as GenericLineHeight; use values::generics::text::Spacing; @@ -154,3 +155,90 @@ impl ToComputedValue for LineHeight { } } } + +/// A generic value for the `text-overflow` property. +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] +pub enum TextOverflowSide { + /// Clip inline content. + Clip, + /// Render ellipsis to represent clipped inline content. + Ellipsis, + /// Render a given string to represent clipped inline content. + String(Box<str>), +} + +impl Parse for TextOverflowSide { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result<TextOverflowSide, ParseError<'i>> { + let location = input.current_source_location(); + match *input.next()? { + Token::Ident(ref ident) => { + match_ignore_ascii_case! { ident, + "clip" => Ok(TextOverflowSide::Clip), + "ellipsis" => Ok(TextOverflowSide::Ellipsis), + _ => Err(location.new_custom_error( + SelectorParseErrorKind::UnexpectedIdent(ident.clone()) + )) + } + } + Token::QuotedString(ref v) => { + Ok(TextOverflowSide::String(v.as_ref().to_owned().into_boxed_str())) + } + ref t => Err(location.new_unexpected_token_error(t.clone())), + } + } +} + +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] +/// text-overflow. Specifies rendering when inline content overflows its line box edge. +pub struct TextOverflow { + /// First value. Applies to end line box edge if no second is supplied; line-left edge otherwise. + pub first: TextOverflowSide, + /// Second value. Applies to the line-right edge if supplied. + pub second: Option<TextOverflowSide>, +} + +impl Parse for TextOverflow { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<TextOverflow, ParseError<'i>> { + let first = TextOverflowSide::parse(context, input)?; + let second = input.try(|input| TextOverflowSide::parse(context, input)).ok(); + Ok(TextOverflow { first, second }) + } +} + +impl ToComputedValue for TextOverflow { + type ComputedValue = ComputedTextOverflow; + + #[inline] + fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue { + if let Some(ref second) = self.second { + Self::ComputedValue { + first: self.first.clone(), + second: second.clone(), + sides_are_logical: false, + } + } else { + Self::ComputedValue { + first: TextOverflowSide::Clip, + second: self.first.clone(), + sides_are_logical: true, + } + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + if computed.sides_are_logical { + assert!(computed.first == TextOverflowSide::Clip); + TextOverflow { + first: computed.second.clone(), + second: None, + } + } else { + TextOverflow { + first: computed.first.clone(), + second: Some(computed.second.clone()), + } + } + } +} |