mirror of
https://github.com/servo/servo.git
synced 2025-06-24 17:14:33 +01:00
layout: During inline layout, make place_between_floats
use the same
line height computation logic as final block size assignment. Improves Wikipedia.
This commit is contained in:
parent
51dd6984f7
commit
00a2685cbe
6 changed files with 143 additions and 51 deletions
|
@ -333,7 +333,9 @@ impl Floats {
|
||||||
let maybe_location = self.available_rect(float_b,
|
let maybe_location = self.available_rect(float_b,
|
||||||
info.size.block,
|
info.size.block,
|
||||||
info.max_inline_size);
|
info.max_inline_size);
|
||||||
debug!("place_float: Got available rect: {:?} for y-pos: {:?}", maybe_location, float_b);
|
debug!("place_float: got available rect: {:?} for block-pos: {:?}",
|
||||||
|
maybe_location,
|
||||||
|
float_b);
|
||||||
match maybe_location {
|
match maybe_location {
|
||||||
// If there are no floats blocking us, return the current location
|
// If there are no floats blocking us, return the current location
|
||||||
// TODO(eatkinson): integrate with overflow
|
// TODO(eatkinson): integrate with overflow
|
||||||
|
|
|
@ -1268,37 +1268,6 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns, and computes, the block-size of this fragment.
|
|
||||||
pub fn content_block_size(&self, layout_context: &LayoutContext) -> Au {
|
|
||||||
match self.specific {
|
|
||||||
SpecificFragmentInfo::Generic |
|
|
||||||
SpecificFragmentInfo::GeneratedContent(_) |
|
|
||||||
SpecificFragmentInfo::Iframe(_) |
|
|
||||||
SpecificFragmentInfo::Table |
|
|
||||||
SpecificFragmentInfo::TableCell |
|
|
||||||
SpecificFragmentInfo::TableRow |
|
|
||||||
SpecificFragmentInfo::TableWrapper |
|
|
||||||
SpecificFragmentInfo::InlineBlock(_) |
|
|
||||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0),
|
|
||||||
SpecificFragmentInfo::Image(ref image_fragment_info) => {
|
|
||||||
image_fragment_info.replaced_image_fragment_info.computed_block_size()
|
|
||||||
}
|
|
||||||
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
|
|
||||||
canvas_fragment_info.replaced_image_fragment_info.computed_block_size()
|
|
||||||
}
|
|
||||||
SpecificFragmentInfo::ScannedText(_) => {
|
|
||||||
// Compute the block-size based on the line-block-size and font size.
|
|
||||||
self.calculate_line_height(layout_context)
|
|
||||||
}
|
|
||||||
SpecificFragmentInfo::TableColumn(_) => {
|
|
||||||
panic!("Table column fragments do not have block size")
|
|
||||||
}
|
|
||||||
SpecificFragmentInfo::UnscannedText(_) => {
|
|
||||||
panic!("Unscanned text fragments should have been scanned by now!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the dimensions of the content box.
|
/// Returns the dimensions of the content box.
|
||||||
///
|
///
|
||||||
/// This is marked `#[inline]` because it is frequently called when only one or two of the
|
/// This is marked `#[inline]` because it is frequently called when only one or two of the
|
||||||
|
|
|
@ -148,6 +148,9 @@ pub struct Line {
|
||||||
/// FFF float
|
/// FFF float
|
||||||
/// ~~~
|
/// ~~~
|
||||||
pub green_zone: LogicalSize<Au>,
|
pub green_zone: LogicalSize<Au>,
|
||||||
|
|
||||||
|
/// The inline metrics for this line.
|
||||||
|
pub inline_metrics: InlineMetrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
int_range_index! {
|
int_range_index! {
|
||||||
|
@ -181,11 +184,21 @@ struct LineBreaker {
|
||||||
cur_b: Au,
|
cur_b: Au,
|
||||||
/// The computed value of the indentation for the first line (`text-indent`, CSS 2.1 § 16.1).
|
/// The computed value of the indentation for the first line (`text-indent`, CSS 2.1 § 16.1).
|
||||||
first_line_indentation: Au,
|
first_line_indentation: Au,
|
||||||
|
/// The minimum block-size above the baseline for each line, as specified by the line height
|
||||||
|
/// and font style.
|
||||||
|
minimum_block_size_above_baseline: Au,
|
||||||
|
/// The minimum depth below the baseline for each line, as specified by the line height and
|
||||||
|
/// font style.
|
||||||
|
minimum_depth_below_baseline: Au,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LineBreaker {
|
impl LineBreaker {
|
||||||
/// Creates a new `LineBreaker` with a set of floats and the indentation of the first line.
|
/// Creates a new `LineBreaker` with a set of floats and the indentation of the first line.
|
||||||
fn new(float_context: Floats, first_line_indentation: Au) -> LineBreaker {
|
fn new(float_context: Floats,
|
||||||
|
first_line_indentation: Au,
|
||||||
|
minimum_block_size_above_baseline: Au,
|
||||||
|
minimum_depth_below_baseline: Au)
|
||||||
|
-> LineBreaker {
|
||||||
LineBreaker {
|
LineBreaker {
|
||||||
new_fragments: Vec::new(),
|
new_fragments: Vec::new(),
|
||||||
work_list: VecDeque::new(),
|
work_list: VecDeque::new(),
|
||||||
|
@ -193,11 +206,16 @@ impl LineBreaker {
|
||||||
range: Range::empty(),
|
range: Range::empty(),
|
||||||
bounds: LogicalRect::zero(float_context.writing_mode),
|
bounds: LogicalRect::zero(float_context.writing_mode),
|
||||||
green_zone: LogicalSize::zero(float_context.writing_mode),
|
green_zone: LogicalSize::zero(float_context.writing_mode),
|
||||||
|
inline_metrics: InlineMetrics::new(minimum_block_size_above_baseline,
|
||||||
|
minimum_depth_below_baseline,
|
||||||
|
minimum_block_size_above_baseline),
|
||||||
},
|
},
|
||||||
floats: float_context,
|
floats: float_context,
|
||||||
lines: Vec::new(),
|
lines: Vec::new(),
|
||||||
cur_b: Au(0),
|
cur_b: Au(0),
|
||||||
first_line_indentation: first_line_indentation,
|
first_line_indentation: first_line_indentation,
|
||||||
|
minimum_block_size_above_baseline: minimum_block_size_above_baseline,
|
||||||
|
minimum_depth_below_baseline: minimum_depth_below_baseline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +236,10 @@ impl LineBreaker {
|
||||||
Au(0),
|
Au(0),
|
||||||
Au(0));
|
Au(0));
|
||||||
self.pending_line.green_zone = LogicalSize::zero(self.floats.writing_mode);
|
self.pending_line.green_zone = LogicalSize::zero(self.floats.writing_mode);
|
||||||
|
self.pending_line.inline_metrics =
|
||||||
|
InlineMetrics::new(self.minimum_block_size_above_baseline,
|
||||||
|
self.minimum_depth_below_baseline,
|
||||||
|
self.minimum_block_size_above_baseline)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reflows fragments for the given inline flow.
|
/// Reflows fragments for the given inline flow.
|
||||||
|
@ -370,14 +392,15 @@ impl LineBreaker {
|
||||||
|
|
||||||
// FIXME(eatkinson): this assumes that the tallest fragment in the line determines the line
|
// FIXME(eatkinson): this assumes that the tallest fragment in the line determines the line
|
||||||
// block-size. This might not be the case with some weird text fonts.
|
// block-size. This might not be the case with some weird text fonts.
|
||||||
|
fn new_inline_metrics_for_line(&self, new_fragment: &Fragment, layout_context: &LayoutContext)
|
||||||
|
-> InlineMetrics {
|
||||||
|
self.pending_line.inline_metrics.max(&new_fragment.inline_metrics(layout_context))
|
||||||
|
}
|
||||||
|
|
||||||
fn new_block_size_for_line(&self, new_fragment: &Fragment, layout_context: &LayoutContext)
|
fn new_block_size_for_line(&self, new_fragment: &Fragment, layout_context: &LayoutContext)
|
||||||
-> Au {
|
-> Au {
|
||||||
let fragment_block_size = new_fragment.content_block_size(layout_context);
|
Au::max(self.pending_line.bounds.size.block,
|
||||||
if fragment_block_size > self.pending_line.bounds.size.block {
|
self.new_inline_metrics_for_line(new_fragment, layout_context).block_size())
|
||||||
fragment_block_size
|
|
||||||
} else {
|
|
||||||
self.pending_line.bounds.size.block
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the position of a line that has only the provided fragment. Returns the bounding
|
/// Computes the position of a line that has only the provided fragment. Returns the bounding
|
||||||
|
@ -616,7 +639,7 @@ impl LineBreaker {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !need_ellipsis {
|
if !need_ellipsis {
|
||||||
self.push_fragment_to_line_ignoring_text_overflow(fragment);
|
self.push_fragment_to_line_ignoring_text_overflow(fragment, layout_context);
|
||||||
} else {
|
} else {
|
||||||
let ellipsis = fragment.transform_into_ellipsis(layout_context);
|
let ellipsis = fragment.transform_into_ellipsis(layout_context);
|
||||||
if let Some(truncation_info) =
|
if let Some(truncation_info) =
|
||||||
|
@ -624,9 +647,9 @@ impl LineBreaker {
|
||||||
ellipsis.border_box.size.inline) {
|
ellipsis.border_box.size.inline) {
|
||||||
let fragment = fragment.transform_with_split_info(&truncation_info.split,
|
let fragment = fragment.transform_with_split_info(&truncation_info.split,
|
||||||
truncation_info.text_run);
|
truncation_info.text_run);
|
||||||
self.push_fragment_to_line_ignoring_text_overflow(fragment);
|
self.push_fragment_to_line_ignoring_text_overflow(fragment, layout_context);
|
||||||
}
|
}
|
||||||
self.push_fragment_to_line_ignoring_text_overflow(ellipsis);
|
self.push_fragment_to_line_ignoring_text_overflow(ellipsis, layout_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if line_flush_mode == LineFlushMode::Flush {
|
if line_flush_mode == LineFlushMode::Flush {
|
||||||
|
@ -636,14 +659,18 @@ impl LineBreaker {
|
||||||
|
|
||||||
/// Pushes a fragment to the current line unconditionally, without placing an ellipsis in the
|
/// Pushes a fragment to the current line unconditionally, without placing an ellipsis in the
|
||||||
/// case of `text-overflow: ellipsis`.
|
/// case of `text-overflow: ellipsis`.
|
||||||
fn push_fragment_to_line_ignoring_text_overflow(&mut self, fragment: Fragment) {
|
fn push_fragment_to_line_ignoring_text_overflow(&mut self,
|
||||||
|
fragment: Fragment,
|
||||||
|
layout_context: &LayoutContext) {
|
||||||
let indentation = self.indentation_for_pending_fragment();
|
let indentation = self.indentation_for_pending_fragment();
|
||||||
self.pending_line.range.extend_by(FragmentIndex(1));
|
self.pending_line.range.extend_by(FragmentIndex(1));
|
||||||
self.pending_line.bounds.size.inline = self.pending_line.bounds.size.inline +
|
self.pending_line.bounds.size.inline = self.pending_line.bounds.size.inline +
|
||||||
fragment.border_box.size.inline +
|
fragment.border_box.size.inline +
|
||||||
indentation;
|
indentation;
|
||||||
self.pending_line.bounds.size.block = max(self.pending_line.bounds.size.block,
|
self.pending_line.inline_metrics =
|
||||||
fragment.border_box.size.block);
|
self.new_inline_metrics_for_line(&fragment, layout_context);
|
||||||
|
self.pending_line.bounds.size.block =
|
||||||
|
self.new_block_size_for_line(&fragment, layout_context);
|
||||||
self.new_fragments.push(fragment);
|
self.new_fragments.push(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,11 +757,11 @@ pub struct InlineFlow {
|
||||||
/// lines.
|
/// lines.
|
||||||
pub lines: Vec<Line>,
|
pub lines: Vec<Line>,
|
||||||
|
|
||||||
/// The minimum block-size above the baseline for each line, as specified by the line block-
|
/// The minimum block-size above the baseline for each line, as specified by the line height
|
||||||
/// size and font style.
|
/// and font style.
|
||||||
pub minimum_block_size_above_baseline: Au,
|
pub minimum_block_size_above_baseline: Au,
|
||||||
|
|
||||||
/// The minimum depth below the baseline for each line, as specified by the line block-size and
|
/// The minimum depth below the baseline for each line, as specified by the line height and
|
||||||
/// font style.
|
/// font style.
|
||||||
pub minimum_depth_below_baseline: Au,
|
pub minimum_depth_below_baseline: Au,
|
||||||
|
|
||||||
|
@ -1148,7 +1175,10 @@ impl Flow for InlineFlow {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Perform line breaking.
|
// Perform line breaking.
|
||||||
let mut scanner = LineBreaker::new(self.base.floats.clone(), indentation);
|
let mut scanner = LineBreaker::new(self.base.floats.clone(),
|
||||||
|
indentation,
|
||||||
|
self.minimum_block_size_above_baseline,
|
||||||
|
self.minimum_depth_below_baseline);
|
||||||
scanner.scan_for_lines(self, layout_context);
|
scanner.scan_for_lines(self, layout_context);
|
||||||
|
|
||||||
// Now, go through each line and lay out the fragments inside.
|
// Now, go through each line and lay out the fragments inside.
|
||||||
|
@ -1417,6 +1447,7 @@ fn inline_contexts_are_equal(inline_context_a: &Option<InlineFragmentContext>,
|
||||||
|
|
||||||
/// Block-size above the baseline, depth below the baseline, and ascent for a fragment. See CSS 2.1
|
/// Block-size above the baseline, depth below the baseline, and ascent for a fragment. See CSS 2.1
|
||||||
/// § 10.8.1.
|
/// § 10.8.1.
|
||||||
|
#[derive(Clone, Copy, Debug, RustcEncodable)]
|
||||||
pub struct InlineMetrics {
|
pub struct InlineMetrics {
|
||||||
pub block_size_above_baseline: Au,
|
pub block_size_above_baseline: Au,
|
||||||
pub depth_below_baseline: Au,
|
pub depth_below_baseline: Au,
|
||||||
|
@ -1424,6 +1455,16 @@ pub struct InlineMetrics {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineMetrics {
|
impl InlineMetrics {
|
||||||
|
/// Creates a new set of inline metrics.
|
||||||
|
pub fn new(block_size_above_baseline: Au, depth_below_baseline: Au, ascent: Au)
|
||||||
|
-> InlineMetrics {
|
||||||
|
InlineMetrics {
|
||||||
|
block_size_above_baseline: block_size_above_baseline,
|
||||||
|
depth_below_baseline: depth_below_baseline,
|
||||||
|
ascent: ascent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates inline metrics from font metrics and line block-size per CSS 2.1 § 10.8.1.
|
/// Calculates inline metrics from font metrics and line block-size per CSS 2.1 § 10.8.1.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_font_metrics(font_metrics: &FontMetrics, line_height: Au) -> InlineMetrics {
|
pub fn from_font_metrics(font_metrics: &FontMetrics, line_height: Au) -> InlineMetrics {
|
||||||
|
@ -1445,6 +1486,19 @@ impl InlineMetrics {
|
||||||
ascent: font_metrics.ascent + leading.scale_by(0.5),
|
ascent: font_metrics.ascent + leading.scale_by(0.5),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block_size(&self) -> Au {
|
||||||
|
self.block_size_above_baseline + self.depth_below_baseline
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max(&self, other: &InlineMetrics) -> InlineMetrics {
|
||||||
|
InlineMetrics {
|
||||||
|
block_size_above_baseline: Au::max(self.block_size_above_baseline,
|
||||||
|
other.block_size_above_baseline),
|
||||||
|
depth_below_baseline: Au::max(self.depth_below_baseline, other.depth_below_baseline),
|
||||||
|
ascent: Au::max(self.ascent, other.ascent),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
|
|
@ -188,6 +188,7 @@ flaky_cpu == append_style_a.html append_style_b.html
|
||||||
== letter_spacing_a.html letter_spacing_ref.html
|
== letter_spacing_a.html letter_spacing_ref.html
|
||||||
== line_breaking_whitespace_collapse_a.html line_breaking_whitespace_collapse_ref.html
|
== line_breaking_whitespace_collapse_a.html line_breaking_whitespace_collapse_ref.html
|
||||||
== line_height_a.html line_height_ref.html
|
== line_height_a.html line_height_ref.html
|
||||||
|
== line_height_float_placement_a.html line_height_float_placement_ref.html
|
||||||
!= linear_gradients_corners_a.html linear_gradients_corners_ref.html
|
!= linear_gradients_corners_a.html linear_gradients_corners_ref.html
|
||||||
== linear_gradients_lengths_a.html linear_gradients_lengths_ref.html
|
== linear_gradients_lengths_a.html linear_gradients_lengths_ref.html
|
||||||
== linear_gradients_parsing_a.html linear_gradients_parsing_ref.html
|
== linear_gradients_parsing_a.html linear_gradients_parsing_ref.html
|
||||||
|
|
32
tests/ref/line_height_float_placement_a.html
Normal file
32
tests/ref/line_height_float_placement_a.html
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/ahem.css">
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Ahem, monospace;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
#floaty {
|
||||||
|
float: left;
|
||||||
|
height: 20px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
#pre {
|
||||||
|
line-height: 32px;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id=floaty></div>
|
||||||
|
<div id=pre>x
|
||||||
|
x</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
34
tests/ref/line_height_float_placement_ref.html
Normal file
34
tests/ref/line_height_float_placement_ref.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/ahem.css">
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: Ahem, monospace;
|
||||||
|
}
|
||||||
|
#floaty {
|
||||||
|
float: left;
|
||||||
|
height: 20px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
#pre {
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
.spacer {
|
||||||
|
color: transparent;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id=floaty></div>
|
||||||
|
<div id=pre>x<span class=spacer>x</span>
|
||||||
|
x<span class=spacer>x</span></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue