mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Make ComputedValuesExt expose keywords for the sizing properties (#33558)
This will allow callers to start obeying `min-content`, `max-content`, `fit-content` and `stretch` in follow-up patches. The old functionality is kept as deprecated methods that we should eventually remove. This patch has very little impact on the existing behavior, just some very minimal implementation of the keywords for css tables. This also overhauls fixed-layout-2.html since: - It had code that wasn't doing anything - It had wrong expecations in prose - The logic seemed broken in general - All browsers were failing one testcase Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
c7ef974968
commit
057dd1e9eb
14 changed files with 419 additions and 268 deletions
|
@ -936,10 +936,10 @@ impl FlexContainer {
|
|||
.padding_border_margin(containing_block_for_container);
|
||||
let max_box_size = self
|
||||
.style
|
||||
.content_max_box_size(containing_block_for_container, &pbm);
|
||||
.content_max_box_size_deprecated(containing_block_for_container, &pbm);
|
||||
let min_box_size = self
|
||||
.style
|
||||
.content_min_box_size(containing_block_for_container, &pbm)
|
||||
.content_min_box_size_deprecated(containing_block_for_container, &pbm)
|
||||
.auto_is(Au::zero);
|
||||
|
||||
let max_box_size = self.config.flex_axis.vec2_to_flex_relative(max_box_size);
|
||||
|
@ -1012,15 +1012,15 @@ impl<'a> FlexItem<'a> {
|
|||
let pbm = box_.style().padding_border_margin(containing_block);
|
||||
let content_box_size = box_
|
||||
.style()
|
||||
.content_box_size(containing_block, &pbm)
|
||||
.content_box_size_deprecated(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let max_size = box_
|
||||
.style()
|
||||
.content_max_box_size(containing_block, &pbm)
|
||||
.content_max_box_size_deprecated(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let min_size = box_
|
||||
.style()
|
||||
.content_min_box_size(containing_block, &pbm)
|
||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
|
||||
let margin_auto_is_zero = flex_context.sides_to_flex_relative(pbm.margin.auto_is(Au::zero));
|
||||
|
@ -2005,7 +2005,7 @@ impl FlexItemBox {
|
|||
cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis);
|
||||
|
||||
let (content_box_size, content_min_size, content_max_size, pbm) =
|
||||
style.content_box_sizes_and_padding_border_margin(containing_block);
|
||||
style.content_box_sizes_and_padding_border_margin_deprecated(containing_block);
|
||||
let padding = main_start_cross_start.sides_to_flex_relative(pbm.padding);
|
||||
let border = main_start_cross_start.sides_to_flex_relative(pbm.border);
|
||||
let margin = main_start_cross_start.sides_to_flex_relative(pbm.margin);
|
||||
|
|
|
@ -915,13 +915,13 @@ impl FloatBox {
|
|||
// https://drafts.csswg.org/css2/#float-width
|
||||
let style = non_replaced.style.clone();
|
||||
let box_size = style
|
||||
.content_box_size(containing_block, &pbm)
|
||||
.content_box_size_deprecated(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let max_box_size = style
|
||||
.content_max_box_size(containing_block, &pbm)
|
||||
.content_max_box_size_deprecated(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let min_box_size = style
|
||||
.content_min_box_size(containing_block, &pbm)
|
||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from))
|
||||
.auto_is(Au::zero);
|
||||
|
||||
|
|
|
@ -1929,15 +1929,15 @@ impl IndependentFormattingContext {
|
|||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||
let box_size = non_replaced
|
||||
.style
|
||||
.content_box_size(layout.containing_block, &pbm)
|
||||
.content_box_size_deprecated(layout.containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let max_box_size = non_replaced
|
||||
.style
|
||||
.content_max_box_size(layout.containing_block, &pbm)
|
||||
.content_max_box_size_deprecated(layout.containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let min_box_size = non_replaced
|
||||
.style
|
||||
.content_min_box_size(layout.containing_block, &pbm)
|
||||
.content_min_box_size_deprecated(layout.containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from))
|
||||
.auto_is(Au::zero);
|
||||
let block_size = box_size
|
||||
|
|
|
@ -135,10 +135,10 @@ impl BlockLevelBox {
|
|||
}
|
||||
|
||||
let min_size = style
|
||||
.content_min_box_size(containing_block, &pbm)
|
||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
||||
.auto_is(Au::zero);
|
||||
let max_size = style.content_max_box_size(containing_block, &pbm);
|
||||
let prefered_size = style.content_box_size(containing_block, &pbm);
|
||||
let max_size = style.content_max_box_size_deprecated(containing_block, &pbm);
|
||||
let prefered_size = style.content_box_size_deprecated(containing_block, &pbm);
|
||||
let inline_size = prefered_size
|
||||
.inline
|
||||
.auto_is(|| {
|
||||
|
@ -1048,11 +1048,15 @@ impl NonReplacedFormattingContext {
|
|||
sequential_layout_state: &mut SequentialLayoutState,
|
||||
) -> BoxFragment {
|
||||
let pbm = self.style.padding_border_margin(containing_block);
|
||||
let box_size = self.style.content_box_size(containing_block, &pbm);
|
||||
let max_box_size = self.style.content_max_box_size(containing_block, &pbm);
|
||||
let box_size = self
|
||||
.style
|
||||
.content_box_size_deprecated(containing_block, &pbm);
|
||||
let max_box_size = self
|
||||
.style
|
||||
.content_max_box_size_deprecated(containing_block, &pbm);
|
||||
let min_box_size = self
|
||||
.style
|
||||
.content_min_box_size(containing_block, &pbm)
|
||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
||||
.auto_is(Au::zero);
|
||||
let block_size = box_size.block.map(|block_size| {
|
||||
block_size.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
||||
|
@ -1424,10 +1428,10 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
|||
style: &'a Arc<ComputedValues>,
|
||||
) -> ContainingBlockPaddingAndBorder<'a> {
|
||||
let pbm = style.padding_border_margin(containing_block);
|
||||
let box_size = style.content_box_size(containing_block, &pbm);
|
||||
let max_box_size = style.content_max_box_size(containing_block, &pbm);
|
||||
let box_size = style.content_box_size_deprecated(containing_block, &pbm);
|
||||
let max_box_size = style.content_max_box_size_deprecated(containing_block, &pbm);
|
||||
let min_box_size = style
|
||||
.content_min_box_size(containing_block, &pbm)
|
||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
||||
.auto_is(Au::zero);
|
||||
|
||||
// https://drafts.csswg.org/css2/#the-width-property
|
||||
|
|
|
@ -9,7 +9,9 @@ use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
|
|||
use app_units::Au;
|
||||
use serde::Serialize;
|
||||
use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode};
|
||||
use style::values::computed::{CSSPixelLength, LengthPercentage};
|
||||
use style::values::computed::{
|
||||
CSSPixelLength, LengthPercentage, MaxSize as StyleMaxSize, Size as StyleSize,
|
||||
};
|
||||
use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr;
|
||||
use style::Zero;
|
||||
use style_traits::CSSPixel;
|
||||
|
@ -145,89 +147,6 @@ impl<T: Clone> LogicalVec2<AutoOr<T>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<LengthPercentageOrAuto<'_>> {
|
||||
pub(crate) fn percentages_relative_to(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
) -> LogicalVec2<AuOrAuto> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.map(|value| value.to_used_value(containing_block.inline_size)),
|
||||
block: {
|
||||
self.block
|
||||
.non_auto()
|
||||
.and_then(|value| {
|
||||
value.maybe_to_used_value(containing_block.block_size.non_auto())
|
||||
})
|
||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<LengthPercentageOrAuto<'_>> {
|
||||
pub(crate) fn percentages_relative_to_basis(
|
||||
&self,
|
||||
basis: &LogicalVec2<Au>,
|
||||
) -> LogicalVec2<AuOrAuto> {
|
||||
LogicalVec2 {
|
||||
inline: self.inline.map(|value| value.to_used_value(basis.inline)),
|
||||
block: self.block.map(|value| value.to_used_value(basis.block)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<LengthPercentageOrAuto<'_>> {
|
||||
pub(crate) fn maybe_percentages_relative_to_basis(
|
||||
&self,
|
||||
basis: &LogicalVec2<Option<Au>>,
|
||||
) -> LogicalVec2<AuOrAuto> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.non_auto()
|
||||
.and_then(|value| value.maybe_to_used_value(basis.inline))
|
||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage),
|
||||
block: self
|
||||
.block
|
||||
.non_auto()
|
||||
.and_then(|value| value.maybe_to_used_value(basis.block))
|
||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<Option<&'_ LengthPercentage>> {
|
||||
pub(crate) fn percentages_relative_to(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
) -> LogicalVec2<Option<Au>> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.map(|lp| lp.to_used_value(containing_block.inline_size)),
|
||||
block: self
|
||||
.block
|
||||
.and_then(|lp| lp.maybe_to_used_value(containing_block.block_size.non_auto())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<Option<&'_ LengthPercentage>> {
|
||||
pub(crate) fn maybe_percentages_relative_to_basis(
|
||||
&self,
|
||||
basis: &LogicalVec2<Option<Au>>,
|
||||
) -> LogicalVec2<Option<Au>> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.and_then(|v| v.maybe_to_used_value(basis.inline)),
|
||||
block: self.block.and_then(|v| v.maybe_to_used_value(basis.block)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero> LogicalRect<T> {
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
|
@ -701,3 +620,144 @@ impl ToLogicalWithContainingBlock<LogicalRect<Au>> for PhysicalRect<Au> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The possible keywords accepted by the sizing properties.
|
||||
/// <https://drafts.csswg.org/css-sizing/#sizing-properties>
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum SizeKeyword {
|
||||
/// Represents an `auto` value for the preferred and minimum size properties,
|
||||
/// or `none` for the maximum size properties.
|
||||
/// <https://drafts.csswg.org/css-sizing/#valdef-width-auto>
|
||||
/// <https://drafts.csswg.org/css-sizing/#valdef-max-width-none>
|
||||
Initial,
|
||||
/// <https://drafts.csswg.org/css-sizing/#valdef-width-min-content>
|
||||
MinContent,
|
||||
/// <https://drafts.csswg.org/css-sizing/#valdef-width-max-content>
|
||||
MaxContent,
|
||||
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-fit-content>
|
||||
FitContent,
|
||||
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-stretch>
|
||||
Stretch,
|
||||
}
|
||||
|
||||
/// The possible values accepted by the sizing properties,
|
||||
/// with numeric `<length-percentage>` resolved as a `T`.
|
||||
/// <https://drafts.csswg.org/css-sizing/#sizing-properties>
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Size<T> {
|
||||
Keyword(SizeKeyword),
|
||||
Numeric(T),
|
||||
}
|
||||
|
||||
impl<T> Default for Size<T> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::Keyword(SizeKeyword::Initial)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Size<T> {
|
||||
#[inline]
|
||||
pub(crate) fn is_keyword(&self) -> bool {
|
||||
matches!(self, Self::Keyword(_))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_numeric(&self) -> Option<T> {
|
||||
match self {
|
||||
Self::Keyword(_) => None,
|
||||
Self::Numeric(numeric) => Some(numeric).cloned(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_auto_or(&self) -> AutoOr<T> {
|
||||
self.to_numeric()
|
||||
.map_or(AutoOr::Auto, AutoOr::LengthPercentage)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map<U>(&self, f: impl FnOnce(T) -> U) -> Size<U> {
|
||||
match self {
|
||||
Size::Keyword(keyword) => Size::Keyword(keyword.clone()),
|
||||
Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn maybe_map<U>(&self, f: impl FnOnce(T) -> Option<U>) -> Option<Size<U>> {
|
||||
Some(match self {
|
||||
Size::Keyword(keyword) => Size::Keyword(keyword.clone()),
|
||||
Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StyleSize> for Size<LengthPercentage> {
|
||||
fn from(size: StyleSize) -> Self {
|
||||
match size {
|
||||
StyleSize::LengthPercentage(length) => Size::Numeric(length.0),
|
||||
StyleSize::Auto => Size::Keyword(SizeKeyword::Initial),
|
||||
StyleSize::MinContent => Size::Keyword(SizeKeyword::MinContent),
|
||||
StyleSize::MaxContent => Size::Keyword(SizeKeyword::MaxContent),
|
||||
StyleSize::FitContent => Size::Keyword(SizeKeyword::FitContent),
|
||||
StyleSize::Stretch => Size::Keyword(SizeKeyword::Stretch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StyleMaxSize> for Size<LengthPercentage> {
|
||||
fn from(max_size: StyleMaxSize) -> Self {
|
||||
match max_size {
|
||||
StyleMaxSize::LengthPercentage(length) => Size::Numeric(length.0),
|
||||
StyleMaxSize::None => Size::Keyword(SizeKeyword::Initial),
|
||||
StyleMaxSize::MinContent => Size::Keyword(SizeKeyword::MinContent),
|
||||
StyleMaxSize::MaxContent => Size::Keyword(SizeKeyword::MaxContent),
|
||||
StyleMaxSize::FitContent => Size::Keyword(SizeKeyword::FitContent),
|
||||
StyleMaxSize::Stretch => Size::Keyword(SizeKeyword::Stretch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<Size<LengthPercentage>> {
|
||||
pub(crate) fn percentages_relative_to(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.map(|lp| lp.to_used_value(containing_block.inline_size)),
|
||||
block: self
|
||||
.block
|
||||
.maybe_map(|lp| lp.maybe_to_used_value(containing_block.block_size.non_auto()))
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_percentages_relative_to_basis(
|
||||
&self,
|
||||
basis: &LogicalVec2<Option<Au>>,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.maybe_map(|v| v.maybe_to_used_value(basis.inline))
|
||||
.unwrap_or_default(),
|
||||
block: self
|
||||
.block
|
||||
.maybe_map(|v| v.maybe_to_used_value(basis.block))
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn percentages_relative_to_basis(
|
||||
&self,
|
||||
basis: &LogicalVec2<Au>,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
LogicalVec2 {
|
||||
inline: self.inline.map(|value| value.to_used_value(basis.inline)),
|
||||
block: self.block.map(|value| value.to_used_value(basis.block)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ impl<'a> IndefiniteContainingBlock<'a> {
|
|||
auto_minimum: &LogicalVec2<Au>,
|
||||
) -> Self {
|
||||
let (content_box_size, content_min_size, content_max_size, _) =
|
||||
style.content_box_sizes_and_padding_border_margin(self);
|
||||
style.content_box_sizes_and_padding_border_margin_deprecated(self);
|
||||
let block_size = content_box_size.block.map(|v| {
|
||||
v.clamp_between_extremums(
|
||||
content_min_size.block.auto_is(|| auto_minimum.block),
|
||||
|
|
|
@ -476,7 +476,7 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
},
|
||||
IndependentFormattingContext::NonReplaced(non_replaced) => non_replaced
|
||||
.style
|
||||
.content_box_size(&indefinite_containing_block, &pbm),
|
||||
.content_box_size_deprecated(&indefinite_containing_block, &pbm),
|
||||
};
|
||||
|
||||
let shared_fragment = self.fragment.borrow();
|
||||
|
@ -561,10 +561,10 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
// https://drafts.csswg.org/css2/#min-max-heights
|
||||
let min_size = non_replaced
|
||||
.style
|
||||
.content_min_box_size(&indefinite_containing_block, &pbm)
|
||||
.content_min_box_size_deprecated(&indefinite_containing_block, &pbm)
|
||||
.map(|t| t.map(Au::from).auto_is(Au::zero));
|
||||
let max_size = style
|
||||
.content_max_box_size(&containing_block.into(), &pbm)
|
||||
.content_max_box_size_deprecated(&containing_block.into(), &pbm)
|
||||
.map(|t| t.map(Au::from));
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
|
||||
|
|
|
@ -427,15 +427,15 @@ impl ReplacedContent {
|
|||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Au> {
|
||||
let box_size = style
|
||||
.content_box_size(containing_block, pbm)
|
||||
.content_box_size_deprecated(containing_block, pbm)
|
||||
// We need to clamp to zero here to obtain the proper aspect
|
||||
// ratio when box-sizing is border-box and the inner box size
|
||||
// would otherwise be negative.
|
||||
.map(|value| value.map(|value| value.max(Au::zero())));
|
||||
let min_box_size = style
|
||||
.content_min_box_size(containing_block, pbm)
|
||||
.content_min_box_size_deprecated(containing_block, pbm)
|
||||
.auto_is(Au::zero);
|
||||
let max_box_size = style.content_max_box_size(containing_block, pbm);
|
||||
let max_box_size = style.content_max_box_size_deprecated(containing_block, pbm);
|
||||
self.used_size_as_if_inline_element_from_content_box_sizes(
|
||||
containing_block,
|
||||
style,
|
||||
|
|
|
@ -121,7 +121,7 @@ pub(crate) fn outer_inline(
|
|||
get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> ContentSizes,
|
||||
) -> ContentSizes {
|
||||
let (content_box_size, content_min_size, content_max_size, pbm) =
|
||||
style.content_box_sizes_and_padding_border_margin(containing_block);
|
||||
style.content_box_sizes_and_padding_border_margin_deprecated(containing_block);
|
||||
let content_min_size = LogicalVec2 {
|
||||
inline: content_min_size.inline.auto_is(|| auto_minimum.inline),
|
||||
block: content_min_size.block.auto_is(|| auto_minimum.block),
|
||||
|
|
|
@ -16,11 +16,8 @@ use style::properties::ComputedValues;
|
|||
use style::servo::selector_parser::PseudoElement;
|
||||
use style::values::computed::basic_shape::ClipPath;
|
||||
use style::values::computed::image::Image as ComputedImageLayer;
|
||||
use style::values::computed::{
|
||||
AlignItems, BorderStyle, LengthPercentage, NonNegativeLengthPercentage, Size,
|
||||
};
|
||||
use style::values::computed::{AlignItems, BorderStyle, LengthPercentage};
|
||||
use style::values::generics::box_::Perspective;
|
||||
use style::values::generics::length::MaxSize;
|
||||
use style::values::generics::position::{GenericAspectRatio, PreferredRatio};
|
||||
use style::values::specified::align::AlignFlags;
|
||||
use style::values::specified::{box_ as stylo, Overflow};
|
||||
|
@ -32,7 +29,7 @@ use crate::dom_traversal::Contents;
|
|||
use crate::fragment_tree::FragmentFlags;
|
||||
use crate::geom::{
|
||||
AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize,
|
||||
PhysicalVec,
|
||||
PhysicalVec, Size,
|
||||
};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
|
@ -190,48 +187,72 @@ pub(crate) trait ComputedValuesExt {
|
|||
fn box_size(
|
||||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalVec2<LengthPercentageOrAuto<'_>>;
|
||||
) -> LogicalVec2<Size<LengthPercentage>>;
|
||||
fn min_box_size(
|
||||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalVec2<LengthPercentageOrAuto<'_>>;
|
||||
) -> LogicalVec2<Size<LengthPercentage>>;
|
||||
fn max_box_size(
|
||||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalVec2<Option<&LengthPercentage>>;
|
||||
) -> LogicalVec2<Size<LengthPercentage>>;
|
||||
fn content_box_size(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Size<Au>>;
|
||||
fn content_box_size_deprecated(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto>;
|
||||
fn content_box_size_for_box_size(
|
||||
&self,
|
||||
box_size: LogicalVec2<AuOrAuto>,
|
||||
box_size: LogicalVec2<Size<Au>>,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto>;
|
||||
) -> LogicalVec2<Size<Au>>;
|
||||
fn content_min_box_size(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Size<Au>>;
|
||||
fn content_min_box_size_deprecated(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto>;
|
||||
fn content_min_box_size_for_min_size(
|
||||
&self,
|
||||
box_size: LogicalVec2<AuOrAuto>,
|
||||
box_size: LogicalVec2<Size<Au>>,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto>;
|
||||
) -> LogicalVec2<Size<Au>>;
|
||||
fn content_max_box_size(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Size<Au>>;
|
||||
fn content_max_box_size_deprecated(
|
||||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Option<Au>>;
|
||||
fn content_max_box_size_for_max_size(
|
||||
&self,
|
||||
box_size: LogicalVec2<Option<Au>>,
|
||||
box_size: LogicalVec2<Size<Au>>,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Option<Au>>;
|
||||
) -> LogicalVec2<Size<Au>>;
|
||||
fn content_box_sizes_and_padding_border_margin(
|
||||
&self,
|
||||
containing_block: &IndefiniteContainingBlock,
|
||||
) -> (
|
||||
LogicalVec2<Size<Au>>,
|
||||
LogicalVec2<Size<Au>>,
|
||||
LogicalVec2<Size<Au>>,
|
||||
PaddingBorderMargin,
|
||||
);
|
||||
fn content_box_sizes_and_padding_border_margin_deprecated(
|
||||
&self,
|
||||
containing_block: &IndefiniteContainingBlock,
|
||||
) -> (
|
||||
LogicalVec2<AuOrAuto>,
|
||||
LogicalVec2<AuOrAuto>,
|
||||
|
@ -309,12 +330,12 @@ impl ComputedValuesExt for ComputedValues {
|
|||
fn box_size(
|
||||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalVec2<LengthPercentageOrAuto<'_>> {
|
||||
) -> LogicalVec2<Size<LengthPercentage>> {
|
||||
let position = self.get_position();
|
||||
LogicalVec2::from_physical_size(
|
||||
&PhysicalSize::new(
|
||||
size_to_length(&position.width),
|
||||
size_to_length(&position.height),
|
||||
position.clone_width().into(),
|
||||
position.clone_height().into(),
|
||||
),
|
||||
containing_block_writing_mode,
|
||||
)
|
||||
|
@ -323,12 +344,12 @@ impl ComputedValuesExt for ComputedValues {
|
|||
fn min_box_size(
|
||||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalVec2<LengthPercentageOrAuto<'_>> {
|
||||
) -> LogicalVec2<Size<LengthPercentage>> {
|
||||
let position = self.get_position();
|
||||
LogicalVec2::from_physical_size(
|
||||
&PhysicalSize::new(
|
||||
size_to_length(&position.min_width),
|
||||
size_to_length(&position.min_height),
|
||||
position.clone_min_width().into(),
|
||||
position.clone_min_height().into(),
|
||||
),
|
||||
containing_block_writing_mode,
|
||||
)
|
||||
|
@ -337,20 +358,13 @@ impl ComputedValuesExt for ComputedValues {
|
|||
fn max_box_size(
|
||||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalVec2<Option<&LengthPercentage>> {
|
||||
fn unwrap(max_size: &MaxSize<NonNegativeLengthPercentage>) -> Option<&LengthPercentage> {
|
||||
match max_size {
|
||||
MaxSize::LengthPercentage(length) => Some(&length.0),
|
||||
MaxSize::None |
|
||||
MaxSize::MinContent |
|
||||
MaxSize::MaxContent |
|
||||
MaxSize::FitContent |
|
||||
MaxSize::Stretch => None,
|
||||
}
|
||||
}
|
||||
) -> LogicalVec2<Size<LengthPercentage>> {
|
||||
let position = self.get_position();
|
||||
LogicalVec2::from_physical_size(
|
||||
&PhysicalSize::new(unwrap(&position.max_width), unwrap(&position.max_height)),
|
||||
&PhysicalSize::new(
|
||||
position.clone_max_width().into(),
|
||||
position.clone_max_height().into(),
|
||||
),
|
||||
containing_block_writing_mode,
|
||||
)
|
||||
}
|
||||
|
@ -359,18 +373,27 @@ impl ComputedValuesExt for ComputedValues {
|
|||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto> {
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
let box_size = self
|
||||
.box_size(containing_block.style.writing_mode)
|
||||
.percentages_relative_to(containing_block);
|
||||
self.content_box_size_for_box_size(box_size, pbm)
|
||||
}
|
||||
|
||||
fn content_box_size_for_box_size(
|
||||
fn content_box_size_deprecated(
|
||||
&self,
|
||||
box_size: LogicalVec2<AuOrAuto>,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto> {
|
||||
self.content_box_size(containing_block, pbm)
|
||||
.map(Size::to_auto_or)
|
||||
}
|
||||
|
||||
fn content_box_size_for_box_size(
|
||||
&self,
|
||||
box_size: LogicalVec2<Size<Au>>,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
match self.get_position().box_sizing {
|
||||
BoxSizing::ContentBox => box_size,
|
||||
BoxSizing::BorderBox => LogicalVec2 {
|
||||
|
@ -390,18 +413,27 @@ impl ComputedValuesExt for ComputedValues {
|
|||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto> {
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
let box_size = self
|
||||
.min_box_size(containing_block.style.writing_mode)
|
||||
.percentages_relative_to(containing_block);
|
||||
self.content_min_box_size_for_min_size(box_size, pbm)
|
||||
}
|
||||
|
||||
fn content_min_box_size_for_min_size(
|
||||
fn content_min_box_size_deprecated(
|
||||
&self,
|
||||
min_box_size: LogicalVec2<AuOrAuto>,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<AuOrAuto> {
|
||||
self.content_min_box_size(containing_block, pbm)
|
||||
.map(Size::to_auto_or)
|
||||
}
|
||||
|
||||
fn content_min_box_size_for_min_size(
|
||||
&self,
|
||||
min_box_size: LogicalVec2<Size<Au>>,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
match self.get_position().box_sizing {
|
||||
BoxSizing::ContentBox => min_box_size,
|
||||
BoxSizing::BorderBox => LogicalVec2 {
|
||||
|
@ -420,7 +452,7 @@ impl ComputedValuesExt for ComputedValues {
|
|||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Option<Au>> {
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
let max_box_size = self
|
||||
.max_box_size(containing_block.style.writing_mode)
|
||||
.percentages_relative_to(containing_block);
|
||||
|
@ -428,11 +460,20 @@ impl ComputedValuesExt for ComputedValues {
|
|||
self.content_max_box_size_for_max_size(max_box_size, pbm)
|
||||
}
|
||||
|
||||
fn content_max_box_size_for_max_size(
|
||||
fn content_max_box_size_deprecated(
|
||||
&self,
|
||||
max_box_size: LogicalVec2<Option<Au>>,
|
||||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Option<Au>> {
|
||||
self.content_max_box_size(containing_block, pbm)
|
||||
.map(Size::to_numeric)
|
||||
}
|
||||
|
||||
fn content_max_box_size_for_max_size(
|
||||
&self,
|
||||
max_box_size: LogicalVec2<Size<Au>>,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
match self.get_position().box_sizing {
|
||||
BoxSizing::ContentBox => max_box_size,
|
||||
BoxSizing::BorderBox => {
|
||||
|
@ -454,9 +495,9 @@ impl ComputedValuesExt for ComputedValues {
|
|||
&self,
|
||||
containing_block: &IndefiniteContainingBlock,
|
||||
) -> (
|
||||
LogicalVec2<AuOrAuto>,
|
||||
LogicalVec2<AuOrAuto>,
|
||||
LogicalVec2<Option<Au>>,
|
||||
LogicalVec2<Size<Au>>,
|
||||
LogicalVec2<Size<Au>>,
|
||||
LogicalVec2<Size<Au>>,
|
||||
PaddingBorderMargin,
|
||||
) {
|
||||
// <https://drafts.csswg.org/css-sizing-3/#cyclic-percentage-contribution>
|
||||
|
@ -493,6 +534,25 @@ impl ComputedValuesExt for ComputedValues {
|
|||
(content_box_size, content_min_size, content_max_size, pbm)
|
||||
}
|
||||
|
||||
fn content_box_sizes_and_padding_border_margin_deprecated(
|
||||
&self,
|
||||
containing_block: &IndefiniteContainingBlock,
|
||||
) -> (
|
||||
LogicalVec2<AuOrAuto>,
|
||||
LogicalVec2<AuOrAuto>,
|
||||
LogicalVec2<Option<Au>>,
|
||||
PaddingBorderMargin,
|
||||
) {
|
||||
let (content_box_size, content_min_size, content_max_size, pbm) =
|
||||
self.content_box_sizes_and_padding_border_margin(containing_block);
|
||||
(
|
||||
content_box_size.map(Size::to_auto_or),
|
||||
content_min_size.map(Size::to_auto_or),
|
||||
content_max_size.map(Size::to_numeric),
|
||||
pbm,
|
||||
)
|
||||
}
|
||||
|
||||
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin {
|
||||
self.padding_border_margin_with_writing_mode_and_containing_block_inline_size(
|
||||
containing_block.style.writing_mode,
|
||||
|
@ -998,15 +1058,6 @@ impl From<stylo::Display> for Display {
|
|||
}
|
||||
}
|
||||
|
||||
fn size_to_length(size: &Size) -> LengthPercentageOrAuto {
|
||||
match size {
|
||||
Size::LengthPercentage(length) => LengthPercentageOrAuto::LengthPercentage(&length.0),
|
||||
Size::Auto | Size::MinContent | Size::MaxContent | Size::FitContent | Size::Stretch => {
|
||||
LengthPercentageOrAuto::Auto
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait Clamp: Sized {
|
||||
fn clamp_below_max(self, max: Option<Self>) -> Self;
|
||||
fn clamp_between_extremums(self, min: Self, max: Option<Self>) -> Self;
|
||||
|
|
|
@ -33,8 +33,8 @@ use crate::fragment_tree::{
|
|||
PositioningFragment,
|
||||
};
|
||||
use crate::geom::{
|
||||
AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint,
|
||||
PhysicalRect, PhysicalSides, ToLogical, ToLogicalWithContainingBlock,
|
||||
AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
|
||||
Size, SizeKeyword, ToLogical, ToLogicalWithContainingBlock,
|
||||
};
|
||||
use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength};
|
||||
use crate::sizing::ContentSizes;
|
||||
|
@ -245,9 +245,15 @@ impl<'a> TableLayout<'a> {
|
|||
layout_context: &LayoutContext,
|
||||
writing_mode: WritingMode,
|
||||
) {
|
||||
// It's not clear whether `inline-size: stretch` allows fixed table mode or not,
|
||||
// we align with Gecko and Blink.
|
||||
// <https://github.com/w3c/csswg-drafts/issues/10937>.
|
||||
let is_in_fixed_mode = self.table.style.get_table().clone_table_layout() ==
|
||||
TableLayoutMode::Fixed &&
|
||||
!self.table.style.box_size(writing_mode).inline.is_auto();
|
||||
!matches!(
|
||||
self.table.style.box_size(writing_mode).inline,
|
||||
Size::Keyword(SizeKeyword::Initial | SizeKeyword::MaxContent)
|
||||
);
|
||||
let row_measures = vec![LogicalVec2::zero(); self.table.size.width];
|
||||
self.cell_measures = vec![row_measures; self.table.size.height];
|
||||
|
||||
|
@ -369,8 +375,8 @@ impl<'a> TableLayout<'a> {
|
|||
self.rows = vec![RowLayout::default(); self.table.size.height];
|
||||
self.columns = vec![ColumnLayout::default(); self.table.size.width];
|
||||
|
||||
let is_length = |size: &LengthPercentageOrAuto| {
|
||||
size.non_auto().is_some_and(|size| !size.has_percentage())
|
||||
let is_length = |size: &Size<ComputedLengthPercentage>| {
|
||||
size.to_numeric().is_some_and(|size| !size.has_percentage())
|
||||
};
|
||||
|
||||
for column_index in 0..self.table.size.width {
|
||||
|
@ -837,13 +843,13 @@ impl<'a> TableLayout<'a> {
|
|||
// This diverges a little from the specification, but should be equivalent
|
||||
// (other than using the stretch-fit size instead of the containing block width).
|
||||
let used_width_of_table = match style
|
||||
.content_box_size(containing_block_for_table, &self.pbm)
|
||||
.content_box_size_deprecated(containing_block_for_table, &self.pbm)
|
||||
.inline
|
||||
{
|
||||
LengthPercentage(_) => resolved_table_width.max(grid_min_max.min_content),
|
||||
Auto => {
|
||||
let min_width: Au = style
|
||||
.content_min_box_size(containing_block_for_table, &self.pbm)
|
||||
.content_min_box_size_deprecated(containing_block_for_table, &self.pbm)
|
||||
.inline
|
||||
.auto_is(Au::zero);
|
||||
resolved_table_width
|
||||
|
@ -1587,12 +1593,12 @@ impl<'a> TableLayout<'a> {
|
|||
// the resulting length, properly clamped between min-block-size and max-block-size.
|
||||
let style = &self.table.style;
|
||||
let table_height_from_style = match style
|
||||
.content_box_size(containing_block_for_table, &self.pbm)
|
||||
.content_box_size_deprecated(containing_block_for_table, &self.pbm)
|
||||
.block
|
||||
{
|
||||
LengthPercentage(_) => containing_block_for_children.block_size,
|
||||
Auto => style
|
||||
.content_min_box_size(containing_block_for_table, &self.pbm)
|
||||
.content_min_box_size_deprecated(containing_block_for_table, &self.pbm)
|
||||
.block
|
||||
.map(Au::from),
|
||||
}
|
||||
|
@ -2711,7 +2717,7 @@ impl Table {
|
|||
.style
|
||||
.box_size(writing_mode)
|
||||
.block
|
||||
.non_auto()
|
||||
.to_numeric()
|
||||
.and_then(|size| size.to_length())
|
||||
.map_or_else(Au::zero, Au::from);
|
||||
let percentage_contribution =
|
||||
|
@ -2841,12 +2847,13 @@ fn get_size_percentage_contribution_from_style(
|
|||
let max_size = style.max_box_size(writing_mode);
|
||||
|
||||
let get_contribution_for_axis =
|
||||
|size: LengthPercentageOrAuto<'_>, max_size: Option<&ComputedLengthPercentage>| {
|
||||
|size: Size<ComputedLengthPercentage>, max_size: Size<ComputedLengthPercentage>| {
|
||||
let size_percentage = size
|
||||
.non_auto()
|
||||
.to_numeric()
|
||||
.and_then(|length_percentage| length_percentage.to_percentage())
|
||||
.unwrap_or(Percentage(0.));
|
||||
let max_size_percentage = max_size
|
||||
.to_numeric()
|
||||
.and_then(|length_percentage| length_percentage.to_percentage())
|
||||
.unwrap_or(Percentage(f32::INFINITY));
|
||||
Percentage(size_percentage.0.min(max_size_percentage.0))
|
||||
|
@ -2871,22 +2878,22 @@ fn get_outer_sizes_from_style(
|
|||
block: size.block.max(padding_border_sums.block),
|
||||
},
|
||||
};
|
||||
let get_size_for_axis = |size: &LengthPercentageOrAuto<'_>| {
|
||||
size.non_auto()
|
||||
.and_then(|size| size.to_length())
|
||||
.map_or_else(Au::zero, Au::from)
|
||||
};
|
||||
let get_max_size_for_axis = |size: &Option<&ComputedLengthPercentage>| {
|
||||
size.and_then(|length_percentage| length_percentage.to_length())
|
||||
.map_or(MAX_AU, Au::from)
|
||||
let get_size_for_axis = |size: &Size<ComputedLengthPercentage>| {
|
||||
// TODO(#32853): This treats all sizing keywords as `auto`.
|
||||
size.to_numeric()
|
||||
.and_then(|length_percentage| length_percentage.to_length())
|
||||
.map(Au::from)
|
||||
};
|
||||
|
||||
let size = style.box_size(writing_mode);
|
||||
let min_size = style.min_box_size(writing_mode);
|
||||
let max_size = style.max_box_size(writing_mode);
|
||||
(
|
||||
outer_size(size.map(get_size_for_axis)),
|
||||
outer_size(style.min_box_size(writing_mode).map(get_size_for_axis)),
|
||||
outer_size(style.max_box_size(writing_mode).map(get_max_size_for_axis)),
|
||||
size.inline.is_auto(),
|
||||
outer_size(size.map(|v| get_size_for_axis(v).unwrap_or(Au(0)))),
|
||||
outer_size(min_size.map(|v| get_size_for_axis(v).unwrap_or(Au(0)))),
|
||||
outer_size(max_size.map(|v| get_size_for_axis(v).unwrap_or(MAX_AU))),
|
||||
// TODO(#32853): This treats all sizing keywords as `auto`.
|
||||
size.inline.is_keyword(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
2
tests/wpt/meta/MANIFEST.json
vendored
2
tests/wpt/meta/MANIFEST.json
vendored
|
@ -565151,7 +565151,7 @@
|
|||
]
|
||||
],
|
||||
"fixed-layout-2.html": [
|
||||
"dcbabb1ff7460ce563c3f127b9215e7b1211434b",
|
||||
"3b7f65feccf578e7ead60186bf48517d750428be",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
[table-width-redistribution-fixed.html]
|
||||
[table 3]
|
||||
expected: FAIL
|
||||
|
||||
[table 15]
|
||||
expected: FAIL
|
||||
|
||||
|
|
180
tests/wpt/tests/css/css-tables/fixed-layout-2.html
vendored
180
tests/wpt/tests/css/css-tables/fixed-layout-2.html
vendored
|
@ -1,84 +1,116 @@
|
|||
<!doctype html>
|
||||
<script src='/resources/testharness.js'></script>
|
||||
<script src='/resources/testharnessreport.js'></script>
|
||||
<link rel='stylesheet' href='./support/base.css' />
|
||||
<!DOCTYPE html>
|
||||
<title>table-layout:fixed with various widths</title>
|
||||
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-tables-3/#in-fixed-mode">
|
||||
<main>
|
||||
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/10937">
|
||||
<link rel="stylesheet" href="./support/base.css">
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
width: 0;
|
||||
}
|
||||
x-table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0px;
|
||||
}
|
||||
x-td:first-child {
|
||||
padding: 0;
|
||||
background: cyan;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
x-td + x-td {
|
||||
padding: 0;
|
||||
height: 50px;
|
||||
}
|
||||
x-td > div {
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<main id="main">
|
||||
<h1>Fixed Layout</h1>
|
||||
<p>Checks whether fixed layout is implemented properly (width is not definite)</p>
|
||||
|
||||
<hr/>
|
||||
<p>This should be a 100px-wide blue square:</p>
|
||||
<p>Table-layout:fixed does not apply to width:auto tables</p>
|
||||
<x-table style="table-layout: fixed; border-spacing: 0px">
|
||||
<x-tr>
|
||||
<x-td style="padding: 0; background: blue; height: 100px;"><div style="width: 100px"></div></x-td>
|
||||
<x-td style="padding: 0"></x-td>
|
||||
</x-tr>
|
||||
</x-table>
|
||||
|
||||
<hr/>
|
||||
<p>This should be a 100px-wide blue square:</p>
|
||||
<p>Table-layout:fixed does not apply to width:max-content tables</p>
|
||||
<x-table style="table-layout: fixed; width: max-content; border-spacing: 0px">
|
||||
<x-tr>
|
||||
<x-td style="padding: 0; background: blue; height: 100px;"><div style="width: 100px"></div></x-td>
|
||||
<x-td style="padding: 0"></x-td>
|
||||
</x-tr>
|
||||
</x-table>
|
||||
|
||||
<hr/>
|
||||
<p>This should be a 100px-wide blue square:</p>
|
||||
<p>Table-layout:fixed does apply to width:min-content/fit-content tables</p>
|
||||
<x-table style="table-layout: fixed; width: fit-content; border-spacing: 0px">
|
||||
<x-tr>
|
||||
<x-td style="padding: 0; background: blue; height: 50px;"><div style="width: 100px"></div></x-td>
|
||||
<x-td style="padding: 0"></x-td>
|
||||
</x-tr>
|
||||
</x-table>
|
||||
<x-table style="table-layout: fixed; width: min-content; border-spacing: 0px">
|
||||
<x-tr>
|
||||
<x-td style="padding: 0; background: blue; height: 50px;width:100px;"><div style="width: 100px"></div></x-td>
|
||||
<x-td style="padding: 0;height:50px"><div style="width: 100px"></div></x-td>
|
||||
</x-tr>
|
||||
</x-table>
|
||||
|
||||
<p>Checks whether fixed layout is implemented properly</p>
|
||||
</main>
|
||||
|
||||
<template id="template">
|
||||
<hr>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<div class="wrapper">
|
||||
<x-table>
|
||||
<x-tr>
|
||||
<x-td>
|
||||
<div></div>
|
||||
</x-td>
|
||||
<x-td></x-td>
|
||||
</x-tr>
|
||||
</x-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
while(true) {
|
||||
var xtd = document.querySelector('x-td[rowspan], x-td[colspan]'); if(!xtd) break;
|
||||
var td = document.createElement('td'); for(var i = xtd.attributes.length; i--;) { td.setAttribute(xtd.attributes[i].name,xtd.attributes[i].value) }
|
||||
xtd.parentNode.replaceChild(td,xtd);
|
||||
let sizeData = {
|
||||
"10px": true,
|
||||
"100%": true,
|
||||
"calc(10px + 100%)": true,
|
||||
"auto": false,
|
||||
"min-content": true,
|
||||
"max-content": false,
|
||||
"fit-content": true,
|
||||
"calc-size(any, 10px + 100%)": true,
|
||||
|
||||
// These expectations are tentative, see https://github.com/w3c/csswg-drafts/issues/10937
|
||||
"fit-content(0)": true,
|
||||
"stretch": true,
|
||||
|
||||
// These are non-standard, expect the most popular behavior among the supporting implementations.
|
||||
"-moz-available": true,
|
||||
"-webkit-fill-available": true,
|
||||
"intrinsic": false,
|
||||
"min-intrinsic": false,
|
||||
};
|
||||
|
||||
function checkSize(size, allowsFixed) {
|
||||
let fragment = template.content.cloneNode(true);
|
||||
if (allowsFixed) {
|
||||
fragment.querySelector("p").textContent = "This should be a 50x50 cyan square:";
|
||||
fragment.querySelector("p + p").textContent = "Table-layout:fixed does apply to width:" + size + " tables";
|
||||
} else {
|
||||
fragment.querySelector("p").textContent = "This should be a 100x50 cyan rectangle:";
|
||||
fragment.querySelector("p + p").textContent = "Table-layout:fixed does NOT apply to width:" + size + " tables";
|
||||
}
|
||||
let table = fragment.querySelector("x-table");
|
||||
table.style.width = size;
|
||||
table.querySelector("div").textContent = size;
|
||||
main.appendChild(fragment);
|
||||
|
||||
test(() => {
|
||||
assert_equals(
|
||||
getComputedStyle(table).tableLayout,
|
||||
"fixed",
|
||||
"The computed value is 'fixed' regardless of whether it applies"
|
||||
);
|
||||
if (allowsFixed) {
|
||||
assert_equals(table.offsetWidth, 50, "Table is in fixed mode");
|
||||
} else {
|
||||
assert_equals(table.offsetWidth, 100, "Table is NOT in fixed mode");
|
||||
}
|
||||
}, size);
|
||||
}
|
||||
|
||||
generate_tests(assert_equals, [
|
||||
[
|
||||
"Table-layout:fixed is not applied when width is auto",
|
||||
document.querySelector("x-table:nth-of-type(1) > x-tr:first-child > x-td:first-child").offsetWidth,
|
||||
100
|
||||
],
|
||||
[
|
||||
"Table-layout:fixed reports fixed when width is auto",
|
||||
getComputedStyle(document.querySelector("x-table:nth-of-type(1)")).tableLayout,
|
||||
'fixed'
|
||||
],
|
||||
[
|
||||
"Table-layout:fixed is not applied when width is max-content",
|
||||
document.querySelector("x-table:nth-of-type(2) > x-tr:first-child > x-td:first-child").offsetWidth,
|
||||
100
|
||||
],
|
||||
[
|
||||
"Table-layout:fixed reports fixed when width is max-content",
|
||||
getComputedStyle(document.querySelector("x-table:nth-of-type(2)")).tableLayout,
|
||||
'fixed'
|
||||
],
|
||||
[
|
||||
"Table-layout:fixed is applied when width is min-content",
|
||||
document.querySelector("x-table:nth-of-type(3) > x-tr:first-child > x-td:first-child").offsetWidth,
|
||||
document.querySelector("x-table:nth-of-type(4) > x-tr:first-child > x-td:first-child").offsetWidth
|
||||
]
|
||||
])
|
||||
for (let [size, allowsFixed] of Object.entries(sizeData)) {
|
||||
if (CSS.supports("width", size)) {
|
||||
checkSize(size, allowsFixed);
|
||||
|
||||
// calc-size() should have the same behavior as its basis.
|
||||
// https://drafts.csswg.org/css-values-5/#calc-size
|
||||
let calcSize = "calc-size(" + size + ", size)";
|
||||
if (CSS.supports("width", calcSize)) {
|
||||
checkSize(calcSize, allowsFixed);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue