layout: Implement word-break: break-all per CSS3-TEXT § 5.2.

This commit is contained in:
Patrick Walton 2015-01-01 16:34:51 -05:00
parent df6a7959df
commit 0627d4c599
5 changed files with 95 additions and 28 deletions

View file

@ -39,13 +39,13 @@ use servo_util::str::is_whitespace;
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Mutex};
use string_cache::Atom; use string_cache::Atom;
use style::{ComputedValues, TElement, TNode, cascade_anonymous}; use style::{ComputedValues, TElement, TNode, cascade_anonymous};
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto}; use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto};
use style::computed_values::{LengthOrPercentageOrNone}; use style::computed_values::{LengthOrPercentageOrNone};
use style::computed_values::{clear, overflow_wrap, position, text_align}; use style::computed_values::{clear, overflow_wrap, position, text_align, text_decoration};
use style::computed_values::{text_decoration, vertical_align, white_space}; use style::computed_values::{vertical_align, white_space, word_break};
use std::sync::{Arc, Mutex};
use url::Url; use url::Url;
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position /// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
@ -1138,16 +1138,12 @@ impl Fragment {
/// information are both optional due to the possibility of them being whitespace. /// information are both optional due to the possibility of them being whitespace.
pub fn calculate_split_position(&self, max_inline_size: Au, starts_line: bool) pub fn calculate_split_position(&self, max_inline_size: Au, starts_line: bool)
-> Option<SplitResult> { -> Option<SplitResult> {
let text_fragment_info = match self.specific { let text_fragment_info =
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Table | if let SpecificFragmentInfo::ScannedText(ref text_fragment_info) = self.specific {
SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) | text_fragment_info
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => return None, } else {
SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not have inline_size"), return None
SpecificFragmentInfo::UnscannedText(_) => { };
panic!("Unscanned text fragments should have been scanned by now!")
}
SpecificFragmentInfo::ScannedText(ref text_fragment_info) => text_fragment_info,
};
let mut flags = SplitOptions::empty(); let mut flags = SplitOptions::empty();
if starts_line { if starts_line {
@ -1157,11 +1153,27 @@ impl Fragment {
} }
} }
let natural_word_breaking_strategy = match self.style().get_inheritedtext().word_break {
text_fragment_info.run.natural_word_slices_in_range(&text_fragment_info.range); word_break::T::normal => {
self.calculate_split_position_using_breaking_strategy(natural_word_breaking_strategy, // Break at normal word boundaries.
max_inline_size, let natural_word_breaking_strategy =
flags) text_fragment_info.run.natural_word_slices_in_range(&text_fragment_info.range);
self.calculate_split_position_using_breaking_strategy(
natural_word_breaking_strategy,
max_inline_size,
flags)
}
word_break::T::break_all => {
// Break at character boundaries.
let character_breaking_strategy =
text_fragment_info.run.character_slices_in_range(&text_fragment_info.range);
flags.remove(RETRY_AT_CHARACTER_BOUNDARIES);
return self.calculate_split_position_using_breaking_strategy(
character_breaking_strategy,
max_inline_size,
flags)
}
}
} }
/// A helper method that uses the breaking strategy described by `slice_iterator` (at present, /// A helper method that uses the breaking strategy described by `slice_iterator` (at present,
@ -1172,16 +1184,12 @@ impl Fragment {
flags: SplitOptions) flags: SplitOptions)
-> Option<SplitResult> -> Option<SplitResult>
where I: Iterator<TextRunSlice<'a>> { where I: Iterator<TextRunSlice<'a>> {
let text_fragment_info = match self.specific { let text_fragment_info =
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Table | if let SpecificFragmentInfo::ScannedText(ref text_fragment_info) = self.specific {
SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) | text_fragment_info
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => return None, } else {
SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not have inline_size"), return None
SpecificFragmentInfo::UnscannedText(_) => { };
panic!("Unscanned text fragments should have been scanned by now!")
}
SpecificFragmentInfo::ScannedText(ref text_fragment_info) => text_fragment_info,
};
let mut pieces_processed_count: uint = 0; let mut pieces_processed_count: uint = 0;
let mut remaining_inline_size = max_inline_size; let mut remaining_inline_size = max_inline_size;

View file

@ -1322,6 +1322,9 @@ pub mod longhands {
// name per CSS-TEXT 6.2. // name per CSS-TEXT 6.2.
${single_keyword("overflow-wrap", "normal break-word")} ${single_keyword("overflow-wrap", "normal break-word")}
// TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support.
${single_keyword("word-break", "normal break-all")}
${new_style_struct("Text", is_inherited=False)} ${new_style_struct("Text", is_inherited=False)}
<%self:longhand name="text-decoration"> <%self:longhand name="text-decoration">

View file

@ -224,3 +224,4 @@ fragment=top != ../html/acid2.html acid2_ref.html
== border_radius_clip_a.html border_radius_clip_ref.html == border_radius_clip_a.html border_radius_clip_ref.html
== stacking_context_overflow_a.html stacking_context_overflow_ref.html == stacking_context_overflow_a.html stacking_context_overflow_ref.html
== stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html == stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html
== word_break_a.html word_break_ref.html

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<!-- Tests that `word-break: break-all` works. -->
<link rel="stylesheet" type="text/css" href="css/ahem.css">
<style>
html, body {
margin: 0;
}
section {
word-break: break-all;
width: 300px;
color: purple;
}
</style>
</head>
<body>
<section>X XXXXXXX</section>
</body>
</html>

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<!-- Tests that `word-break: break-all` works. -->
<style>
div {
background: purple;
position: absolute;
}
#a {
width: 100px;
left: 0;
top: 0;
height: 100px;
}
#b {
left: 200px;
top: 0;
width: 100px;
height: 100px;
}
#c {
left: 0;
top: 100px;
width: 300px;
height: 200px;
}
</style>
</head>
<body>
<div id=a></div><div id=b></div><div id=c></div>
</body>
</html>