Bug 1309165 - Implement text-overflow using nsstring bindings; r?heycam,mystor,emilio
MozReview-Commit-ID: BxoFVigIOyV
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -446,17 +446,17 @@ impl Debug for ${style_struct.gecko_stru
# Make a list of types we can't auto-generate.
#
force_stub = [];
# These are currently being shuffled to a different style struct on the gecko side.
force_stub += ["backface-visibility", "transform-box", "transform-style"]
# These live in an nsFont member in Gecko. Should be straightforward to do manually.
force_stub += ["font-kerning", "font-variant"]
# These have unusual representations in gecko.
- force_stub += ["list-style-type", "text-overflow"]
+ force_stub += ["list-style-type"]
# In a nsTArray, have to be done manually, but probably not too much work
# (the "filling them", not the "making them work")
force_stub += ["animation-name", "animation-duration",
"animation-timing-function", "animation-iteration-count",
"animation-direction", "animation-play-state",
"animation-fill-mode", "animation-delay"]
# These are part of shorthands so we must include them in stylo builds,
@@ -1629,17 +1629,17 @@ fn static_assert() {
}
}
<%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"></%call>
</%self:impl_trait>
<%self:impl_trait style_struct_name="Text"
- skip_longhands="text-decoration-color text-decoration-line"
+ skip_longhands="text-decoration-color text-decoration-line text-overflow"
skip_additionals="*">
${impl_color("text_decoration_color", "mTextDecorationColor", need_clone=True)}
pub fn set_text_decoration_line(&mut self, v: longhands::text_decoration_line::computed_value::T) {
let mut bits: u8 = 0;
if v.underline {
bits |= structs::NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE as u8;
@@ -1650,16 +1650,72 @@ fn static_assert() {
if v.line_through {
bits |= structs::NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH as u8;
}
self.gecko.mTextDecorationLine = bits;
}
${impl_simple_copy('text_decoration_line', 'mTextDecorationLine')}
+
+ fn clear_overflow_sides_if_string(&mut self) {
+ use gecko_bindings::structs::nsStyleTextOverflowSide;
+ use nsstring::nsString;
+ fn clear_if_string(side: &mut nsStyleTextOverflowSide) {
+ if side.mType == structs::NS_STYLE_TEXT_OVERFLOW_STRING as u8 {
+ side.mString.assign(&nsString::new());
+ side.mType = structs::NS_STYLE_TEXT_OVERFLOW_CLIP as u8;
+ }
+ }
+ clear_if_string(&mut self.gecko.mTextOverflow.mLeft);
+ clear_if_string(&mut self.gecko.mTextOverflow.mRight);
+ }
+ pub fn set_text_overflow(&mut self, v: longhands::text_overflow::computed_value::T) {
+ use gecko_bindings::structs::nsStyleTextOverflowSide;
+ use properties::longhands::text_overflow::{SpecifiedValue, Side};
+
+ fn set(side: &mut nsStyleTextOverflowSide, value: &Side) {
+ use nsstring::nsCString;
+ let ty = match *value {
+ Side::Clip => structs::NS_STYLE_TEXT_OVERFLOW_CLIP,
+ Side::Ellipsis => structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS,
+ Side::String(ref s) => {
+ side.mString.assign_utf8(&nsCString::from(&**s));
+ structs::NS_STYLE_TEXT_OVERFLOW_STRING
+ }
+ };
+ side.mType = ty as u8;
+ }
+
+ self.clear_overflow_sides_if_string();
+ if v.second.is_none() {
+ self.gecko.mTextOverflow.mLogicalDirections = true;
+ }
+
+ let SpecifiedValue { ref first, ref second } = v;
+ let second = second.as_ref().unwrap_or(&first);
+
+ set(&mut self.gecko.mTextOverflow.mLeft, first);
+ set(&mut self.gecko.mTextOverflow.mRight, second);
+ }
+
+ pub fn copy_text_overflow_from(&mut self, other: &Self) {
+ use gecko_bindings::structs::nsStyleTextOverflowSide;
+ fn set(side: &mut nsStyleTextOverflowSide, other: &nsStyleTextOverflowSide) {
+ if other.mType == structs::NS_STYLE_TEXT_OVERFLOW_STRING as u8 {
+ side.mString.assign(&other.mString)
+ }
+ side.mType = other.mType
+ }
+ self.clear_overflow_sides_if_string();
+ set(&mut self.gecko.mTextOverflow.mLeft, &other.gecko.mTextOverflow.mLeft);
+ set(&mut self.gecko.mTextOverflow.mRight, &other.gecko.mTextOverflow.mRight);
+ self.gecko.mTextOverflow.mLogicalDirections = other.gecko.mTextOverflow.mLogicalDirections;
+ }
+
#[inline]
pub fn has_underline(&self) -> bool {
(self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE as u8)) != 0
}
#[inline]
pub fn has_overline(&self) -> bool {
(self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_OVERLINE as u8)) != 0
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -7,17 +7,98 @@
<% data.new_style_struct("Text",
inherited=False,
gecko_name="TextReset",
additional_methods=[Method("has_underline", "bool"),
Method("has_overline", "bool"),
Method("has_line_through", "bool")]) %>
-${helpers.single_keyword("text-overflow", "clip ellipsis", animatable=False)}
+% if product == "servo":
+ ${helpers.single_keyword("text-overflow", "clip ellipsis", animatable=False)}
+% else:
+<%helpers:longhand name="text-overflow" animatable="False">
+ use cssparser::ToCss;
+ use std::fmt;
+ use values::computed::ComputedValueAsSpecified;
+ use values::NoViewportPercentage;
+
+ impl ComputedValueAsSpecified for SpecifiedValue {}
+ impl NoViewportPercentage for SpecifiedValue {}
+
+ #[derive(PartialEq, Eq, Clone, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ pub enum Side {
+ Clip,
+ Ellipsis,
+ String(String),
+ }
+
+ #[derive(PartialEq, Eq, Clone, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ pub struct SpecifiedValue {
+ pub first: Side,
+ pub second: Option<Side>
+ }
+
+ pub mod computed_value {
+ pub type T = super::SpecifiedValue;
+ }
+
+ #[inline]
+ pub fn get_initial_value() -> computed_value::T {
+ SpecifiedValue {
+ first: Side::Clip,
+ second: None
+ }
+ }
+ pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+ let first = try!(Side::parse(input));
+ let second = Side::parse(input).ok();
+ Ok(SpecifiedValue {
+ first: first,
+ second: second,
+ })
+ }
+ impl Parse for Side {
+ fn parse(input: &mut Parser) -> Result<Side, ()> {
+ if let Ok(ident) = input.try(|input| input.expect_ident()) {
+ match_ignore_ascii_case! { ident,
+ "clip" => Ok(Side::Clip),
+ "ellipsis" => Ok(Side::Ellipsis),
+ _ => Err(())
+ }
+ } else {
+ Ok(Side::String(try!(input.expect_string()).into_owned()))
+ }
+ }
+ }
+
+ impl ToCss for Side {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ Side::Clip => dest.write_str("clip"),
+ Side::Ellipsis => dest.write_str("ellipsis"),
+ Side::String(ref s) => dest.write_str(s)
+ }
+ }
+ }
+
+ impl ToCss for SpecifiedValue {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(self.first.to_css(dest));
+ if let Some(ref second) = self.second {
+ try!(dest.write_str(" "));
+ try!(second.to_css(dest));
+ }
+ Ok(())
+ }
+ }
+</%helpers:longhand>
+% endif
${helpers.single_keyword("unicode-bidi",
"normal embed isolate bidi-override isolate-override plaintext",
animatable=False)}
// FIXME: This prop should be animatable.
<%helpers:longhand name="${'text-decoration' if product == 'servo' else 'text-decoration-line'}"
custom_cascade="${product == 'servo'}"