mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
layout: Unify logic for laying out replaced and non-replaced in a BFC (#37864)
The logic for laying out block-level replaced elements wasn't taking floats into account when resolving a `stretch` inline size. By handling them with the same logic as non-replaced elements, we fix that problem, and reduce the amount of code. Testing: Adding new tests Fixes: #37861 Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
72b1331949
commit
4ee7a34f32
8 changed files with 257 additions and 252 deletions
|
@ -2147,7 +2147,7 @@ impl FlexItem<'_> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_table(&self) -> bool {
|
fn is_table(&self) -> bool {
|
||||||
self.box_.is_table()
|
self.box_.independent_formatting_context.is_table()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2225,7 +2225,7 @@ impl FlexItemBox {
|
||||||
.map(|v| Au::zero().max(v - pbm_auto_is_zero.cross)),
|
.map(|v| Au::zero().max(v - pbm_auto_is_zero.cross)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_table = self.is_table();
|
let is_table = self.independent_formatting_context.is_table();
|
||||||
let tentative_cross_content_size = if cross_axis_is_item_block_axis {
|
let tentative_cross_content_size = if cross_axis_is_item_block_axis {
|
||||||
self.independent_formatting_context
|
self.independent_formatting_context
|
||||||
.tentative_block_content_size(preferred_aspect_ratio)
|
.tentative_block_content_size(preferred_aspect_ratio)
|
||||||
|
@ -2718,12 +2718,4 @@ impl FlexItemBox {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_table(&self) -> bool {
|
|
||||||
match &self.independent_formatting_context.contents {
|
|
||||||
IndependentFormattingContextContents::NonReplaced(content) => content.is_table(),
|
|
||||||
IndependentFormattingContextContents::Replaced(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1066,36 +1066,6 @@ impl SequentialLayoutState {
|
||||||
.map(|offset| offset - self.position_with_zero_clearance(block_start_margin))
|
.map(|offset| offset - self.position_with_zero_clearance(block_start_margin))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A block that is replaced or establishes an independent formatting context can't overlap floats,
|
|
||||||
/// it has to be placed next to them, and may get some clearance if there isn't enough space.
|
|
||||||
/// Given such a block with the provided 'clear', 'block_start_margin', 'pbm' and 'object_size',
|
|
||||||
/// this method finds an area that is big enough and doesn't overlap floats.
|
|
||||||
/// It returns a tuple with:
|
|
||||||
/// - The clearance amount (if any), which includes both the effect of 'clear'
|
|
||||||
/// and the extra space to avoid floats.
|
|
||||||
/// - The LogicalRect in which the block can be placed without overlapping floats.
|
|
||||||
pub(crate) fn calculate_clearance_and_inline_adjustment(
|
|
||||||
&self,
|
|
||||||
clear: Clear,
|
|
||||||
block_start_margin: &CollapsedMargin,
|
|
||||||
pbm: &PaddingBorderMargin,
|
|
||||||
object_size: LogicalVec2<Au>,
|
|
||||||
) -> (Option<Au>, LogicalRect<Au>) {
|
|
||||||
// First compute the clear position required by the 'clear' property.
|
|
||||||
// The code below may then add extra clearance when the element can't fit
|
|
||||||
// next to floats not covered by 'clear'.
|
|
||||||
let clear_position = self.calculate_clear_position(clear, block_start_margin);
|
|
||||||
let ceiling =
|
|
||||||
clear_position.unwrap_or_else(|| self.position_without_clearance(block_start_margin));
|
|
||||||
let mut placement = PlacementAmongFloats::new(&self.floats, ceiling, object_size, pbm);
|
|
||||||
let placement_rect = placement.place();
|
|
||||||
let position = &placement_rect.start_corner;
|
|
||||||
let has_clearance = clear_position.is_some() || position.block > ceiling;
|
|
||||||
let clearance = has_clearance
|
|
||||||
.then(|| position.block - self.position_with_zero_clearance(block_start_margin));
|
|
||||||
(clearance, placement_rect)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a new adjoining margin.
|
/// Adds a new adjoining margin.
|
||||||
pub(crate) fn adjoin_assign(&mut self, margin: &CollapsedMargin) {
|
pub(crate) fn adjoin_assign(&mut self, margin: &CollapsedMargin) {
|
||||||
self.current_margin.adjoin_assign(margin)
|
self.current_margin.adjoin_assign(margin)
|
||||||
|
|
|
@ -30,7 +30,6 @@ use crate::flow::float::{
|
||||||
};
|
};
|
||||||
use crate::formatting_contexts::{
|
use crate::formatting_contexts::{
|
||||||
Baselines, IndependentFormattingContext, IndependentFormattingContextContents,
|
Baselines, IndependentFormattingContext, IndependentFormattingContextContents,
|
||||||
IndependentNonReplacedContents,
|
|
||||||
};
|
};
|
||||||
use crate::fragment_tree::{
|
use crate::fragment_tree::{
|
||||||
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
|
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
|
||||||
|
@ -41,9 +40,8 @@ use crate::geom::{
|
||||||
};
|
};
|
||||||
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
||||||
use crate::replaced::ReplacedContents;
|
|
||||||
use crate::sizing::{self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
||||||
use crate::style_ext::{ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin};
|
use crate::style_ext::{AspectRatio, ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin};
|
||||||
use crate::{
|
use crate::{
|
||||||
ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock,
|
ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock,
|
||||||
SizeConstraint,
|
SizeConstraint,
|
||||||
|
@ -956,11 +954,13 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
|
||||||
depends_on_block_constraints,
|
depends_on_block_constraints,
|
||||||
available_block_size,
|
available_block_size,
|
||||||
justify_self,
|
justify_self,
|
||||||
|
..
|
||||||
} = solve_containing_block_padding_and_border_for_in_flow_box(
|
} = solve_containing_block_padding_and_border_for_in_flow_box(
|
||||||
containing_block,
|
containing_block,
|
||||||
&layout_style,
|
&layout_style,
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
ignore_block_margins_for_stretch,
|
ignore_block_margins_for_stretch,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
let ResolvedMargins {
|
let ResolvedMargins {
|
||||||
margin,
|
margin,
|
||||||
|
@ -1178,15 +1178,16 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
|
||||||
.with_block_margins_collapsed_with_children(block_margins_collapsed_with_children)
|
.with_block_margins_collapsed_with_children(block_margins_collapsed_with_children)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndependentNonReplacedContents {
|
impl IndependentFormattingContext {
|
||||||
/// Lay out a normal in flow non-replaced block that establishes an independent
|
/// Lay out an in-flow block-level box that establishes an independent
|
||||||
/// formatting context in its containing formatting context.
|
/// formatting context in its containing formatting context.
|
||||||
///
|
///
|
||||||
/// - <https://drafts.csswg.org/css2/visudet.html#blockwidth>
|
/// - <https://drafts.csswg.org/css2/visudet.html#blockwidth>
|
||||||
|
/// - <https://drafts.csswg.org/css2/visudet.html#block-replaced-width>
|
||||||
/// - <https://drafts.csswg.org/css2/visudet.html#normal-block>
|
/// - <https://drafts.csswg.org/css2/visudet.html#normal-block>
|
||||||
|
/// - <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
|
||||||
pub(crate) fn layout_in_flow_block_level(
|
pub(crate) fn layout_in_flow_block_level(
|
||||||
&self,
|
&self,
|
||||||
base: &LayoutBoxBase,
|
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
positioning_context: &mut PositioningContext,
|
positioning_context: &mut PositioningContext,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
|
@ -1195,7 +1196,6 @@ impl IndependentNonReplacedContents {
|
||||||
) -> BoxFragment {
|
) -> BoxFragment {
|
||||||
if let Some(sequential_layout_state) = sequential_layout_state {
|
if let Some(sequential_layout_state) = sequential_layout_state {
|
||||||
return self.layout_in_flow_block_level_sequentially(
|
return self.layout_in_flow_block_level_sequentially(
|
||||||
base,
|
|
||||||
layout_context,
|
layout_context,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
containing_block,
|
containing_block,
|
||||||
|
@ -1205,10 +1205,10 @@ impl IndependentNonReplacedContents {
|
||||||
}
|
}
|
||||||
|
|
||||||
let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
|
let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
|
||||||
base.inline_content_sizes(layout_context, constraint_space, self)
|
self.inline_content_sizes(layout_context, constraint_space)
|
||||||
.sizes
|
.sizes
|
||||||
};
|
};
|
||||||
let layout_style = self.layout_style(base);
|
let layout_style = self.layout_style();
|
||||||
let ContainingBlockPaddingAndBorder {
|
let ContainingBlockPaddingAndBorder {
|
||||||
containing_block: containing_block_for_children,
|
containing_block: containing_block_for_children,
|
||||||
pbm,
|
pbm,
|
||||||
|
@ -1216,11 +1216,13 @@ impl IndependentNonReplacedContents {
|
||||||
depends_on_block_constraints,
|
depends_on_block_constraints,
|
||||||
available_block_size,
|
available_block_size,
|
||||||
justify_self,
|
justify_self,
|
||||||
|
preferred_aspect_ratio,
|
||||||
} = solve_containing_block_padding_and_border_for_in_flow_box(
|
} = solve_containing_block_padding_and_border_for_in_flow_box(
|
||||||
containing_block,
|
containing_block,
|
||||||
&layout_style,
|
&layout_style,
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
ignore_block_margins_for_stretch,
|
ignore_block_margins_for_stretch,
|
||||||
|
Some(self),
|
||||||
);
|
);
|
||||||
|
|
||||||
let lazy_block_size = LazySize::new(
|
let lazy_block_size = LazySize::new(
|
||||||
|
@ -1237,7 +1239,7 @@ impl IndependentNonReplacedContents {
|
||||||
positioning_context,
|
positioning_context,
|
||||||
&containing_block_for_children,
|
&containing_block_for_children,
|
||||||
containing_block,
|
containing_block,
|
||||||
base,
|
preferred_aspect_ratio,
|
||||||
false, /* depends_on_block_constraints */
|
false, /* depends_on_block_constraints */
|
||||||
&lazy_block_size,
|
&lazy_block_size,
|
||||||
);
|
);
|
||||||
|
@ -1268,7 +1270,7 @@ impl IndependentNonReplacedContents {
|
||||||
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||||
|
|
||||||
let mut base_fragment_info = base.base_fragment_info;
|
let mut base_fragment_info = self.base.base_fragment_info;
|
||||||
if depends_on_block_constraints {
|
if depends_on_block_constraints {
|
||||||
base_fragment_info.flags.insert(
|
base_fragment_info.flags.insert(
|
||||||
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
@ -1276,7 +1278,7 @@ impl IndependentNonReplacedContents {
|
||||||
}
|
}
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
base_fragment_info,
|
base_fragment_info,
|
||||||
base.style.clone(),
|
self.base.style.clone(),
|
||||||
layout.fragments,
|
layout.fragments,
|
||||||
content_rect.as_physical(Some(containing_block)),
|
content_rect.as_physical(Some(containing_block)),
|
||||||
pbm.padding.to_physical(containing_block_writing_mode),
|
pbm.padding.to_physical(containing_block_writing_mode),
|
||||||
|
@ -1294,14 +1296,13 @@ impl IndependentNonReplacedContents {
|
||||||
/// layout concerns, such clearing and placing the content next to floats.
|
/// layout concerns, such clearing and placing the content next to floats.
|
||||||
fn layout_in_flow_block_level_sequentially(
|
fn layout_in_flow_block_level_sequentially(
|
||||||
&self,
|
&self,
|
||||||
base: &LayoutBoxBase,
|
|
||||||
layout_context: &LayoutContext<'_>,
|
layout_context: &LayoutContext<'_>,
|
||||||
positioning_context: &mut PositioningContext,
|
positioning_context: &mut PositioningContext,
|
||||||
containing_block: &ContainingBlock<'_>,
|
containing_block: &ContainingBlock<'_>,
|
||||||
sequential_layout_state: &mut SequentialLayoutState,
|
sequential_layout_state: &mut SequentialLayoutState,
|
||||||
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
|
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
|
||||||
) -> BoxFragment {
|
) -> BoxFragment {
|
||||||
let style = &base.style;
|
let style = &self.base.style;
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||||
let ContentBoxSizesAndPBM {
|
let ContentBoxSizesAndPBM {
|
||||||
content_box_sizes,
|
content_box_sizes,
|
||||||
|
@ -1309,7 +1310,7 @@ impl IndependentNonReplacedContents {
|
||||||
depends_on_block_constraints,
|
depends_on_block_constraints,
|
||||||
..
|
..
|
||||||
} = self
|
} = self
|
||||||
.layout_style(base)
|
.layout_style()
|
||||||
.content_box_sizes_and_padding_border_margin(&containing_block.into());
|
.content_box_sizes_and_padding_border_margin(&containing_block.into());
|
||||||
|
|
||||||
let (margin_block_start, margin_block_end) =
|
let (margin_block_start, margin_block_end) =
|
||||||
|
@ -1341,16 +1342,34 @@ impl IndependentNonReplacedContents {
|
||||||
sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
|
sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then compute a tentative block size, only taking extrinsic values into account.
|
// Then compute a tentative block size.
|
||||||
let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
|
let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
|
||||||
let available_block_size = containing_block
|
let available_block_size = containing_block
|
||||||
.size
|
.size
|
||||||
.block
|
.block
|
||||||
.to_definite()
|
.to_definite()
|
||||||
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
|
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
|
||||||
let (preferred_block_size, min_block_size, max_block_size) = content_box_sizes
|
let is_table = self.is_table();
|
||||||
.block
|
let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
|
||||||
.resolve_each_extrinsic(Size::FitContent, Au::zero(), available_block_size);
|
let tentative_block_content_size =
|
||||||
|
self.tentative_block_content_size(preferred_aspect_ratio);
|
||||||
|
let (preferred_block_size, min_block_size, max_block_size) =
|
||||||
|
if let Some(block_content_size) = tentative_block_content_size {
|
||||||
|
let (preferred, min, max) = content_box_sizes.block.resolve_each(
|
||||||
|
Size::FitContent,
|
||||||
|
Au::zero,
|
||||||
|
available_block_size,
|
||||||
|
|| block_content_size,
|
||||||
|
is_table,
|
||||||
|
);
|
||||||
|
(Some(preferred), min, max)
|
||||||
|
} else {
|
||||||
|
content_box_sizes.block.resolve_each_extrinsic(
|
||||||
|
Size::FitContent,
|
||||||
|
Au::zero(),
|
||||||
|
available_block_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
let tentative_block_size =
|
let tentative_block_size =
|
||||||
SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
|
SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
|
||||||
|
|
||||||
|
@ -1359,18 +1378,18 @@ impl IndependentNonReplacedContents {
|
||||||
let constraint_space = ConstraintSpace::new(
|
let constraint_space = ConstraintSpace::new(
|
||||||
tentative_block_size,
|
tentative_block_size,
|
||||||
style.writing_mode,
|
style.writing_mode,
|
||||||
self.preferred_aspect_ratio(),
|
preferred_aspect_ratio,
|
||||||
);
|
);
|
||||||
base.inline_content_sizes(layout_context, &constraint_space, self)
|
self.inline_content_sizes(layout_context, &constraint_space)
|
||||||
.sizes
|
.sizes
|
||||||
};
|
};
|
||||||
|
|
||||||
let justify_self = resolve_justify_self(style, containing_block.style);
|
let justify_self = resolve_justify_self(style, containing_block.style);
|
||||||
let is_table = self.is_table();
|
let is_replaced = self.is_replaced();
|
||||||
let compute_inline_size = |stretch_size| {
|
let compute_inline_size = |stretch_size| {
|
||||||
content_box_sizes.inline.resolve(
|
content_box_sizes.inline.resolve(
|
||||||
Direction::Inline,
|
Direction::Inline,
|
||||||
automatic_inline_size(justify_self, is_table),
|
automatic_inline_size(justify_self, is_table, is_replaced),
|
||||||
Au::zero,
|
Au::zero,
|
||||||
Some(stretch_size),
|
Some(stretch_size),
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
|
@ -1412,7 +1431,7 @@ impl IndependentNonReplacedContents {
|
||||||
style,
|
style,
|
||||||
},
|
},
|
||||||
containing_block,
|
containing_block,
|
||||||
base,
|
preferred_aspect_ratio,
|
||||||
false, /* depends_on_block_constraints */
|
false, /* depends_on_block_constraints */
|
||||||
&lazy_block_size,
|
&lazy_block_size,
|
||||||
);
|
);
|
||||||
|
@ -1478,7 +1497,7 @@ impl IndependentNonReplacedContents {
|
||||||
style,
|
style,
|
||||||
},
|
},
|
||||||
containing_block,
|
containing_block,
|
||||||
base,
|
preferred_aspect_ratio,
|
||||||
false, /* depends_on_block_constraints */
|
false, /* depends_on_block_constraints */
|
||||||
&lazy_block_size,
|
&lazy_block_size,
|
||||||
);
|
);
|
||||||
|
@ -1568,7 +1587,7 @@ impl IndependentNonReplacedContents {
|
||||||
size: content_size,
|
size: content_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut base_fragment_info = base.base_fragment_info;
|
let mut base_fragment_info = self.base.base_fragment_info;
|
||||||
if depends_on_block_constraints {
|
if depends_on_block_constraints {
|
||||||
base_fragment_info.flags.insert(
|
base_fragment_info.flags.insert(
|
||||||
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
@ -1591,144 +1610,6 @@ impl IndependentNonReplacedContents {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReplacedContents {
|
|
||||||
/// <https://drafts.csswg.org/css2/visudet.html#block-replaced-width>
|
|
||||||
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-width>
|
|
||||||
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
|
|
||||||
fn layout_in_flow_block_level(
|
|
||||||
&self,
|
|
||||||
base: &LayoutBoxBase,
|
|
||||||
layout_context: &LayoutContext,
|
|
||||||
containing_block: &ContainingBlock,
|
|
||||||
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
|
|
||||||
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
|
|
||||||
) -> BoxFragment {
|
|
||||||
let content_box_sizes_and_pbm = self
|
|
||||||
.layout_style(base)
|
|
||||||
.content_box_sizes_and_padding_border_margin(&containing_block.into());
|
|
||||||
let pbm = &content_box_sizes_and_pbm.pbm;
|
|
||||||
let content_size = self.used_size_as_if_inline_element(
|
|
||||||
containing_block,
|
|
||||||
&base.style,
|
|
||||||
&content_box_sizes_and_pbm,
|
|
||||||
ignore_block_margins_for_stretch,
|
|
||||||
);
|
|
||||||
|
|
||||||
let margin_inline_start;
|
|
||||||
let margin_inline_end;
|
|
||||||
let effective_margin_inline_start;
|
|
||||||
let (margin_block_start, margin_block_end) =
|
|
||||||
solve_block_margins_for_in_flow_block_level(pbm);
|
|
||||||
let justify_self = resolve_justify_self(&base.style, containing_block.style);
|
|
||||||
|
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
|
||||||
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
|
|
||||||
let fragments = self.make_fragments(layout_context, &base.style, physical_content_size);
|
|
||||||
|
|
||||||
let clearance;
|
|
||||||
if let Some(ref mut sequential_layout_state) = sequential_layout_state {
|
|
||||||
// From https://drafts.csswg.org/css2/#floats:
|
|
||||||
// "The border box of a table, a block-level replaced element, or an element in
|
|
||||||
// the normal flow that establishes a new block formatting context (such as an
|
|
||||||
// element with overflow other than visible) must not overlap the margin box of
|
|
||||||
// any floats in the same block formatting context as the element itself. If
|
|
||||||
// necessary, implementations should clear the said element by placing it below
|
|
||||||
// any preceding floats, but may place it adjacent to such floats if there is
|
|
||||||
// sufficient space. They may even make the border box of said element narrower
|
|
||||||
// than defined by section 10.3.3. CSS 2 does not define when a UA may put said
|
|
||||||
// element next to the float or by how much said element may become narrower."
|
|
||||||
let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
|
|
||||||
let size = content_size + pbm.padding_border_sums;
|
|
||||||
let placement_rect;
|
|
||||||
(clearance, placement_rect) = sequential_layout_state
|
|
||||||
.calculate_clearance_and_inline_adjustment(
|
|
||||||
Clear::from_style_and_container_writing_mode(
|
|
||||||
&base.style,
|
|
||||||
containing_block.style.writing_mode,
|
|
||||||
),
|
|
||||||
&collapsed_margin_block_start,
|
|
||||||
pbm,
|
|
||||||
size,
|
|
||||||
);
|
|
||||||
(
|
|
||||||
(margin_inline_start, margin_inline_end),
|
|
||||||
effective_margin_inline_start,
|
|
||||||
) = solve_inline_margins_avoiding_floats(
|
|
||||||
sequential_layout_state,
|
|
||||||
containing_block,
|
|
||||||
pbm,
|
|
||||||
size.inline,
|
|
||||||
placement_rect,
|
|
||||||
justify_self,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Clearance prevents margin collapse between this block and previous ones,
|
|
||||||
// so in that case collapse margins before adjoining them below.
|
|
||||||
if clearance.is_some() {
|
|
||||||
sequential_layout_state.collapse_margins();
|
|
||||||
}
|
|
||||||
sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
|
|
||||||
|
|
||||||
// Margins can never collapse into replaced elements.
|
|
||||||
sequential_layout_state.collapse_margins();
|
|
||||||
sequential_layout_state
|
|
||||||
.advance_block_position(size.block + clearance.unwrap_or_else(Au::zero));
|
|
||||||
sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end));
|
|
||||||
} else {
|
|
||||||
clearance = None;
|
|
||||||
(
|
|
||||||
(margin_inline_start, margin_inline_end),
|
|
||||||
effective_margin_inline_start,
|
|
||||||
) = solve_inline_margins_for_in_flow_block_level(
|
|
||||||
containing_block,
|
|
||||||
pbm,
|
|
||||||
content_size.inline,
|
|
||||||
justify_self,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let margin = LogicalSides {
|
|
||||||
inline_start: margin_inline_start,
|
|
||||||
inline_end: margin_inline_end,
|
|
||||||
block_start: margin_block_start,
|
|
||||||
block_end: margin_block_end,
|
|
||||||
};
|
|
||||||
|
|
||||||
let start_corner = LogicalVec2 {
|
|
||||||
block: pbm.padding.block_start +
|
|
||||||
pbm.border.block_start +
|
|
||||||
clearance.unwrap_or_else(Au::zero),
|
|
||||||
inline: pbm.padding.inline_start +
|
|
||||||
pbm.border.inline_start +
|
|
||||||
effective_margin_inline_start,
|
|
||||||
};
|
|
||||||
let content_rect = LogicalRect {
|
|
||||||
start_corner,
|
|
||||||
size: content_size,
|
|
||||||
}
|
|
||||||
.as_physical(Some(containing_block));
|
|
||||||
|
|
||||||
let mut base_fragment_info = base.base_fragment_info;
|
|
||||||
if content_box_sizes_and_pbm.depends_on_block_constraints {
|
|
||||||
base_fragment_info.flags.insert(
|
|
||||||
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxFragment::new(
|
|
||||||
base_fragment_info,
|
|
||||||
base.style.clone(),
|
|
||||||
fragments,
|
|
||||||
content_rect,
|
|
||||||
pbm.padding.to_physical(containing_block_writing_mode),
|
|
||||||
pbm.border.to_physical(containing_block_writing_mode),
|
|
||||||
margin.to_physical(containing_block_writing_mode),
|
|
||||||
clearance,
|
|
||||||
)
|
|
||||||
.with_block_margins_collapsed_with_children(CollapsedBlockMargins::from_margin(&margin))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContainingBlockPaddingAndBorder<'a> {
|
struct ContainingBlockPaddingAndBorder<'a> {
|
||||||
containing_block: ContainingBlock<'a>,
|
containing_block: ContainingBlock<'a>,
|
||||||
pbm: PaddingBorderMargin,
|
pbm: PaddingBorderMargin,
|
||||||
|
@ -1736,6 +1617,7 @@ struct ContainingBlockPaddingAndBorder<'a> {
|
||||||
depends_on_block_constraints: bool,
|
depends_on_block_constraints: bool,
|
||||||
available_block_size: Option<Au>,
|
available_block_size: Option<Au>,
|
||||||
justify_self: AlignFlags,
|
justify_self: AlignFlags,
|
||||||
|
preferred_aspect_ratio: Option<AspectRatio>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ResolvedMargins {
|
struct ResolvedMargins {
|
||||||
|
@ -1761,6 +1643,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
layout_style: &'a LayoutStyle,
|
layout_style: &'a LayoutStyle,
|
||||||
get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
|
get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
|
||||||
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
|
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
|
||||||
|
context: Option<&IndependentFormattingContext>,
|
||||||
) -> ContainingBlockPaddingAndBorder<'a> {
|
) -> ContainingBlockPaddingAndBorder<'a> {
|
||||||
let style = layout_style.style();
|
let style = layout_style.style();
|
||||||
if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
|
if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
|
||||||
|
@ -1787,6 +1670,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
// The initial `justify-self` is `auto`, but use `normal` (behaving as `stretch`).
|
// The initial `justify-self` is `auto`, but use `normal` (behaving as `stretch`).
|
||||||
// This is being discussed in <https://github.com/w3c/csswg-drafts/issues/11461>.
|
// This is being discussed in <https://github.com/w3c/csswg-drafts/issues/11461>.
|
||||||
justify_self: AlignFlags::NORMAL,
|
justify_self: AlignFlags::NORMAL,
|
||||||
|
preferred_aspect_ratio: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1806,13 +1690,32 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
.to_definite()
|
.to_definite()
|
||||||
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
|
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
|
||||||
|
|
||||||
|
// TODO: support preferred aspect ratios on boxes that don't establish an independent
|
||||||
|
// formatting context.
|
||||||
|
let preferred_aspect_ratio =
|
||||||
|
context.and_then(|context| context.preferred_aspect_ratio(&pbm.padding_border_sums));
|
||||||
|
let is_table = layout_style.is_table();
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/#the-height-property
|
// https://drafts.csswg.org/css2/#the-height-property
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
|
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
|
||||||
let tentative_block_size = content_box_sizes.block.resolve_extrinsic(
|
let tentative_block_content_size =
|
||||||
Size::FitContent,
|
context.and_then(|context| context.tentative_block_content_size(preferred_aspect_ratio));
|
||||||
Au::zero(),
|
let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
|
||||||
available_block_size,
|
SizeConstraint::Definite(content_box_sizes.block.resolve(
|
||||||
);
|
Direction::Block,
|
||||||
|
Size::FitContent,
|
||||||
|
Au::zero,
|
||||||
|
available_block_size,
|
||||||
|
|| block_content_size,
|
||||||
|
is_table,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
content_box_sizes.block.resolve_extrinsic(
|
||||||
|
Size::FitContent,
|
||||||
|
Au::zero(),
|
||||||
|
available_block_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/#the-width-property
|
// https://drafts.csswg.org/css2/#the-width-property
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
||||||
|
@ -1820,14 +1723,14 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
get_inline_content_sizes(&ConstraintSpace::new(
|
get_inline_content_sizes(&ConstraintSpace::new(
|
||||||
tentative_block_size,
|
tentative_block_size,
|
||||||
writing_mode,
|
writing_mode,
|
||||||
None, /* TODO: support preferred aspect ratios on non-replaced boxes */
|
preferred_aspect_ratio,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
let justify_self = resolve_justify_self(style, containing_block.style);
|
let justify_self = resolve_justify_self(style, containing_block.style);
|
||||||
let is_table = layout_style.is_table();
|
let is_replaced = context.is_some_and(|context| context.is_replaced());
|
||||||
let inline_size = content_box_sizes.inline.resolve(
|
let inline_size = content_box_sizes.inline.resolve(
|
||||||
Direction::Inline,
|
Direction::Inline,
|
||||||
automatic_inline_size(justify_self, is_table),
|
automatic_inline_size(justify_self, is_table, is_replaced),
|
||||||
Au::zero,
|
Au::zero,
|
||||||
Some(available_inline_size),
|
Some(available_inline_size),
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
|
@ -1857,6 +1760,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
depends_on_block_constraints,
|
depends_on_block_constraints,
|
||||||
available_block_size,
|
available_block_size,
|
||||||
justify_self,
|
justify_self,
|
||||||
|
preferred_aspect_ratio,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1923,10 +1827,14 @@ fn resolve_justify_self(style: &ComputedValues, parent_style: &ComputedValues) -
|
||||||
/// Determines the automatic size for the inline axis of a block-level box.
|
/// Determines the automatic size for the inline axis of a block-level box.
|
||||||
/// <https://drafts.csswg.org/css-sizing-3/#automatic-size>
|
/// <https://drafts.csswg.org/css-sizing-3/#automatic-size>
|
||||||
#[inline]
|
#[inline]
|
||||||
fn automatic_inline_size<T>(justify_self: AlignFlags, is_table: bool) -> Size<T> {
|
fn automatic_inline_size<T>(
|
||||||
|
justify_self: AlignFlags,
|
||||||
|
is_table: bool,
|
||||||
|
is_replaced: bool,
|
||||||
|
) -> Size<T> {
|
||||||
match justify_self {
|
match justify_self {
|
||||||
AlignFlags::STRETCH => Size::Stretch,
|
AlignFlags::STRETCH => Size::Stretch,
|
||||||
AlignFlags::NORMAL if !is_table => Size::Stretch,
|
AlignFlags::NORMAL if !is_table && !is_replaced => Size::Stretch,
|
||||||
_ => Size::FitContent,
|
_ => Size::FitContent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2318,34 +2226,6 @@ pub(crate) struct IndependentFloatOrAtomicLayoutResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndependentFormattingContext {
|
impl IndependentFormattingContext {
|
||||||
pub(crate) fn layout_in_flow_block_level(
|
|
||||||
&self,
|
|
||||||
layout_context: &LayoutContext,
|
|
||||||
positioning_context: &mut PositioningContext,
|
|
||||||
containing_block: &ContainingBlock,
|
|
||||||
sequential_layout_state: Option<&mut SequentialLayoutState>,
|
|
||||||
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
|
|
||||||
) -> BoxFragment {
|
|
||||||
match &self.contents {
|
|
||||||
IndependentFormattingContextContents::NonReplaced(contents) => contents
|
|
||||||
.layout_in_flow_block_level(
|
|
||||||
&self.base,
|
|
||||||
layout_context,
|
|
||||||
positioning_context,
|
|
||||||
containing_block,
|
|
||||||
sequential_layout_state,
|
|
||||||
ignore_block_margins_for_stretch,
|
|
||||||
),
|
|
||||||
IndependentFormattingContextContents::Replaced(contents) => contents
|
|
||||||
.layout_in_flow_block_level(
|
|
||||||
&self.base,
|
|
||||||
layout_context,
|
|
||||||
containing_block,
|
|
||||||
sequential_layout_state,
|
|
||||||
ignore_block_margins_for_stretch,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub(crate) fn layout_float_or_atomic_inline(
|
pub(crate) fn layout_float_or_atomic_inline(
|
||||||
&self,
|
&self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
|
|
|
@ -265,6 +265,48 @@ impl IndependentFormattingContext {
|
||||||
IndependentFormattingContextContents::Replaced(..) => {},
|
IndependentFormattingContextContents::Replaced(..) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(crate) fn layout(
|
||||||
|
&self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
positioning_context: &mut PositioningContext,
|
||||||
|
containing_block_for_children: &ContainingBlock,
|
||||||
|
containing_block: &ContainingBlock,
|
||||||
|
preferred_aspect_ratio: Option<AspectRatio>,
|
||||||
|
depends_on_block_constraints: bool,
|
||||||
|
lazy_block_size: &LazySize,
|
||||||
|
) -> CacheableLayoutResult {
|
||||||
|
match &self.contents {
|
||||||
|
IndependentFormattingContextContents::NonReplaced(content) => content.layout(
|
||||||
|
layout_context,
|
||||||
|
positioning_context,
|
||||||
|
containing_block_for_children,
|
||||||
|
containing_block,
|
||||||
|
&self.base,
|
||||||
|
depends_on_block_constraints,
|
||||||
|
lazy_block_size,
|
||||||
|
),
|
||||||
|
IndependentFormattingContextContents::Replaced(content) => content.layout(
|
||||||
|
layout_context,
|
||||||
|
containing_block_for_children,
|
||||||
|
preferred_aspect_ratio,
|
||||||
|
&self.base,
|
||||||
|
depends_on_block_constraints,
|
||||||
|
lazy_block_size,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_table(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
&self.contents,
|
||||||
|
IndependentFormattingContextContents::NonReplaced(
|
||||||
|
IndependentNonReplacedContents::Table(_)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndependentNonReplacedContents {
|
impl IndependentNonReplacedContents {
|
||||||
|
@ -312,7 +354,7 @@ impl IndependentNonReplacedContents {
|
||||||
skip_all
|
skip_all
|
||||||
)]
|
)]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn layout(
|
pub(crate) fn layout(
|
||||||
&self,
|
&self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
positioning_context: &mut PositioningContext,
|
positioning_context: &mut PositioningContext,
|
||||||
|
@ -378,11 +420,6 @@ impl IndependentNonReplacedContents {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn is_table(&self) -> bool {
|
|
||||||
matches!(self, Self::Table(_))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn repair_style(
|
fn repair_style(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &SharedStyleContext,
|
context: &SharedStyleContext,
|
||||||
|
|
|
@ -26,11 +26,13 @@ use webrender_api::ImageKey;
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::{LayoutContext, LayoutImageCacheResult};
|
use crate::context::{LayoutContext, LayoutImageCacheResult};
|
||||||
use crate::dom::NodeExt;
|
use crate::dom::NodeExt;
|
||||||
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
|
use crate::fragment_tree::{
|
||||||
use crate::geom::{
|
BaseFragmentInfo, CollapsedBlockMargins, Fragment, IFrameFragment, ImageFragment,
|
||||||
LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size, Sizes,
|
|
||||||
};
|
};
|
||||||
use crate::layout_box_base::LayoutBoxBase;
|
use crate::geom::{
|
||||||
|
LazySize, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size, Sizes,
|
||||||
|
};
|
||||||
|
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
||||||
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
||||||
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle};
|
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle};
|
||||||
use crate::{ConstraintSpace, ContainingBlock, SizeConstraint};
|
use crate::{ConstraintSpace, ContainingBlock, SizeConstraint};
|
||||||
|
@ -598,6 +600,40 @@ impl ReplacedContents {
|
||||||
pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
|
pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
|
||||||
LayoutStyle::Default(&base.style)
|
LayoutStyle::Default(&base.style)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn layout(
|
||||||
|
&self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
containing_block_for_children: &ContainingBlock,
|
||||||
|
preferred_aspect_ratio: Option<AspectRatio>,
|
||||||
|
base: &LayoutBoxBase,
|
||||||
|
depends_on_block_constraints: bool,
|
||||||
|
lazy_block_size: &LazySize,
|
||||||
|
) -> CacheableLayoutResult {
|
||||||
|
// TODO: consider caching the result in LayoutBoxBase like we do for non-replaced.
|
||||||
|
let writing_mode = base.style.writing_mode;
|
||||||
|
let inline_size = containing_block_for_children.size.inline;
|
||||||
|
let content_block_size = self.content_size(
|
||||||
|
Direction::Block,
|
||||||
|
preferred_aspect_ratio,
|
||||||
|
&|| SizeConstraint::Definite(inline_size),
|
||||||
|
&|| self.fallback_block_size(writing_mode),
|
||||||
|
);
|
||||||
|
let size = LogicalVec2 {
|
||||||
|
inline: inline_size,
|
||||||
|
block: lazy_block_size.resolve(|| content_block_size),
|
||||||
|
}
|
||||||
|
.to_physical_size(writing_mode);
|
||||||
|
CacheableLayoutResult {
|
||||||
|
baselines: Default::default(),
|
||||||
|
collapsible_margins_in_children: CollapsedBlockMargins::zero(),
|
||||||
|
content_block_size,
|
||||||
|
content_inline_size_for_table: None,
|
||||||
|
depends_on_block_constraints,
|
||||||
|
fragments: self.make_fragments(layout_context, &base.style, size),
|
||||||
|
specific_layout_info: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeInlineContentSizes for ReplacedContents {
|
impl ComputeInlineContentSizes for ReplacedContents {
|
||||||
|
|
26
tests/wpt/meta/MANIFEST.json
vendored
26
tests/wpt/meta/MANIFEST.json
vendored
|
@ -254076,6 +254076,32 @@
|
||||||
],
|
],
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
|
],
|
||||||
|
"replaced-next-to-float-1.html": [
|
||||||
|
"b97f2ddba445dfdad6285691a509b3f2f7042b44",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/reference/ref-filled-green-100px-square.xht",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"replaced-next-to-float-2.html": [
|
||||||
|
"1a00846074ba376528d82836a644952773ce0edf",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/reference/ref-filled-green-100px-square.xht",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"svg-intrinsic-size-005.html": [
|
"svg-intrinsic-size-005.html": [
|
||||||
|
|
23
tests/wpt/tests/css/css-sizing/stretch/replaced-next-to-float-1.html
vendored
Normal file
23
tests/wpt/tests/css/css-sizing/stretch/replaced-next-to-float-1.html
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing">
|
||||||
|
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4028">
|
||||||
|
<link rel="help" href="https://github.com/servo/servo/issues/37861">
|
||||||
|
<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
|
||||||
|
<style>
|
||||||
|
#reference-overlapped-red {
|
||||||
|
position: absolute;
|
||||||
|
background-color: red;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||||
|
<div id="reference-overlapped-red"></div>
|
||||||
|
|
||||||
|
<div style="width:200px; margin-left: -100px;">
|
||||||
|
<div style="float: left; width: 100px; height: 100px;"></div>
|
||||||
|
<canvas width="1" height="1" style="display: block; width: stretch; background: green"></canvas>
|
||||||
|
</div>
|
41
tests/wpt/tests/css/css-sizing/stretch/replaced-next-to-float-2.html
vendored
Normal file
41
tests/wpt/tests/css/css-sizing/stretch/replaced-next-to-float-2.html
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing">
|
||||||
|
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4028">
|
||||||
|
<link rel="help" href="https://github.com/servo/servo/issues/37861">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css2/#floats">
|
||||||
|
<meta name="assert" content="The border box of a block-level replaced element
|
||||||
|
can't overlap the margin box of any float in the same block formatting context.
|
||||||
|
The stretch size needs to respect that.
|
||||||
|
">
|
||||||
|
<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
|
||||||
|
<style>
|
||||||
|
#reference-overlapped-red {
|
||||||
|
position: absolute;
|
||||||
|
background-color: red;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
.stretch {
|
||||||
|
display: flow-root;
|
||||||
|
height: 25px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||||
|
<div id="reference-overlapped-red"></div>
|
||||||
|
|
||||||
|
<div style="width:200px; margin-left: -100px;">
|
||||||
|
<div style="float: left; width: 100px; height: 75px;"></div>
|
||||||
|
<canvas class="stretch" style="width: 0; min-width: stretch"></canvas>
|
||||||
|
<canvas class="stretch" style="width: 1000px; max-width: stretch"></canvas>
|
||||||
|
<canvas class="stretch" style="width: stretch; padding: 0 10px; border: solid green; border-width: 0 10px; margin-left: 10px"></canvas>
|
||||||
|
</div>
|
||||||
|
<div style="width:250px; margin-left: -150px;">
|
||||||
|
<div style="float: left; clear: left; width: 100px; height: 1px;"></div>
|
||||||
|
<div style="float: left; clear: left; width: 150px; height: 1px;"></div>
|
||||||
|
<div style="float: left; clear: left; width: 125px; height: 1px;"></div>
|
||||||
|
<canvas class="stretch" style="width: stretch"></canvas>
|
||||||
|
</div>
|
Loading…
Add table
Add a link
Reference in a new issue