layout: Take the white-space property into account when computing

intrinsic sizes of inline flows.

Improves Amazon.
This commit is contained in:
Patrick Walton 2015-04-22 17:07:06 -07:00
parent f9a50c9be0
commit f8b9b31680
5 changed files with 154 additions and 7 deletions

View file

@ -16,8 +16,7 @@ use flow_ref::FlowRef;
use incremental::{self, RestyleDamage};
use inline::{InlineFragmentContext, InlineMetrics};
use layout_debug;
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
use model;
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
use text;
use opaque_node::OpaqueNodeMethods;
use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
@ -1191,7 +1190,6 @@ impl Fragment {
}
SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
let range = &text_fragment_info.range;
let min_line_inline_size = text_fragment_info.run.min_width_for_range(range);
// See http://dev.w3.org/csswg/css-sizing/#max-content-inline-size.
// TODO: Account for soft wrap opportunities.
@ -1199,6 +1197,11 @@ impl Fragment {
.metrics_for_range(range)
.advance_width;
let min_line_inline_size = match self.style.get_inheritedtext().white_space {
white_space::T::pre | white_space::T::nowrap => max_line_inline_size,
white_space::T::normal => text_fragment_info.run.min_width_for_range(range),
};
result.union_block(&IntrinsicISizes {
minimum_inline_size: min_line_inline_size,
preferred_inline_size: max_line_inline_size,

View file

@ -1133,12 +1133,49 @@ impl Flow for InlineFlow {
flow::mut_base(kid).floats = Floats::new(writing_mode);
}
let mut computation = IntrinsicISizesContribution::new();
let mut intrinsic_sizes_for_flow = IntrinsicISizesContribution::new();
let mut intrinsic_sizes_for_inline_run = IntrinsicISizesContribution::new();
let mut intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
for fragment in self.fragments.fragments.iter_mut() {
debug!("Flow: measuring {:?}", *fragment);
computation.union_inline(&fragment.compute_intrinsic_inline_sizes().finish())
let intrinsic_sizes_for_fragment = fragment.compute_intrinsic_inline_sizes().finish();
match fragment.style.get_inheritedtext().white_space {
white_space::T::nowrap => {
intrinsic_sizes_for_nonbroken_run.union_nonbreaking_inline(
&intrinsic_sizes_for_fragment)
}
white_space::T::pre => {
intrinsic_sizes_for_nonbroken_run.union_nonbreaking_inline(
&intrinsic_sizes_for_fragment);
// Flush the intrinsic sizes we've been gathering up in order to handle the
// line break, if necessary.
if fragment.requires_line_break_afterward_if_wrapping_on_newlines() {
intrinsic_sizes_for_inline_run.union_inline(
&intrinsic_sizes_for_nonbroken_run.finish());
intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
intrinsic_sizes_for_flow.union_block(
&intrinsic_sizes_for_inline_run.finish());
intrinsic_sizes_for_inline_run = IntrinsicISizesContribution::new();
}
}
white_space::T::normal => {
// Flush the intrinsic sizes we were gathering up for the nonbroken run, if
// necessary.
intrinsic_sizes_for_inline_run.union_inline(
&intrinsic_sizes_for_nonbroken_run.finish());
intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
intrinsic_sizes_for_nonbroken_run.union_inline(&intrinsic_sizes_for_fragment)
}
}
}
self.base.intrinsic_inline_sizes = computation.finish()
// Flush any remaining nonbroken-run and inline-run intrinsic sizes.
intrinsic_sizes_for_inline_run.union_inline(&intrinsic_sizes_for_nonbroken_run.finish());
intrinsic_sizes_for_flow.union_block(&intrinsic_sizes_for_inline_run.finish());
// Finish up the computation.
self.base.intrinsic_inline_sizes = intrinsic_sizes_for_flow.finish()
}
/// Recursively (top-down) determines the actual inline-size of child contexts and fragments.

View file

@ -331,6 +331,17 @@ impl IntrinsicISizesContribution {
self.content_intrinsic_sizes.preferred_inline_size + sizes.preferred_inline_size
}
/// Updates the computation so that the minimum is the sum of the current minimum and the
/// given minimum and the preferred is the sum of the current preferred and the given
/// preferred. This is used when laying out fragments in the inline direction when
/// `white-space` is `pre` or `nowrap`.
pub fn union_nonbreaking_inline(&mut self, sizes: &IntrinsicISizes) {
self.content_intrinsic_sizes.minimum_inline_size =
self.content_intrinsic_sizes.minimum_inline_size + sizes.minimum_inline_size;
self.content_intrinsic_sizes.preferred_inline_size =
self.content_intrinsic_sizes.preferred_inline_size + sizes.preferred_inline_size
}
/// Updates the computation so that the minimum is the maximum of the current minimum and the
/// given minimum and the preferred is the maximum of the current preferred and the given
/// preferred. This can be useful when laying out fragments in the block direction (but note

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
table {
width: 0;
}
td {
border: solid black 1px;
white-space: nowrap;
}
</style>
</head>
<body>
<table>
<tr>
<td>
<div>
<div>Instant Video</div>
</div>
</td>
<td>
<div>
<div>Digital Music Store</div>
</div>
</td>
<td>
<div>
<div>Cloud Drive</div>
</div>
</td>
<td>
<div>
<div>Fire Phone</div>
</div>
</td>
<td>
<div>
<div>Appstore<br>for Android</div>
</div>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
td {
border: solid black 1px;
}
</style>
</head>
<body>
<table>
<tr>
<td>
<div>
<div>Instant&nbsp;Video</div>
</div>
</td>
<td>
<div>
<div>Digital&nbsp;Music&nbsp;Store</div>
</div>
</td>
<td>
<div>
<div>Cloud&nbsp;Drive</div>
</div>
</td>
<td>
<div>
<div>Fire&nbsp;Phone</div>
</div>
</td>
<td>
<div>
<div><div>Appstore</div><div>for Android</div></div>
</div>
</td>
</tr>
</table>
</body>
</html>