Auto merge of #12370 - emilio:wrap, r=mbrubeck

Fix line-breaking with white-space: pre-wrap/pre-line;

<!-- Please describe your changes on the following line: -->

Not sure if this is the appropriate fix, but we'll know soon.

---
<!-- 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 #12369

<!-- Either: -->
- [x] There are tests for these changes OR

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

r? @mbrubeck

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12370)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-07-11 01:08:57 -07:00 committed by GitHub
commit 8ded106186
6 changed files with 74 additions and 22 deletions

View file

@ -1541,11 +1541,10 @@ 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 = let text_fragment_info = match self.specific {
if let SpecificFragmentInfo::ScannedText(ref text_fragment_info) = self.specific { SpecificFragmentInfo::ScannedText(ref text_fragment_info)
text_fragment_info => text_fragment_info,
} else { _ => return None,
return None
}; };
let mut flags = SplitOptions::empty(); let mut flags = SplitOptions::empty();
@ -1618,11 +1617,10 @@ impl Fragment {
flags: SplitOptions) flags: SplitOptions)
-> Option<SplitResult> -> Option<SplitResult>
where I: Iterator<Item=TextRunSlice<'a>> { where I: Iterator<Item=TextRunSlice<'a>> {
let text_fragment_info = let text_fragment_info = match self.specific {
if let SpecificFragmentInfo::ScannedText(ref text_fragment_info) = self.specific { SpecificFragmentInfo::ScannedText(ref text_fragment_info)
text_fragment_info => text_fragment_info,
} else { _ => return None,
return None
}; };
let mut remaining_inline_size = max_inline_size; let mut remaining_inline_size = max_inline_size;
@ -1661,7 +1659,8 @@ impl Fragment {
// see if we're going to overflow the line. If so, perform a best-effort split. // see if we're going to overflow the line. If so, perform a best-effort split.
let mut remaining_range = slice.text_run_range(); let mut remaining_range = slice.text_run_range();
let split_is_empty = inline_start_range.is_empty() && let split_is_empty = inline_start_range.is_empty() &&
!self.requires_line_break_afterward_if_wrapping_on_newlines(); !(self.requires_line_break_afterward_if_wrapping_on_newlines() &&
!self.white_space().allow_wrap());
if split_is_empty { if split_is_empty {
// We're going to overflow the line. // We're going to overflow the line.
overflowing = true; overflowing = true;

View file

@ -459,10 +459,12 @@ impl LineBreaker {
kind: FloatKind::Left, kind: FloatKind::Left,
}); });
let fragment_margin_box_inline_size = first_fragment.margin_box_inline_size();
// Simple case: if the fragment fits, then we can stop here. // Simple case: if the fragment fits, then we can stop here.
if line_bounds.size.inline > first_fragment.margin_box_inline_size() { if line_bounds.size.inline > fragment_margin_box_inline_size {
debug!("LineBreaker: fragment fits on line {}", self.lines.len()); debug!("LineBreaker: fragment fits on line {}", self.lines.len());
return (line_bounds, first_fragment.margin_box_inline_size()); return (line_bounds, fragment_margin_box_inline_size);
} }
// If not, but we can't split the fragment, then we'll place the line here and it will // If not, but we can't split the fragment, then we'll place the line here and it will
@ -471,7 +473,7 @@ impl LineBreaker {
debug!("LineBreaker: line doesn't fit, but is unsplittable"); debug!("LineBreaker: line doesn't fit, but is unsplittable");
} }
(line_bounds, first_fragment.margin_box_inline_size()) (line_bounds, fragment_margin_box_inline_size)
} }
/// Performs float collision avoidance. This is called when adding a fragment is going to /// Performs float collision avoidance. This is called when adding a fragment is going to

View file

@ -340,22 +340,21 @@ impl TextRunScanner {
let mut byte_range = Range::new(ByteIndex(mapping.byte_range.begin() as isize), let mut byte_range = Range::new(ByteIndex(mapping.byte_range.begin() as isize),
ByteIndex(mapping.byte_range.length() as isize)); ByteIndex(mapping.byte_range.length() as isize));
let mut flags = ScannedTextFlags::empty();
let text_size = old_fragment.border_box.size;
let requires_line_break_afterward_if_wrapping_on_newlines = let requires_line_break_afterward_if_wrapping_on_newlines =
scanned_run.run.text[mapping.byte_range.begin()..mapping.byte_range.end()] scanned_run.run.text[mapping.byte_range.begin()..mapping.byte_range.end()]
.ends_with('\n'); .ends_with('\n');
if requires_line_break_afterward_if_wrapping_on_newlines { if requires_line_break_afterward_if_wrapping_on_newlines {
byte_range.extend_by(ByteIndex(-1)); // Trim the '\n' byte_range.extend_by(ByteIndex(-1)); // Trim the '\n'
flags.insert(REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES);
} }
let text_size = old_fragment.border_box.size;
let mut flags = ScannedTextFlags::empty();
if mapping.selected { if mapping.selected {
flags.insert(SELECTED); flags.insert(SELECTED);
} }
if requires_line_break_afterward_if_wrapping_on_newlines {
flags.insert(REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES);
}
let insertion_point = if mapping.contains_insertion_point(scanned_run.insertion_point) { let insertion_point = if mapping.contains_insertion_point(scanned_run.insertion_point) {
scanned_run.insertion_point scanned_run.insertion_point

View file

@ -6150,6 +6150,18 @@
"url": "/_mozilla/css/test_variable_serialization_specified.html" "url": "/_mozilla/css/test_variable_serialization_specified.html"
} }
], ],
"css/white-space-pre-line-long-line.html": [
{
"path": "css/white-space-pre-line-long-line.html",
"url": "/_mozilla/css/white-space-pre-line-long-line.html"
}
],
"css/white-space-pre-wrap-long-line.html": [
{
"path": "css/white-space-pre-wrap-long-line.html",
"url": "/_mozilla/css/white-space-pre-wrap-long-line.html"
}
],
"mozilla/DOMParser.html": [ "mozilla/DOMParser.html": [
{ {
"path": "mozilla/DOMParser.html", "path": "mozilla/DOMParser.html",

View file

@ -0,0 +1,20 @@
<!doctype html>
<meta charset="utf-8">
<title>White space pre-line crashtest (#12369)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
div {
width: 70px;
white-space: pre-line;
}
</style>
<div>This is an actual loooooooong line
Line 2</div>
<script>
async_test(function(t) {
window.addEventListener('load', function() {
t.done();
});
});
</script>

View file

@ -0,0 +1,20 @@
<!doctype html>
<meta charset="utf-8">
<title>White space pre-wrap crashtest (#12369)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
div {
width: 70px;
white-space: pre-wrap;
}
</style>
<div>This is an actual loooooooong line
Line 2</div>
<script>
async_test(function(t) {
window.addEventListener('load', function() {
t.done();
});
});
</script>