servo: Merge #13924 - implemented string-valued text-overflow (from cynicaldevil:text-overflow); r=emilio
authorNikhil Shagrithaya <nikhilshagri@gmail.com>
Wed, 09 Nov 2016 16:36:45 -0600
changeset 478286 a9cf0bb7f6e20c467f64cca06de75b034602244c
parent 478285 e39d52350b622ff39a858b5d01d41613d79534ea
child 478287 affcacf6944e87d46d480bcd0d55d488c5ae96e5
push id44079
push userbmo:gps@mozilla.com
push dateSat, 04 Feb 2017 00:14:49 +0000
reviewersemilio
servo: Merge #13924 - implemented string-valued text-overflow (from cynicaldevil:text-overflow); r=emilio <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #13709 <!-- Either: --> - [x] There are tests for these changes <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> cc @Manishearth The lorem-ipsum example from MDN works as expected. Source-Repo: https://github.com/servo/servo Source-Revision: a91f48ee05933784630fdf918fc4b66037dba9f1
servo/components/layout/fragment.rs
servo/components/layout/inline.rs
servo/components/style/properties/longhand/text.mako.rs
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -1032,22 +1032,25 @@ impl Fragment {
             split.range,
             size,
             insertion_point,
             flags);
         self.transform(size, SpecificFragmentInfo::ScannedText(info))
     }
 
     /// Transforms this fragment into an ellipsis fragment, preserving all the other data.
-    pub fn transform_into_ellipsis(&self, layout_context: &LayoutContext) -> Fragment {
+    pub fn transform_into_ellipsis(&self,
+                                   layout_context: &LayoutContext,
+                                   text_overflow_string: String)
+                                   -> Fragment {
         let mut unscanned_ellipsis_fragments = LinkedList::new();
         unscanned_ellipsis_fragments.push_back(self.transform(
                 self.border_box.size,
                 SpecificFragmentInfo::UnscannedText(
-                    box UnscannedTextFragmentInfo::new("…".to_owned(), None))));
+                    box UnscannedTextFragmentInfo::new(text_overflow_string, None))));
         let ellipsis_fragments = TextRunScanner::new().scan_for_runs(&mut layout_context.font_context(),
                                                                      unscanned_ellipsis_fragments);
         debug_assert!(ellipsis_fragments.len() == 1);
         ellipsis_fragments.fragments.into_iter().next().unwrap()
     }
 
     pub fn restyle_damage(&self) -> RestyleDamage {
         self.restyle_damage | self.specific.restyle_damage()
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -26,20 +26,20 @@ use model::IntrinsicISizesContribution;
 use range::{Range, RangeIndex};
 use script_layout_interface::wrapper_traits::PseudoElementType;
 use std::{fmt, i32, isize, mem};
 use std::cmp::max;
 use std::collections::VecDeque;
 use std::sync::Arc;
 use style::arc_ptr_eq;
 use style::computed_values::{display, overflow_x, position, text_align, text_justify};
-use style::computed_values::{text_overflow, vertical_align, white_space};
+use style::computed_values::{vertical_align, white_space};
 use style::context::{SharedStyleContext, StyleContext};
 use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
-use style::properties::ServoComputedValues;
+use style::properties::{longhands, ServoComputedValues};
 use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPOSITION, RESOLVE_GENERATED_CONTENT};
 use text;
 use unicode_bidi;
 
 /// `Line`s are represented as offsets into the child list, rather than
 /// as an object that "owns" fragments. Choosing a different set of line
 /// breaks requires a new list of offsets, and possibly some splitting and
 /// merging of TextFragments.
@@ -679,39 +679,50 @@ impl LineBreaker {
         let indentation = self.indentation_for_pending_fragment();
         if self.pending_line_is_empty() {
             debug_assert!(self.new_fragments.len() <= (isize::MAX as usize));
             self.pending_line.range.reset(FragmentIndex(self.new_fragments.len() as isize),
                                           FragmentIndex(0));
         }
 
         // Determine if an ellipsis will be necessary to account for `text-overflow`.
-        let mut need_ellipsis = false;
         let available_inline_size = self.pending_line.green_zone.inline -
             self.pending_line.bounds.size.inline - indentation;
-        match (fragment.style().get_text().text_overflow,
-               fragment.style().get_box().overflow_x) {
-            (text_overflow::T::clip, _) | (_, overflow_x::T::visible) => {}
-            (text_overflow::T::ellipsis, _) => {
-                need_ellipsis = fragment.margin_box_inline_size() > available_inline_size;
+
+        let ellipsis = match (&fragment.style().get_text().text_overflow.first,
+            fragment.style().get_box().overflow_x) {
+            (&longhands::text_overflow::Side::Clip, _) | (_, overflow_x::T::visible) => None,
+            (&longhands::text_overflow::Side::Ellipsis, _) => {
+                if fragment.margin_box_inline_size() > available_inline_size {
+                    Some("…".to_string())
+                } else {
+                    None
+                }
+            },
+            (&longhands::text_overflow::Side::String(ref string), _) => {
+                if fragment.margin_box_inline_size() > available_inline_size {
+                    Some(string.to_string())
+                } else {
+                    None
+                }
             }
-        }
+        };
 
-        if !need_ellipsis {
-            self.push_fragment_to_line_ignoring_text_overflow(fragment, layout_context);
-        } else {
-            let ellipsis = fragment.transform_into_ellipsis(layout_context);
+        if let Some(string) = ellipsis {
+            let ellipsis = fragment.transform_into_ellipsis(layout_context, string);
             if let Some(truncation_info) =
                     fragment.truncate_to_inline_size(available_inline_size -
                                                      ellipsis.margin_box_inline_size()) {
                 let fragment = fragment.transform_with_split_info(&truncation_info.split,
                                                                   truncation_info.text_run);
                 self.push_fragment_to_line_ignoring_text_overflow(fragment, layout_context);
             }
             self.push_fragment_to_line_ignoring_text_overflow(ellipsis, layout_context);
+        } else {
+            self.push_fragment_to_line_ignoring_text_overflow(fragment, layout_context);
         }
 
         if line_flush_mode == LineFlushMode::Flush {
             self.flush_current_line()
         }
     }
 
     /// Pushes a fragment to the current line unconditionally, without placing an ellipsis in the
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -7,19 +7,16 @@
 
 <% 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")]) %>
 
-% if product == "servo":
-    ${helpers.single_keyword("text-overflow", "clip ellipsis", animatable=False)}
-% else:
 <%helpers:longhand name="text-overflow" animatable="False">
     use std::fmt;
     use style_traits::ToCss;
     use values::NoViewportPercentage;
     use values::computed::ComputedValueAsSpecified;
 
     impl ComputedValueAsSpecified for SpecifiedValue {}
     impl NoViewportPercentage for SpecifiedValue {}
@@ -88,17 +85,16 @@
             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'}"