mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Properly handle subpixel units when dividing space between flex lines (#32913)
Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
5d6840873a
commit
8582678e4b
4 changed files with 247 additions and 182 deletions
|
@ -506,137 +506,6 @@ impl FlexContainer {
|
||||||
flex_context.container_max_cross_size,
|
flex_context.container_max_cross_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-flexbox/#algo-line-align
|
|
||||||
// Align all flex lines per `align-content`.
|
|
||||||
let mut cross_start_position_cursor = Au::zero();
|
|
||||||
let mut line_interval = cross_gap;
|
|
||||||
|
|
||||||
let mut extra_space_for_align_stretch = Au::zero();
|
|
||||||
if let Some(cross_size) = flex_context.container_definite_inner_size.cross {
|
|
||||||
let mut free_space = cross_size - content_cross_size;
|
|
||||||
let layout_is_flex_reversed = flex_context.flex_wrap_reverse;
|
|
||||||
|
|
||||||
// Implement fallback alignment.
|
|
||||||
//
|
|
||||||
// In addition to the spec at https://www.w3.org/TR/css-align-3/ this implementation follows
|
|
||||||
// the resolution of https://github.com/w3c/csswg-drafts/issues/10154
|
|
||||||
let resolved_align_content: AlignFlags = {
|
|
||||||
let align_content_style = flex_context.align_content.0.primary();
|
|
||||||
|
|
||||||
// Inital values from the style system
|
|
||||||
let mut resolved_align_content = align_content_style.value();
|
|
||||||
let mut is_safe = align_content_style.flags() == AlignFlags::SAFE;
|
|
||||||
|
|
||||||
// From https://drafts.csswg.org/css-flexbox/#algo-line-align:
|
|
||||||
// > Some alignments can only be fulfilled in certain situations or are
|
|
||||||
// > limited in how much space they can consume; for example, space-between
|
|
||||||
// > can only operate when there is more than one alignment subject, and
|
|
||||||
// > baseline alignment, once fulfilled, might not be enough to absorb all
|
|
||||||
// > the excess space. In these cases a fallback alignment takes effect (as
|
|
||||||
// > defined below) to fully consume the excess space.
|
|
||||||
let fallback_is_needed = match resolved_align_content {
|
|
||||||
_ if free_space <= Au::zero() => true,
|
|
||||||
AlignFlags::STRETCH => line_count < 1,
|
|
||||||
AlignFlags::SPACE_BETWEEN |
|
|
||||||
AlignFlags::SPACE_AROUND |
|
|
||||||
AlignFlags::SPACE_EVENLY => line_count < 2,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if fallback_is_needed {
|
|
||||||
(resolved_align_content, is_safe) = match resolved_align_content {
|
|
||||||
AlignFlags::STRETCH => (AlignFlags::FLEX_START, true),
|
|
||||||
AlignFlags::SPACE_BETWEEN => (AlignFlags::FLEX_START, true),
|
|
||||||
AlignFlags::SPACE_AROUND => (AlignFlags::CENTER, true),
|
|
||||||
AlignFlags::SPACE_EVENLY => (AlignFlags::CENTER, true),
|
|
||||||
_ => (resolved_align_content, is_safe),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
|
|
||||||
if free_space <= Au::zero() && is_safe {
|
|
||||||
resolved_align_content = AlignFlags::START;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolved_align_content
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: There are bad cases where we end up distributing much less free space than we have.
|
|
||||||
// For instance if we have 999 Au of free space and 1000 lines, we won't distribute any!
|
|
||||||
// We need to calculate how much free space to distribute to a line for every line, subtracting
|
|
||||||
// that value from the total.
|
|
||||||
if resolved_align_content == AlignFlags::STRETCH {
|
|
||||||
extra_space_for_align_stretch = free_space / initial_line_layouts.len() as i32;
|
|
||||||
free_space -= extra_space_for_align_stretch * initial_line_layouts.len() as i32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
|
|
||||||
cross_start_position_cursor = match resolved_align_content {
|
|
||||||
AlignFlags::START => Au::zero(),
|
|
||||||
AlignFlags::FLEX_START => {
|
|
||||||
if layout_is_flex_reversed {
|
|
||||||
free_space
|
|
||||||
} else {
|
|
||||||
Au::zero()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
AlignFlags::END => free_space,
|
|
||||||
AlignFlags::FLEX_END => {
|
|
||||||
if layout_is_flex_reversed {
|
|
||||||
Au::zero()
|
|
||||||
} else {
|
|
||||||
free_space
|
|
||||||
}
|
|
||||||
},
|
|
||||||
AlignFlags::CENTER => free_space / 2,
|
|
||||||
AlignFlags::STRETCH => Au::zero(),
|
|
||||||
AlignFlags::SPACE_BETWEEN => Au::zero(),
|
|
||||||
AlignFlags::SPACE_AROUND => free_space / line_count as i32 / 2,
|
|
||||||
AlignFlags::SPACE_EVENLY => free_space / (line_count + 1) as i32,
|
|
||||||
|
|
||||||
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
|
|
||||||
_ => Au::zero(),
|
|
||||||
};
|
|
||||||
|
|
||||||
line_interval += match resolved_align_content {
|
|
||||||
AlignFlags::START => Au::zero(),
|
|
||||||
AlignFlags::FLEX_START => Au::zero(),
|
|
||||||
AlignFlags::END => Au::zero(),
|
|
||||||
AlignFlags::FLEX_END => Au::zero(),
|
|
||||||
AlignFlags::CENTER => Au::zero(),
|
|
||||||
AlignFlags::STRETCH => Au::zero(),
|
|
||||||
AlignFlags::SPACE_BETWEEN => free_space / (line_count - 1) as i32,
|
|
||||||
AlignFlags::SPACE_AROUND => free_space / line_count as i32,
|
|
||||||
AlignFlags::SPACE_EVENLY => free_space / (line_count + 1) as i32,
|
|
||||||
|
|
||||||
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
|
|
||||||
_ => Au::zero(),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let final_line_layouts: Vec<_> = initial_line_layouts
|
|
||||||
.into_iter()
|
|
||||||
.map(|initial_layout| {
|
|
||||||
let final_line_cross_size =
|
|
||||||
initial_layout.line_size.cross + extra_space_for_align_stretch;
|
|
||||||
initial_layout.finish_with_final_cross_size(
|
|
||||||
&mut flex_context,
|
|
||||||
main_gap,
|
|
||||||
final_line_cross_size,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let line_cross_start_positions = final_line_layouts
|
|
||||||
.iter()
|
|
||||||
.map(|line| {
|
|
||||||
let cross_start = cross_start_position_cursor;
|
|
||||||
let cross_end = cross_start + line.cross_size + line_interval;
|
|
||||||
cross_start_position_cursor = cross_end;
|
|
||||||
cross_start
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let content_block_size = match flex_context.flex_axis {
|
let content_block_size = match flex_context.flex_axis {
|
||||||
FlexAxis::Row => {
|
FlexAxis::Row => {
|
||||||
// `container_main_size` ends up unused here but in this case that’s fine
|
// `container_main_size` ends up unused here but in this case that’s fine
|
||||||
|
@ -656,58 +525,165 @@ impl FlexContainer {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut remaining_free_cross_space = flex_context
|
||||||
|
.container_definite_inner_size
|
||||||
|
.cross
|
||||||
|
.map(|cross_size| cross_size - content_cross_size)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// Implement fallback alignment.
|
||||||
|
//
|
||||||
|
// In addition to the spec at https://www.w3.org/TR/css-align-3/ this implementation follows
|
||||||
|
// the resolution of https://github.com/w3c/csswg-drafts/issues/10154
|
||||||
|
let num_lines = initial_line_layouts.len();
|
||||||
|
let resolved_align_content: AlignFlags = {
|
||||||
|
let align_content_style = flex_context.align_content.0.primary();
|
||||||
|
|
||||||
|
// Inital values from the style system
|
||||||
|
let mut resolved_align_content = align_content_style.value();
|
||||||
|
let mut is_safe = align_content_style.flags() == AlignFlags::SAFE;
|
||||||
|
|
||||||
|
// From https://drafts.csswg.org/css-flexbox/#algo-line-align:
|
||||||
|
// > Some alignments can only be fulfilled in certain situations or are
|
||||||
|
// > limited in how much space they can consume; for example, space-between
|
||||||
|
// > can only operate when there is more than one alignment subject, and
|
||||||
|
// > baseline alignment, once fulfilled, might not be enough to absorb all
|
||||||
|
// > the excess space. In these cases a fallback alignment takes effect (as
|
||||||
|
// > defined below) to fully consume the excess space.
|
||||||
|
let fallback_is_needed = match resolved_align_content {
|
||||||
|
_ if remaining_free_cross_space <= Au::zero() => true,
|
||||||
|
AlignFlags::STRETCH => num_lines < 1,
|
||||||
|
AlignFlags::SPACE_BETWEEN | AlignFlags::SPACE_AROUND | AlignFlags::SPACE_EVENLY => {
|
||||||
|
num_lines < 2
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if fallback_is_needed {
|
||||||
|
(resolved_align_content, is_safe) = match resolved_align_content {
|
||||||
|
AlignFlags::STRETCH => (AlignFlags::FLEX_START, true),
|
||||||
|
AlignFlags::SPACE_BETWEEN => (AlignFlags::FLEX_START, true),
|
||||||
|
AlignFlags::SPACE_AROUND => (AlignFlags::CENTER, true),
|
||||||
|
AlignFlags::SPACE_EVENLY => (AlignFlags::CENTER, true),
|
||||||
|
_ => (resolved_align_content, is_safe),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
|
||||||
|
if remaining_free_cross_space <= Au::zero() && is_safe {
|
||||||
|
resolved_align_content = AlignFlags::START;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved_align_content
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
|
||||||
|
let mut cross_start_position_cursor = match resolved_align_content {
|
||||||
|
AlignFlags::START => Au::zero(),
|
||||||
|
AlignFlags::FLEX_START => {
|
||||||
|
if flex_context.flex_wrap_reverse {
|
||||||
|
remaining_free_cross_space
|
||||||
|
} else {
|
||||||
|
Au::zero()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AlignFlags::END => remaining_free_cross_space,
|
||||||
|
AlignFlags::FLEX_END => {
|
||||||
|
if flex_context.flex_wrap_reverse {
|
||||||
|
Au::zero()
|
||||||
|
} else {
|
||||||
|
remaining_free_cross_space
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AlignFlags::CENTER => remaining_free_cross_space / 2,
|
||||||
|
AlignFlags::STRETCH => Au::zero(),
|
||||||
|
AlignFlags::SPACE_BETWEEN => Au::zero(),
|
||||||
|
AlignFlags::SPACE_AROUND => remaining_free_cross_space / num_lines as i32 / 2,
|
||||||
|
AlignFlags::SPACE_EVENLY => remaining_free_cross_space / (num_lines as i32 + 1),
|
||||||
|
|
||||||
|
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
|
||||||
|
_ => Au::zero(),
|
||||||
|
};
|
||||||
|
|
||||||
let mut baseline_alignment_participating_baselines = Baselines::default();
|
let mut baseline_alignment_participating_baselines = Baselines::default();
|
||||||
let mut all_baselines = Baselines::default();
|
let mut all_baselines = Baselines::default();
|
||||||
let num_lines = final_line_layouts.len();
|
let flex_item_fragments: Vec<_> = initial_line_layouts
|
||||||
let mut flex_item_fragments =
|
.into_iter()
|
||||||
izip!(final_line_layouts.into_iter(), line_cross_start_positions)
|
.enumerate()
|
||||||
.enumerate()
|
.flat_map(|(index, initial_line_layout)| {
|
||||||
.flat_map(|(index, (mut line, line_cross_start_position))| {
|
// We call `allocate_free_cross_space_for_flex_line` for each line to avoid having
|
||||||
let flow_relative_line_position = match (flex_axis, flex_wrap_reverse) {
|
// leftover space when the number of lines doesn't evenly divide the total free space,
|
||||||
(FlexAxis::Row, false) => LogicalVec2 {
|
// considering the precision of app units.
|
||||||
block: line_cross_start_position,
|
let (space_to_add_to_line, space_to_add_after_line) =
|
||||||
inline: Au::zero(),
|
allocate_free_cross_space_for_flex_line(
|
||||||
},
|
resolved_align_content,
|
||||||
(FlexAxis::Row, true) => LogicalVec2 {
|
remaining_free_cross_space,
|
||||||
block: container_cross_size -
|
(num_lines - index) as i32,
|
||||||
line_cross_start_position -
|
);
|
||||||
line.cross_size,
|
remaining_free_cross_space -= space_to_add_to_line + space_to_add_after_line;
|
||||||
inline: Au::zero(),
|
|
||||||
},
|
|
||||||
(FlexAxis::Column, false) => LogicalVec2 {
|
|
||||||
block: Au::zero(),
|
|
||||||
inline: line_cross_start_position,
|
|
||||||
},
|
|
||||||
(FlexAxis::Column, true) => LogicalVec2 {
|
|
||||||
block: Au::zero(),
|
|
||||||
inline: container_cross_size -
|
|
||||||
line_cross_start_position -
|
|
||||||
line.cross_size,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let line_shared_alignment_baseline = line
|
let final_line_cross_size =
|
||||||
.shared_alignment_baseline
|
initial_line_layout.line_size.cross + space_to_add_to_line;
|
||||||
.map(|baseline| baseline + flow_relative_line_position.block);
|
let mut final_line_layout = initial_line_layout.finish_with_final_cross_size(
|
||||||
let line_all_baselines =
|
&mut flex_context,
|
||||||
line.all_baselines.offset(flow_relative_line_position.block);
|
main_gap,
|
||||||
if index == 0 {
|
final_line_cross_size,
|
||||||
baseline_alignment_participating_baselines.first =
|
);
|
||||||
line_shared_alignment_baseline;
|
|
||||||
all_baselines.first = line_all_baselines.first;
|
|
||||||
}
|
|
||||||
if index == num_lines - 1 {
|
|
||||||
baseline_alignment_participating_baselines.last =
|
|
||||||
line_shared_alignment_baseline;
|
|
||||||
all_baselines.last = line_all_baselines.last;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (fragment, _) in &mut line.item_fragments {
|
let line_cross_start_position = cross_start_position_cursor;
|
||||||
fragment.content_rect.start_corner += flow_relative_line_position
|
cross_start_position_cursor = line_cross_start_position +
|
||||||
}
|
final_line_cross_size +
|
||||||
line.item_fragments
|
space_to_add_after_line +
|
||||||
});
|
cross_gap;
|
||||||
|
|
||||||
|
let flow_relative_line_position = match (flex_axis, flex_wrap_reverse) {
|
||||||
|
(FlexAxis::Row, false) => LogicalVec2 {
|
||||||
|
block: line_cross_start_position,
|
||||||
|
inline: Au::zero(),
|
||||||
|
},
|
||||||
|
(FlexAxis::Row, true) => LogicalVec2 {
|
||||||
|
block: container_cross_size -
|
||||||
|
line_cross_start_position -
|
||||||
|
final_line_layout.cross_size,
|
||||||
|
inline: Au::zero(),
|
||||||
|
},
|
||||||
|
(FlexAxis::Column, false) => LogicalVec2 {
|
||||||
|
block: Au::zero(),
|
||||||
|
inline: line_cross_start_position,
|
||||||
|
},
|
||||||
|
(FlexAxis::Column, true) => LogicalVec2 {
|
||||||
|
block: Au::zero(),
|
||||||
|
inline: container_cross_size -
|
||||||
|
line_cross_start_position -
|
||||||
|
final_line_cross_size,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let line_shared_alignment_baseline = final_line_layout
|
||||||
|
.shared_alignment_baseline
|
||||||
|
.map(|baseline| baseline + flow_relative_line_position.block);
|
||||||
|
let line_all_baselines = final_line_layout
|
||||||
|
.all_baselines
|
||||||
|
.offset(flow_relative_line_position.block);
|
||||||
|
if index == 0 {
|
||||||
|
baseline_alignment_participating_baselines.first =
|
||||||
|
line_shared_alignment_baseline;
|
||||||
|
all_baselines.first = line_all_baselines.first;
|
||||||
|
}
|
||||||
|
if index == num_lines - 1 {
|
||||||
|
baseline_alignment_participating_baselines.last =
|
||||||
|
line_shared_alignment_baseline;
|
||||||
|
all_baselines.last = line_all_baselines.last;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (fragment, _) in &mut final_line_layout.item_fragments {
|
||||||
|
fragment.content_rect.start_corner += flow_relative_line_position
|
||||||
|
}
|
||||||
|
final_line_layout.item_fragments
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut flex_item_fragments = flex_item_fragments.into_iter();
|
||||||
let fragments = absolutely_positioned_items_with_original_order
|
let fragments = absolutely_positioned_items_with_original_order
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|child_as_abspos| match child_as_abspos {
|
.map(|child_as_abspos| match child_as_abspos {
|
||||||
|
@ -779,6 +755,52 @@ impl FlexContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Align all flex lines per `align-content` according to
|
||||||
|
/// <https://drafts.csswg.org/css-flexbox/#algo-line-align>. Returns the space to add to
|
||||||
|
/// each line or the space to add after each line.
|
||||||
|
fn allocate_free_cross_space_for_flex_line(
|
||||||
|
resolved_align_content: AlignFlags,
|
||||||
|
remaining_free_cross_space: Au,
|
||||||
|
remaining_line_count: i32,
|
||||||
|
) -> (Au, Au) {
|
||||||
|
if remaining_free_cross_space == Au::zero() {
|
||||||
|
return (Au::zero(), Au::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
match resolved_align_content {
|
||||||
|
AlignFlags::START => (Au::zero(), Au::zero()),
|
||||||
|
AlignFlags::FLEX_START => (Au::zero(), Au::zero()),
|
||||||
|
AlignFlags::END => (Au::zero(), Au::zero()),
|
||||||
|
AlignFlags::FLEX_END => (Au::zero(), Au::zero()),
|
||||||
|
AlignFlags::CENTER => (Au::zero(), Au::zero()),
|
||||||
|
AlignFlags::STRETCH => (
|
||||||
|
remaining_free_cross_space / remaining_line_count,
|
||||||
|
Au::zero(),
|
||||||
|
),
|
||||||
|
AlignFlags::SPACE_BETWEEN => {
|
||||||
|
if remaining_line_count > 1 {
|
||||||
|
(
|
||||||
|
Au::zero(),
|
||||||
|
remaining_free_cross_space / (remaining_line_count - 1),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(Au::zero(), Au::zero())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AlignFlags::SPACE_AROUND => (
|
||||||
|
Au::zero(),
|
||||||
|
remaining_free_cross_space / remaining_line_count,
|
||||||
|
),
|
||||||
|
AlignFlags::SPACE_EVENLY => (
|
||||||
|
Au::zero(),
|
||||||
|
remaining_free_cross_space / (remaining_line_count + 1),
|
||||||
|
),
|
||||||
|
|
||||||
|
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
|
||||||
|
_ => (Au::zero(), Au::zero()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> FlexItem<'a> {
|
impl<'a> FlexItem<'a> {
|
||||||
fn new(flex_context: &FlexContext, box_: &'a mut FlexItemBox) -> Self {
|
fn new(flex_context: &FlexContext, box_: &'a mut FlexItemBox) -> Self {
|
||||||
let containing_block = flex_context.containing_block;
|
let containing_block = flex_context.containing_block;
|
||||||
|
@ -1378,8 +1400,6 @@ impl InitialFlexLineLayout<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align the items along the main-axis per justify-content.
|
// Align the items along the main-axis per justify-content.
|
||||||
let layout_is_flex_reversed = flex_context.flex_direction_is_reversed;
|
|
||||||
|
|
||||||
// Implement fallback alignment.
|
// Implement fallback alignment.
|
||||||
//
|
//
|
||||||
// In addition to the spec at https://www.w3.org/TR/css-align-3/ this implementation follows
|
// In addition to the spec at https://www.w3.org/TR/css-align-3/ this implementation follows
|
||||||
|
@ -1417,7 +1437,7 @@ impl InitialFlexLineLayout<'_> {
|
||||||
let main_start_position = match resolved_justify_content {
|
let main_start_position = match resolved_justify_content {
|
||||||
AlignFlags::START => Au::zero(),
|
AlignFlags::START => Au::zero(),
|
||||||
AlignFlags::FLEX_START => {
|
AlignFlags::FLEX_START => {
|
||||||
if layout_is_flex_reversed {
|
if flex_context.flex_direction_is_reversed {
|
||||||
free_space_in_main_axis
|
free_space_in_main_axis
|
||||||
} else {
|
} else {
|
||||||
Au::zero()
|
Au::zero()
|
||||||
|
@ -1425,7 +1445,7 @@ impl InitialFlexLineLayout<'_> {
|
||||||
},
|
},
|
||||||
AlignFlags::END => free_space_in_main_axis,
|
AlignFlags::END => free_space_in_main_axis,
|
||||||
AlignFlags::FLEX_END => {
|
AlignFlags::FLEX_END => {
|
||||||
if layout_is_flex_reversed {
|
if flex_context.flex_direction_is_reversed {
|
||||||
Au::zero()
|
Au::zero()
|
||||||
} else {
|
} else {
|
||||||
free_space_in_main_axis
|
free_space_in_main_axis
|
||||||
|
|
7
tests/wpt/mozilla/meta/MANIFEST.json
vendored
7
tests/wpt/mozilla/meta/MANIFEST.json
vendored
|
@ -12462,6 +12462,13 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"flex_align_content_stretch_subpixel.html": [
|
||||||
|
"0a08f2540b6cc736d274c7f0b48f2f6123dd1862",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"float-abspos.html": [
|
"float-abspos.html": [
|
||||||
"f691c1756f0dd5b6744952e1516950bacaaf4d33",
|
"f691c1756f0dd5b6744952e1516950bacaaf4d33",
|
||||||
[
|
[
|
||||||
|
|
2
tests/wpt/mozilla/meta/css/flex_align_content_stretch_subpixel.html.ini
vendored
Normal file
2
tests/wpt/mozilla/meta/css/flex_align_content_stretch_subpixel.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[flex_align_content_stretch_subpixel.html]
|
||||||
|
prefs: ["layout.flexbox.enabled:true"]
|
36
tests/wpt/mozilla/tests/css/flex_align_content_stretch_subpixel.html
vendored
Normal file
36
tests/wpt/mozilla/tests/css/flex_align_content_stretch_subpixel.html
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Flex: align-content:stretch with subpixel amounts</title>
|
||||||
|
<style>
|
||||||
|
#flex {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: stretch;
|
||||||
|
height: 5px;
|
||||||
|
border: solid;
|
||||||
|
}
|
||||||
|
#flex > div {
|
||||||
|
width: 100%;
|
||||||
|
outline: 1px solid lime;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="flex"></div>
|
||||||
|
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
/* The flex container is 5px tall. Assuming that 1px are 60 app units,
|
||||||
|
that's 300 app units. Since we have 600 lines, half of them should
|
||||||
|
get 1 app unit, and the others should get 0. This way we ensure that
|
||||||
|
the container gets filled completely. */
|
||||||
|
let flex = document.getElementById("flex");
|
||||||
|
let item = document.createElement("div");
|
||||||
|
for (let i = 0; i < 600; ++i) {
|
||||||
|
flex.appendChild(item.cloneNode());
|
||||||
|
}
|
||||||
|
test(() => {
|
||||||
|
let filled_space = flex.lastElementChild.getBoundingClientRect().bottom
|
||||||
|
- flex.firstElementChild.getBoundingClientRect().top;
|
||||||
|
assert_approx_equals(filled_space, 5, 0.01);
|
||||||
|
}, "Flex items fill the container entirely");
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue