mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implement keyword sizes on absolute/fixed positioned elements (#33950)
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
c5ee573c6d
commit
1c26c0335e
41 changed files with 72 additions and 129 deletions
|
@ -624,7 +624,7 @@ impl ToLogicalWithContainingBlock<LogicalRect<Au>> for PhysicalRect<Au> {
|
||||||
|
|
||||||
/// The possible values accepted by the sizing properties.
|
/// The possible values accepted by the sizing properties.
|
||||||
/// <https://drafts.csswg.org/css-sizing/#sizing-properties>
|
/// <https://drafts.csswg.org/css-sizing/#sizing-properties>
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub(crate) enum Size<T> {
|
pub(crate) enum Size<T> {
|
||||||
/// Represents an `auto` value for the preferred and minimum size properties,
|
/// Represents an `auto` value for the preferred and minimum size properties,
|
||||||
/// or `none` for the maximum size properties.
|
/// or `none` for the maximum size properties.
|
||||||
|
@ -644,6 +644,8 @@ pub(crate) enum Size<T> {
|
||||||
Numeric(T),
|
Numeric(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Copy> Copy for Size<T> {}
|
||||||
|
|
||||||
impl<T> Default for Size<T> {
|
impl<T> Default for Size<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::cell::LazyCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
@ -25,7 +26,7 @@ use crate::fragment_tree::{
|
||||||
};
|
};
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint,
|
AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint,
|
||||||
PhysicalRect, PhysicalVec, ToLogical, ToLogicalWithContainingBlock,
|
PhysicalRect, PhysicalVec, Size, ToLogical, ToLogicalWithContainingBlock,
|
||||||
};
|
};
|
||||||
use crate::sizing::ContentSizes;
|
use crate::sizing::ContentSizes;
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt, DisplayInside};
|
use crate::style_ext::{Clamp, ComputedValuesExt, DisplayInside};
|
||||||
|
@ -461,17 +462,13 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
let used_size = replaced
|
let used_size = replaced
|
||||||
.contents
|
.contents
|
||||||
.used_size_as_if_inline_element(containing_block, &style, &pbm)
|
.used_size_as_if_inline_element(containing_block, &style, &pbm)
|
||||||
.map(|size| AuOrAuto::LengthPercentage(*size));
|
.map(|size| Size::Numeric(*size));
|
||||||
(used_size, Default::default(), Default::default())
|
(used_size, Default::default(), Default::default())
|
||||||
},
|
},
|
||||||
IndependentFormattingContext::NonReplaced(_) => (
|
IndependentFormattingContext::NonReplaced(_) => (
|
||||||
style.content_box_size_deprecated(containing_block, &pbm),
|
style.content_box_size(containing_block, &pbm),
|
||||||
style
|
style.content_min_box_size(containing_block, &pbm),
|
||||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
style.content_max_box_size(containing_block, &pbm),
|
||||||
.map(|value| value.map(Au::from).auto_is(Au::zero)),
|
|
||||||
style
|
|
||||||
.content_max_box_size_deprecated(containing_block, &pbm)
|
|
||||||
.map(|value| value.map(Au::from)),
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -536,14 +533,15 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
flip_anchor: false,
|
flip_anchor: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We can solve the inline axis, but the block one can depend on layout results,
|
// The block axis can depend on layout results, so we only solve it tentatively,
|
||||||
// so we may have to resolve it properly later on.
|
// we may have to resolve it properly later on.
|
||||||
|
let mut block_axis = block_axis_solver.solve_tentatively();
|
||||||
|
|
||||||
|
// The inline axis can be fully resolved, computing intrinsic sizes using the
|
||||||
|
// tentative block size.
|
||||||
let mut inline_axis = inline_axis_solver.solve(Some(|| {
|
let mut inline_axis = inline_axis_solver.solve(Some(|| {
|
||||||
let block_size = computed_size.block.map(|v| {
|
|
||||||
v.clamp_between_extremums(computed_min_size.block, computed_max_size.block)
|
|
||||||
});
|
|
||||||
let containing_block_for_children =
|
let containing_block_for_children =
|
||||||
IndefiniteContainingBlock::new_for_style_and_block_size(&style, block_size);
|
IndefiniteContainingBlock::new_for_style_and_block_size(&style, block_axis.size);
|
||||||
context
|
context
|
||||||
.inline_content_sizes(
|
.inline_content_sizes(
|
||||||
layout_context,
|
layout_context,
|
||||||
|
@ -552,7 +550,6 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
)
|
)
|
||||||
.sizes
|
.sizes
|
||||||
}));
|
}));
|
||||||
let mut block_axis = block_axis_solver.solve_tentatively();
|
|
||||||
|
|
||||||
let mut positioning_context = PositioningContext::new_for_style(&style).unwrap();
|
let mut positioning_context = PositioningContext::new_for_style(&style).unwrap();
|
||||||
let mut new_fragment = {
|
let mut new_fragment = {
|
||||||
|
@ -562,7 +559,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
IndependentFormattingContext::Replaced(replaced) => {
|
IndependentFormattingContext::Replaced(replaced) => {
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
|
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
|
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
|
||||||
content_size = computed_size.auto_is(|| unreachable!());
|
content_size = computed_size.map(|size| size.to_numeric().unwrap());
|
||||||
fragments = replaced.contents.make_fragments(
|
fragments = replaced.contents.make_fragments(
|
||||||
&style,
|
&style,
|
||||||
containing_block,
|
containing_block,
|
||||||
|
@ -752,9 +749,9 @@ struct AbsoluteAxisSolver<'a> {
|
||||||
padding_border_sum: Au,
|
padding_border_sum: Au,
|
||||||
computed_margin_start: AuOrAuto,
|
computed_margin_start: AuOrAuto,
|
||||||
computed_margin_end: AuOrAuto,
|
computed_margin_end: AuOrAuto,
|
||||||
computed_size: AuOrAuto,
|
computed_size: Size<Au>,
|
||||||
computed_min_size: Au,
|
computed_min_size: Size<Au>,
|
||||||
computed_max_size: Option<Au>,
|
computed_max_size: Size<Au>,
|
||||||
avoid_negative_margin_start: bool,
|
avoid_negative_margin_start: bool,
|
||||||
box_offsets: AbsoluteBoxOffsets<'a>,
|
box_offsets: AbsoluteBoxOffsets<'a>,
|
||||||
static_position_rect_axis: RectAxis,
|
static_position_rect_axis: RectAxis,
|
||||||
|
@ -775,24 +772,54 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
||||||
///
|
///
|
||||||
/// In the replaced case, `size` is never `Auto`.
|
/// In the replaced case, `size` is never `Auto`.
|
||||||
fn solve(&self, get_content_size: Option<impl FnOnce() -> ContentSizes>) -> AxisResult {
|
fn solve(&self, get_content_size: Option<impl FnOnce() -> ContentSizes>) -> AxisResult {
|
||||||
let solve_for_anchor = |anchor: Anchor| {
|
let mut get_content_size = get_content_size.map(|get_content_size| {
|
||||||
|
// The provided `get_content_size` is a FnOnce but we may need its result multiple times.
|
||||||
|
// A LazyCell will only invoke it once if needed, and then reuse the result.
|
||||||
|
let content_size = LazyCell::new(get_content_size);
|
||||||
|
move || *content_size
|
||||||
|
});
|
||||||
|
let mut solve_size = |initial_behavior, stretch_size: Au| {
|
||||||
|
let initial_is_stretch = initial_behavior == Size::Stretch;
|
||||||
|
let stretch_size = stretch_size.max(Au::zero());
|
||||||
|
get_content_size
|
||||||
|
.as_mut()
|
||||||
|
.map(|mut get_content_size| {
|
||||||
|
let min_size = self
|
||||||
|
.computed_min_size
|
||||||
|
.resolve_non_initial(stretch_size, &mut get_content_size)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let max_size = self
|
||||||
|
.computed_max_size
|
||||||
|
.resolve_non_initial(stretch_size, &mut get_content_size);
|
||||||
|
self.computed_size
|
||||||
|
.resolve(initial_behavior, stretch_size, &mut get_content_size)
|
||||||
|
.clamp_between_extremums(min_size, max_size)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
self.computed_size
|
||||||
|
.maybe_resolve_extrinsic(Some(stretch_size))
|
||||||
|
.or(initial_is_stretch.then_some(stretch_size))
|
||||||
|
.map(|size| {
|
||||||
|
let min_size = self
|
||||||
|
.computed_min_size
|
||||||
|
.maybe_resolve_extrinsic(Some(stretch_size))
|
||||||
|
.unwrap_or_default();
|
||||||
|
let max_size = self
|
||||||
|
.computed_max_size
|
||||||
|
.maybe_resolve_extrinsic(Some(stretch_size));
|
||||||
|
size.clamp_between_extremums(min_size, max_size)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let mut solve_for_anchor = |anchor: Anchor| {
|
||||||
let margin_start = self.computed_margin_start.auto_is(Au::zero);
|
let margin_start = self.computed_margin_start.auto_is(Au::zero);
|
||||||
let margin_end = self.computed_margin_end.auto_is(Au::zero);
|
let margin_end = self.computed_margin_end.auto_is(Au::zero);
|
||||||
let size = self
|
let stretch_size = self.containing_size -
|
||||||
.computed_size
|
anchor.inset() -
|
||||||
.non_auto()
|
self.padding_border_sum -
|
||||||
.or_else(|| {
|
margin_start -
|
||||||
let content_size = get_content_size?();
|
margin_end;
|
||||||
let available_size = self.containing_size -
|
let size = solve_size(Size::FitContent, stretch_size)
|
||||||
anchor.inset() -
|
|
||||||
self.padding_border_sum -
|
|
||||||
margin_start -
|
|
||||||
margin_end;
|
|
||||||
Some(content_size.shrink_to_fit(available_size))
|
|
||||||
})
|
|
||||||
.map(|size| {
|
|
||||||
size.clamp_between_extremums(self.computed_min_size, self.computed_max_size)
|
|
||||||
})
|
|
||||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
|
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
|
||||||
AxisResult {
|
AxisResult {
|
||||||
anchor,
|
anchor,
|
||||||
|
@ -820,14 +847,10 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
||||||
let start = start.to_used_value(self.containing_size);
|
let start = start.to_used_value(self.containing_size);
|
||||||
let end = end.to_used_value(self.containing_size);
|
let end = end.to_used_value(self.containing_size);
|
||||||
let mut free_space = self.containing_size - start - end - self.padding_border_sum;
|
let mut free_space = self.containing_size - start - end - self.padding_border_sum;
|
||||||
let used_size = self
|
let stretch_size = free_space -
|
||||||
.computed_size
|
self.computed_margin_start.auto_is(Au::zero) -
|
||||||
.auto_is(|| {
|
self.computed_margin_end.auto_is(Au::zero);
|
||||||
free_space -
|
let used_size = solve_size(Size::Stretch, stretch_size).unwrap();
|
||||||
self.computed_margin_start.auto_is(Au::zero) -
|
|
||||||
self.computed_margin_end.auto_is(Au::zero)
|
|
||||||
})
|
|
||||||
.clamp_between_extremums(self.computed_min_size, self.computed_max_size);
|
|
||||||
free_space -= used_size;
|
free_space -= used_size;
|
||||||
let (margin_start, margin_end) =
|
let (margin_start, margin_end) =
|
||||||
match (self.computed_margin_start, self.computed_margin_end) {
|
match (self.computed_margin_start, self.computed_margin_end) {
|
||||||
|
@ -865,9 +888,9 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
||||||
|
|
||||||
fn solve_with_size(&mut self, size: Au) -> AxisResult {
|
fn solve_with_size(&mut self, size: Au) -> AxisResult {
|
||||||
// Override sizes
|
// Override sizes
|
||||||
let old_size = mem::replace(&mut self.computed_size, AuOrAuto::LengthPercentage(size));
|
let old_size = mem::replace(&mut self.computed_size, Size::Numeric(size));
|
||||||
let old_min_size = mem::take(&mut self.computed_min_size);
|
let old_min_size = mem::take(&mut self.computed_min_size);
|
||||||
let old_max_size = self.computed_max_size.take();
|
let old_max_size = mem::take(&mut self.computed_max_size);
|
||||||
|
|
||||||
let result = self.solve_tentatively();
|
let result = self.solve_tentatively();
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[position-absolute-fit-content.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[block-size-with-min-or-max-content-6.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[block-size-with-min-or-max-content-7.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-auto-margin-bottom.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-auto-margin-top.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-block-size.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-orthogonal-auto-margin-left.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-orthogonal-auto-margin-right.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-orthogonal-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-fit-content-orthogonal-block-size.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-auto-margin-bottom.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-auto-margin-top.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-block-size.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-orthogonal-auto-margin-left.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-orthogonal-auto-margin-right.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-orthogonal-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-max-content-orthogonal-block-size.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-auto-margin-bottom.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-auto-margin-top.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-block-size.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-orthogonal-auto-margin-left.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-orthogonal-auto-margin-right.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-orthogonal-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-min-content-orthogonal-block-size.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-orthogonal-left-and-non-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[div-top-and-non-auto-margin.tentative.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[fit-content-block-size-abspos.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[fit-content-block-size-fixedpos.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[intrinsic-percent-replaced-005.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[intrinsic-percent-replaced-007.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[intrinsic-percent-replaced-dynamic-005.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[intrinsic-percent-replaced-dynamic-007.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[abspos-1.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[abspos-2.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[positioned-non-replaced-1.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,12 +1,6 @@
|
||||||
[dialog.html]
|
[dialog.html]
|
||||||
[Open dialog in width: 540px iframe]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Modal dialog in width: 540px iframe]
|
[Modal dialog in width: 540px iframe]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Open dialog in width: 538px iframe]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Modal dialog in width: 538px iframe]
|
[Modal dialog in width: 538px iframe]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue