Bug 1309165 - Implement text-overflow using nsstring bindings; r?heycam,mystor,emilio draft
authorManish Goregaokar <manishsmail@gmail.com>
Tue, 11 Oct 2016 15:18:07 +0530
changeset 423778 3747fe40022adce88b85984325b7ccceac915653
parent 423761 db29a8f683985e19c55429e67e7c7af8df186db2
child 533518 1b646fff97d41aad02362cc254b21155097e796d
push id31983
push userbmo:manishearth@gmail.com
push dateTue, 11 Oct 2016 16:43:08 +0000
reviewersheycam, mystor, emilio
bugs1309165
milestone52.0a1
Bug 1309165 - Implement text-overflow using nsstring bindings; r?heycam,mystor,emilio MozReview-Commit-ID: BxoFVigIOyV
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/text.mako.rs
--- 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'}"