mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #5816 - pcwalton:more-jumpiness, r=mbrubeck
Fixes the "jumpiness" seen on the Google home page, Wikipedia, and many other places. r? @mbrubeck <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5816) <!-- Reviewable:end -->
This commit is contained in:
commit
211ee668fa
3 changed files with 47 additions and 13 deletions
|
@ -598,17 +598,26 @@ pub struct ScannedTextFragmentInfo {
|
||||||
/// so that we can restore the range to its original value (before line breaking occurred) when
|
/// so that we can restore the range to its original value (before line breaking occurred) when
|
||||||
/// performing incremental reflow.
|
/// performing incremental reflow.
|
||||||
pub range_end_including_stripped_whitespace: CharIndex,
|
pub range_end_including_stripped_whitespace: CharIndex,
|
||||||
|
|
||||||
|
/// Whether a line break is required after this fragment if wrapping on newlines (e.g. if
|
||||||
|
/// `white-space: pre` is in effect).
|
||||||
|
pub requires_line_break_afterward_if_wrapping_on_newlines: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScannedTextFragmentInfo {
|
impl ScannedTextFragmentInfo {
|
||||||
/// Creates the information specific to a scanned text fragment from a range and a text run.
|
/// Creates the information specific to a scanned text fragment from a range and a text run.
|
||||||
pub fn new(run: Arc<Box<TextRun>>, range: Range<CharIndex>, content_size: LogicalSize<Au>)
|
pub fn new(run: Arc<Box<TextRun>>,
|
||||||
|
range: Range<CharIndex>,
|
||||||
|
content_size: LogicalSize<Au>,
|
||||||
|
requires_line_break_afterward_if_wrapping_on_newlines: bool)
|
||||||
-> ScannedTextFragmentInfo {
|
-> ScannedTextFragmentInfo {
|
||||||
ScannedTextFragmentInfo {
|
ScannedTextFragmentInfo {
|
||||||
run: run,
|
run: run,
|
||||||
range: range,
|
range: range,
|
||||||
content_size: content_size,
|
content_size: content_size,
|
||||||
range_end_including_stripped_whitespace: range.end(),
|
range_end_including_stripped_whitespace: range.end(),
|
||||||
|
requires_line_break_afterward_if_wrapping_on_newlines:
|
||||||
|
requires_line_break_afterward_if_wrapping_on_newlines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -801,7 +810,13 @@ impl Fragment {
|
||||||
let size = LogicalSize::new(self.style.writing_mode,
|
let size = LogicalSize::new(self.style.writing_mode,
|
||||||
split.inline_size,
|
split.inline_size,
|
||||||
self.border_box.size.block);
|
self.border_box.size.block);
|
||||||
let info = box ScannedTextFragmentInfo::new(text_run, split.range, size);
|
let requires_line_break_afterward_if_wrapping_on_newlines =
|
||||||
|
self.requires_line_break_afterward_if_wrapping_on_newlines();
|
||||||
|
let info = box ScannedTextFragmentInfo::new(
|
||||||
|
text_run,
|
||||||
|
split.range,
|
||||||
|
size,
|
||||||
|
requires_line_break_afterward_if_wrapping_on_newlines);
|
||||||
self.transform(size, SpecificFragmentInfo::ScannedText(info))
|
self.transform(size, SpecificFragmentInfo::ScannedText(info))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,7 +1432,9 @@ impl Fragment {
|
||||||
// The advance is more than the remaining inline-size, so split here. First, check to
|
// The advance is more than the remaining inline-size, so split here. First, check to
|
||||||
// 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();
|
||||||
if inline_start_range.is_empty() {
|
let split_is_empty = inline_start_range.is_empty() &&
|
||||||
|
!self.requires_line_break_afterward_if_wrapping_on_newlines();
|
||||||
|
if split_is_empty {
|
||||||
// We're going to overflow the line.
|
// We're going to overflow the line.
|
||||||
overflowing = true;
|
overflowing = true;
|
||||||
inline_start_range = slice.text_run_range();
|
inline_start_range = slice.text_run_range();
|
||||||
|
@ -1439,7 +1456,7 @@ impl Fragment {
|
||||||
|
|
||||||
// If we failed to find a suitable split point, we're on the verge of overflowing the
|
// If we failed to find a suitable split point, we're on the verge of overflowing the
|
||||||
// line.
|
// line.
|
||||||
if inline_start_range.is_empty() || overflowing {
|
if split_is_empty || overflowing {
|
||||||
// If we've been instructed to retry at character boundaries (probably via
|
// If we've been instructed to retry at character boundaries (probably via
|
||||||
// `overflow-wrap: break-word`), do so.
|
// `overflow-wrap: break-word`), do so.
|
||||||
if flags.contains(RETRY_AT_CHARACTER_BOUNDARIES) {
|
if flags.contains(RETRY_AT_CHARACTER_BOUNDARIES) {
|
||||||
|
@ -1464,7 +1481,9 @@ impl Fragment {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let inline_start = if !inline_start_range.is_empty() {
|
let split_is_empty = inline_start_range.is_empty() &&
|
||||||
|
!self.requires_line_break_afterward_if_wrapping_on_newlines();
|
||||||
|
let inline_start = if !split_is_empty {
|
||||||
Some(SplitInfo::new(inline_start_range, &**text_fragment_info))
|
Some(SplitInfo::new(inline_start_range, &**text_fragment_info))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -1490,6 +1509,9 @@ impl Fragment {
|
||||||
this_info.range.extend_to(other_info.range_end_including_stripped_whitespace);
|
this_info.range.extend_to(other_info.range_end_including_stripped_whitespace);
|
||||||
this_info.content_size.inline =
|
this_info.content_size.inline =
|
||||||
this_info.run.metrics_for_range(&this_info.range).advance_width;
|
this_info.run.metrics_for_range(&this_info.range).advance_width;
|
||||||
|
this_info.requires_line_break_afterward_if_wrapping_on_newlines =
|
||||||
|
this_info.requires_line_break_afterward_if_wrapping_on_newlines ||
|
||||||
|
other_info.requires_line_break_afterward_if_wrapping_on_newlines;
|
||||||
self.border_box.size.inline = this_info.content_size.inline +
|
self.border_box.size.inline = this_info.content_size.inline +
|
||||||
self.border_padding.inline_start_end();
|
self.border_padding.inline_start_end();
|
||||||
}
|
}
|
||||||
|
@ -1920,10 +1942,7 @@ impl Fragment {
|
||||||
pub fn requires_line_break_afterward_if_wrapping_on_newlines(&self) -> bool {
|
pub fn requires_line_break_afterward_if_wrapping_on_newlines(&self) -> bool {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
SpecificFragmentInfo::ScannedText(ref scanned_text) => {
|
SpecificFragmentInfo::ScannedText(ref scanned_text) => {
|
||||||
!scanned_text.range.is_empty() &&
|
scanned_text.requires_line_break_afterward_if_wrapping_on_newlines
|
||||||
scanned_text.run.text.char_at_reverse(scanned_text.range
|
|
||||||
.end()
|
|
||||||
.get() as usize) == '\n'
|
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ use style::properties::style_structs::Font as FontStyle;
|
||||||
use util::geometry::Au;
|
use util::geometry::Au;
|
||||||
use util::linked_list::split_off_head;
|
use util::linked_list::split_off_head;
|
||||||
use util::logical_geometry::{LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalSize, WritingMode};
|
||||||
use util::range::Range;
|
use util::range::{Range, RangeIndex};
|
||||||
use util::smallvec::{SmallVec, SmallVec1};
|
use util::smallvec::{SmallVec, SmallVec1};
|
||||||
|
|
||||||
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextFragment`s.
|
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextFragment`s.
|
||||||
|
@ -193,16 +193,25 @@ impl TextRunScanner {
|
||||||
debug!("TextRunScanner: pushing {} fragment(s)", self.clump.len());
|
debug!("TextRunScanner: pushing {} fragment(s)", self.clump.len());
|
||||||
for (logical_offset, old_fragment) in
|
for (logical_offset, old_fragment) in
|
||||||
mem::replace(&mut self.clump, LinkedList::new()).into_iter().enumerate() {
|
mem::replace(&mut self.clump, LinkedList::new()).into_iter().enumerate() {
|
||||||
let range = *new_ranges.get(logical_offset);
|
let mut range = *new_ranges.get(logical_offset);
|
||||||
if range.is_empty() {
|
if range.is_empty() {
|
||||||
debug!("Elided an `SpecificFragmentInfo::UnscannedText` because it was \
|
debug!("Elided an `SpecificFragmentInfo::UnscannedText` because it was \
|
||||||
zero-length after compression");
|
zero-length after compression");
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let requires_line_break_afterward_if_wrapping_on_newlines =
|
||||||
|
run.text.char_at_reverse(range.end().get() as usize) == '\n';
|
||||||
|
if requires_line_break_afterward_if_wrapping_on_newlines {
|
||||||
|
range.extend_by(CharIndex(-1))
|
||||||
|
}
|
||||||
|
|
||||||
let text_size = old_fragment.border_box.size;
|
let text_size = old_fragment.border_box.size;
|
||||||
let mut new_text_fragment_info =
|
let mut new_text_fragment_info = box ScannedTextFragmentInfo::new(
|
||||||
box ScannedTextFragmentInfo::new(run.clone(), range, text_size);
|
run.clone(),
|
||||||
|
range,
|
||||||
|
text_size,
|
||||||
|
requires_line_break_afterward_if_wrapping_on_newlines);
|
||||||
let new_metrics = new_text_fragment_info.run.metrics_for_range(&range);
|
let new_metrics = new_text_fragment_info.run.metrics_for_range(&range);
|
||||||
let bounding_box_size = bounding_box_for_run_metrics(&new_metrics,
|
let bounding_box_size = bounding_box_for_run_metrics(&new_metrics,
|
||||||
old_fragment.style.writing_mode);
|
old_fragment.style.writing_mode);
|
||||||
|
|
6
tests/html/incremental_inline_line_flush_mode.html
Normal file
6
tests/html/incremental_inline_line_flush_mode.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- This will become "jumpy" when mousing over "Bar" if trailing newlines are stripped from
|
||||||
|
fragments during inline layout. -->
|
||||||
|
<table><td><div style="white-space: pre">
|
||||||
|
Foo</div></td><td><a href="/">Bar</a></td></table>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue