diff --git a/components/gfx/font.rs b/components/gfx/font.rs index 7e1cf5236d5..c955c042eff 100644 --- a/components/gfx/font.rs +++ b/components/gfx/font.rs @@ -148,6 +148,8 @@ bitflags! { const DISABLE_KERNING_SHAPING_FLAG = 0x04, #[doc = "Text direction is right-to-left."] const RTL_FLAG = 0x08, + #[doc = "Set if word-break is set to keep-all."] + const KEEP_ALL_FLAG = 0x10, } } diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs index a431a124239..7ab8f4a870f 100644 --- a/components/gfx/text/text_run.rs +++ b/components/gfx/text/text_run.rs @@ -3,8 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, RunMetrics}; -use font::ShapingOptions; +use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, KEEP_ALL_FLAG}; +use font::{RunMetrics, ShapingOptions}; use platform::font_template::FontTemplateData; use range::Range; use std::cell::Cell; @@ -206,11 +206,14 @@ impl<'a> TextRun { // Split off any trailing whitespace into a separate glyph run. let mut whitespace = slice.end..slice.end; if let Some((i, _)) = word.char_indices().rev() - .take_while(|&(_, c)| char_is_whitespace(c)).last() { - whitespace.start = slice.start + i; - slice.end = whitespace.start; - } - + .take_while(|&(_, c)| char_is_whitespace(c)).last() { + whitespace.start = slice.start + i; + slice.end = whitespace.start; + } else if idx != text.len() && options.flags.contains(KEEP_ALL_FLAG) { + // If there's no whitespace and word-break is set to + // keep-all, try increasing the slice. + continue; + } if slice.len() > 0 { glyphs.push(GlyphRun { glyph_store: font.shape_text(&text[slice.clone()], options), diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 5245e821711..f7f46d2fdcc 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -1637,8 +1637,8 @@ impl Fragment { } match self.style().get_inheritedtext().word_break { - word_break::T::normal => { - // Break at normal word boundaries. + word_break::T::normal | word_break::T::keep_all => { + // Break at normal word boundaries. keep-all forbids soft wrap opportunities. let natural_word_breaking_strategy = text_fragment_info.run.natural_word_slices_in_range(&text_fragment_info.range); self.calculate_split_position_using_breaking_strategy( diff --git a/components/layout/text.rs b/components/layout/text.rs index 18d2cbf3c08..237f339ea71 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -10,7 +10,7 @@ use app_units::Au; use fragment::{Fragment, REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES, ScannedTextFlags}; use fragment::{SELECTED, ScannedTextFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; use gfx::font::{DISABLE_KERNING_SHAPING_FLAG, FontMetrics, IGNORE_LIGATURES_SHAPING_FLAG}; -use gfx::font::{RTL_FLAG, RunMetrics, ShapingFlags, ShapingOptions}; +use gfx::font::{KEEP_ALL_FLAG, RTL_FLAG, RunMetrics, ShapingFlags, ShapingOptions}; use gfx::font_context::FontContext; use gfx::text::glyph::ByteIndex; use gfx::text::text_run::TextRun; @@ -24,7 +24,7 @@ use std::collections::LinkedList; use std::mem; use std::sync::Arc; use style::computed_values::{line_height, text_orientation, text_rendering, text_transform}; -use style::computed_values::white_space; +use style::computed_values::{word_break, white_space}; use style::logical_geometry::{LogicalSize, WritingMode}; use style::properties::ServoComputedValues; use style::properties::style_structs; @@ -151,6 +151,7 @@ impl TextRunScanner { let letter_spacing; let word_spacing; let text_rendering; + let word_break; { let in_fragment = self.clump.front().unwrap(); let font_style = in_fragment.style().get_font_arc(); @@ -169,6 +170,7 @@ impl TextRunScanner { .map(|lop| lop.to_hash_key()) .unwrap_or((Au(0), NotNaN::new(0.0).unwrap())); text_rendering = inherited_text_style.text_rendering; + word_break = inherited_text_style.word_break; } // First, transform/compress text of all the nodes. @@ -289,6 +291,9 @@ impl TextRunScanner { flags.insert(IGNORE_LIGATURES_SHAPING_FLAG); flags.insert(DISABLE_KERNING_SHAPING_FLAG) } + if word_break == word_break::T::keep_all { + flags.insert(KEEP_ALL_FLAG); + } let options = ShapingOptions { letter_spacing: letter_spacing, word_spacing: word_spacing, diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index b2f856059bb..5251f4a8a74 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -385,8 +385,7 @@ ${helpers.single_keyword("overflow-wrap", // TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support. ${helpers.single_keyword("word-break", - "normal break-all", - extra_gecko_values="keep-all", + "normal break-all keep-all", gecko_constant_prefix="NS_STYLE_WORDBREAK", animatable=False)} diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 2e5a102e350..a0eed70e959 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -5970,6 +5970,54 @@ "url": "/_mozilla/css/width_nonreplaced_block_simple_a.html" } ], + "css/word-break-keep-all-005.htm": [ + { + "path": "css/word-break-keep-all-005.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-005.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-005.htm" + } + ], + "css/word-break-keep-all-006.htm": [ + { + "path": "css/word-break-keep-all-006.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-006.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-006.htm" + } + ], + "css/word-break-keep-all-007.htm": [ + { + "path": "css/word-break-keep-all-007.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-007.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-007.htm" + } + ], + "css/word-break-keep-all-008.htm": [ + { + "path": "css/word-break-keep-all-008.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-008.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-008.htm" + } + ], "css/word-spacing.html": [ { "path": "css/word-spacing.html", @@ -19632,6 +19680,54 @@ "url": "/_mozilla/css/width_nonreplaced_block_simple_a.html" } ], + "css/word-break-keep-all-005.htm": [ + { + "path": "css/word-break-keep-all-005.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-005.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-005.htm" + } + ], + "css/word-break-keep-all-006.htm": [ + { + "path": "css/word-break-keep-all-006.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-006.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-006.htm" + } + ], + "css/word-break-keep-all-007.htm": [ + { + "path": "css/word-break-keep-all-007.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-007.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-007.htm" + } + ], + "css/word-break-keep-all-008.htm": [ + { + "path": "css/word-break-keep-all-008.htm", + "references": [ + [ + "/_mozilla/css/word-break-keep-all-ref-008.htm", + "==" + ] + ], + "url": "/_mozilla/css/word-break-keep-all-008.htm" + } + ], "css/word-spacing.html": [ { "path": "css/word-spacing.html", diff --git a/tests/wpt/mozilla/meta/css/word-break-keep-all-008.htm.ini b/tests/wpt/mozilla/meta/css/word-break-keep-all-008.htm.ini new file mode 100644 index 00000000000..3c59220918d --- /dev/null +++ b/tests/wpt/mozilla/meta/css/word-break-keep-all-008.htm.ini @@ -0,0 +1,3 @@ +[word-break-keep-all-008.htm] + type: reftest + expected: FAIL diff --git a/tests/wpt/mozilla/tests/css/word-break-keep-all-005.htm b/tests/wpt/mozilla/tests/css/word-break-keep-all-005.htm new file mode 100644 index 00000000000..5bf0022a007 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/word-break-keep-all-005.htm @@ -0,0 +1,24 @@ + +
+ +