mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
layout: Take percentage columns into account when sizing table grid min and max (#35167)
The specification doesn't say how to deal with percentages when determining the minimum and maximum size of a table grid, so follow the approach that Chromium uses. Essentially, figure out the "missing" percentage from the non-percentage columns and then use that to work backwards to fine the size of the percentage ones. This change is larger than one might expect, because this percentage approach shouldn't happen for tables that are descendants of a flex, grid or table container (except when there is an interceding absolute). We have to pass this information down when building the box tree. This will also make it easier to improve propagated text decorations in the future. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
d5fcc5a5d5
commit
6b04bc6263
26 changed files with 228 additions and 226 deletions
|
@ -11,7 +11,6 @@ use style::properties::longhands::list_style_position::computed_value::T as List
|
|||
use style::properties::ComputedValues;
|
||||
use style::selector_parser::PseudoElement;
|
||||
use style::str::char_is_whitespace;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
|
||||
use super::inline::construct::InlineFormattingContextBuilder;
|
||||
use super::inline::inline_box::InlineBox;
|
||||
|
@ -30,13 +29,14 @@ use crate::layout_box_base::LayoutBoxBase;
|
|||
use crate::positioned::AbsolutelyPositionedBox;
|
||||
use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside};
|
||||
use crate::table::{AnonymousTableContent, Table};
|
||||
use crate::PropagatedBoxTreeData;
|
||||
|
||||
impl BlockFormattingContext {
|
||||
pub(crate) fn construct<'dom, Node>(
|
||||
context: &LayoutContext,
|
||||
info: &NodeAndStyleInfo<Node>,
|
||||
contents: NonReplacedContents,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
is_list_item: bool,
|
||||
) -> Self
|
||||
where
|
||||
|
@ -46,7 +46,7 @@ impl BlockFormattingContext {
|
|||
context,
|
||||
info,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
propagated_data,
|
||||
is_list_item,
|
||||
))
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ impl BlockFormattingContext {
|
|||
struct BlockLevelJob<'dom, Node> {
|
||||
info: NodeAndStyleInfo<Node>,
|
||||
box_slot: BoxSlot<'dom>,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
kind: BlockLevelCreator,
|
||||
}
|
||||
|
||||
|
@ -71,7 +72,6 @@ enum BlockLevelCreator {
|
|||
Independent {
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
},
|
||||
OutOfFlowAbsolutelyPositionedBox {
|
||||
display_inside: DisplayInside,
|
||||
|
@ -100,7 +100,7 @@ enum IntermediateBlockContainer {
|
|||
InlineFormattingContext(BlockContainer),
|
||||
Deferred {
|
||||
contents: NonReplacedContents,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
is_list_item: bool,
|
||||
},
|
||||
}
|
||||
|
@ -135,8 +135,8 @@ pub(crate) struct BlockContainerBuilder<'dom, 'style, Node> {
|
|||
/// be considered the first line for the purposes of `text-indent`.
|
||||
have_already_seen_first_line_for_text_indent: bool,
|
||||
|
||||
/// The propagated [`TextDecorationLine`].
|
||||
text_decoration_line: TextDecorationLine,
|
||||
/// The propagated data to use for BoxTree construction.
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
|
||||
inline_formatting_context_builder: InlineFormattingContextBuilder,
|
||||
|
||||
|
@ -155,14 +155,13 @@ impl BlockContainer {
|
|||
context: &LayoutContext,
|
||||
info: &NodeAndStyleInfo<Node>,
|
||||
contents: NonReplacedContents,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
is_list_item: bool,
|
||||
) -> BlockContainer
|
||||
where
|
||||
Node: NodeExt<'dom>,
|
||||
{
|
||||
let mut builder =
|
||||
BlockContainerBuilder::new(context, info, propagated_text_decoration_line);
|
||||
let mut builder = BlockContainerBuilder::new(context, info, propagated_data);
|
||||
|
||||
if is_list_item {
|
||||
if let Some(marker_contents) = crate::lists::make_marker(context, info) {
|
||||
|
@ -189,16 +188,13 @@ where
|
|||
pub(crate) fn new(
|
||||
context: &'style LayoutContext,
|
||||
info: &'style NodeAndStyleInfo<Node>,
|
||||
propagated_text_decoration_line: TextDecorationLine,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
) -> Self {
|
||||
let text_decoration_line =
|
||||
propagated_text_decoration_line | info.style.clone_text_decoration_line();
|
||||
|
||||
BlockContainerBuilder {
|
||||
context,
|
||||
info,
|
||||
block_level_boxes: Vec::new(),
|
||||
text_decoration_line,
|
||||
propagated_data: propagated_data.union(&info.style),
|
||||
have_already_seen_first_line_for_text_indent: false,
|
||||
anonymous_style: None,
|
||||
anonymous_table_content: Vec::new(),
|
||||
|
@ -215,7 +211,7 @@ where
|
|||
|
||||
if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish(
|
||||
self.context,
|
||||
self.text_decoration_line,
|
||||
self.propagated_data,
|
||||
!self.have_already_seen_first_line_for_text_indent,
|
||||
self.info.is_single_line_text_input(),
|
||||
self.info.style.writing_mode.to_bidi_level(),
|
||||
|
@ -266,10 +262,9 @@ where
|
|||
// > Note that text decorations are not propagated to floating and absolutely
|
||||
// > positioned descendants, nor to the contents of atomic inline-level descendants
|
||||
// > such as inline blocks and inline tables.
|
||||
let propagated_text_decoration_line = if inline_table {
|
||||
TextDecorationLine::NONE
|
||||
} else {
|
||||
self.text_decoration_line
|
||||
let propagated_data = match inline_table {
|
||||
true => self.propagated_data.without_text_decorations(),
|
||||
false => self.propagated_data,
|
||||
};
|
||||
|
||||
let contents: Vec<AnonymousTableContent<'dom, Node>> =
|
||||
|
@ -279,12 +274,7 @@ where
|
|||
_ => None,
|
||||
};
|
||||
|
||||
let ifc = Table::construct_anonymous(
|
||||
self.context,
|
||||
self.info,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
);
|
||||
let ifc = Table::construct_anonymous(self.context, self.info, contents, propagated_data);
|
||||
|
||||
if inline_table {
|
||||
self.inline_formatting_context_builder.push_atomic(ifc);
|
||||
|
@ -296,6 +286,7 @@ where
|
|||
info: anonymous_info,
|
||||
box_slot: BoxSlot::dummy(),
|
||||
kind: BlockLevelCreator::AnonymousTable { table_block },
|
||||
propagated_data,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -418,6 +409,7 @@ where
|
|||
info: info.clone(),
|
||||
box_slot: BoxSlot::dummy(),
|
||||
kind: BlockLevelCreator::OutsideMarker { contents },
|
||||
propagated_data: self.propagated_data.without_text_decorations(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -439,7 +431,7 @@ where
|
|||
display_inside,
|
||||
contents,
|
||||
// Text decorations are not propagated to atomic inline-level descendants.
|
||||
TextDecorationLine::NONE,
|
||||
self.propagated_data.without_text_decorations(),
|
||||
),
|
||||
);
|
||||
box_slot.set(LayoutBox::InlineLevel(atomic));
|
||||
|
@ -489,7 +481,7 @@ where
|
|||
.inline_formatting_context_builder
|
||||
.split_around_block_and_finish(
|
||||
self.context,
|
||||
self.text_decoration_line,
|
||||
self.propagated_data,
|
||||
!self.have_already_seen_first_line_for_text_indent,
|
||||
self.info.style.writing_mode.to_bidi_level(),
|
||||
)
|
||||
|
@ -497,7 +489,7 @@ where
|
|||
self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
|
||||
}
|
||||
|
||||
let propagated_text_decoration_line = self.text_decoration_line;
|
||||
let propagated_data = self.propagated_data;
|
||||
let kind = match contents {
|
||||
Contents::NonReplaced(contents) => match display_inside {
|
||||
DisplayInside::Flow { is_list_item }
|
||||
|
@ -506,7 +498,7 @@ where
|
|||
BlockLevelCreator::SameFormattingContextBlock(
|
||||
IntermediateBlockContainer::Deferred {
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
propagated_data,
|
||||
is_list_item,
|
||||
},
|
||||
)
|
||||
|
@ -514,7 +506,6 @@ where
|
|||
_ => BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents: contents.into(),
|
||||
propagated_text_decoration_line,
|
||||
},
|
||||
},
|
||||
Contents::Replaced(contents) => {
|
||||
|
@ -522,7 +513,6 @@ where
|
|||
BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -530,6 +520,7 @@ where
|
|||
info: info.clone(),
|
||||
box_slot,
|
||||
kind,
|
||||
propagated_data,
|
||||
});
|
||||
|
||||
// Any block also counts as the first line for the purposes of text indent. Even if
|
||||
|
@ -565,6 +556,7 @@ where
|
|||
info: info.clone(),
|
||||
box_slot,
|
||||
kind,
|
||||
propagated_data: self.propagated_data.without_text_decorations(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -583,6 +575,7 @@ where
|
|||
info,
|
||||
display_inside,
|
||||
contents,
|
||||
self.propagated_data,
|
||||
));
|
||||
box_slot.set(LayoutBox::InlineLevel(inline_level_box));
|
||||
return;
|
||||
|
@ -596,13 +589,14 @@ where
|
|||
info: info.clone(),
|
||||
box_slot,
|
||||
kind,
|
||||
propagated_data: self.propagated_data.without_text_decorations(),
|
||||
});
|
||||
}
|
||||
|
||||
fn end_ongoing_inline_formatting_context(&mut self) {
|
||||
if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish(
|
||||
self.context,
|
||||
self.text_decoration_line,
|
||||
self.propagated_data,
|
||||
!self.have_already_seen_first_line_for_text_indent,
|
||||
self.info.is_single_line_text_input(),
|
||||
self.info.style.writing_mode.to_bidi_level(),
|
||||
|
@ -638,6 +632,7 @@ where
|
|||
BlockContainer::InlineFormattingContext(inline_formatting_context),
|
||||
),
|
||||
),
|
||||
propagated_data: self.propagated_data,
|
||||
});
|
||||
|
||||
self.have_already_seen_first_line_for_text_indent = true;
|
||||
|
@ -663,14 +658,13 @@ where
|
|||
BlockLevelCreator::Independent {
|
||||
display_inside,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
} => {
|
||||
let context = IndependentFormattingContext::construct(
|
||||
context,
|
||||
info,
|
||||
display_inside,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
self.propagated_data,
|
||||
);
|
||||
ArcRefCell::new(BlockLevelBox::Independent(context))
|
||||
},
|
||||
|
@ -693,6 +687,7 @@ where
|
|||
info,
|
||||
display_inside,
|
||||
contents,
|
||||
self.propagated_data,
|
||||
))),
|
||||
BlockLevelCreator::OutsideMarker { contents } => {
|
||||
let marker_style = context
|
||||
|
@ -708,7 +703,7 @@ where
|
|||
context,
|
||||
&info.new_replacing_style(marker_style.clone()),
|
||||
contents,
|
||||
TextDecorationLine::empty(),
|
||||
self.propagated_data.without_text_decorations(),
|
||||
false, /* is_list_item */
|
||||
);
|
||||
ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker {
|
||||
|
@ -737,15 +732,9 @@ impl IntermediateBlockContainer {
|
|||
match self {
|
||||
IntermediateBlockContainer::Deferred {
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
propagated_data,
|
||||
is_list_item,
|
||||
} => BlockContainer::construct(
|
||||
context,
|
||||
info,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
is_list_item,
|
||||
),
|
||||
} => BlockContainer::construct(context, info, contents, propagated_data, is_list_item),
|
||||
IntermediateBlockContainer::InlineFormattingContext(block_container) => block_container,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ use style::computed_values::position::T as Position;
|
|||
use style::logical_geometry::WritingMode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Clear as StyleClear;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::dom::NodeExt;
|
||||
|
@ -29,7 +28,7 @@ use crate::fragment_tree::{BoxFragment, CollapsedMargin};
|
|||
use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
||||
use crate::positioned::{relative_adjustement, PositioningContext};
|
||||
use crate::style_ext::{DisplayInside, PaddingBorderMargin};
|
||||
use crate::ContainingBlock;
|
||||
use crate::{ContainingBlock, PropagatedBoxTreeData};
|
||||
|
||||
/// A floating box.
|
||||
#[derive(Debug)]
|
||||
|
@ -902,6 +901,7 @@ impl FloatBox {
|
|||
info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
|
||||
display_inside: DisplayInside,
|
||||
contents: Contents,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
) -> Self {
|
||||
Self {
|
||||
contents: IndependentFormattingContext::construct(
|
||||
|
@ -910,7 +910,7 @@ impl FloatBox {
|
|||
display_inside,
|
||||
contents,
|
||||
// Text decorations are not propagated to any out-of-flow descendants
|
||||
TextDecorationLine::NONE,
|
||||
propagated_data.without_text_decorations(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use std::char::{ToLowercase, ToUppercase};
|
|||
use icu_segmenter::WordSegmenter;
|
||||
use servo_arc::Arc;
|
||||
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
|
||||
use style::values::computed::TextDecorationLine;
|
||||
use style::values::specified::text::TextTransformCase;
|
||||
use unicode_bidi::Level;
|
||||
|
||||
|
@ -22,6 +21,7 @@ use crate::flow::float::FloatBox;
|
|||
use crate::formatting_contexts::IndependentFormattingContext;
|
||||
use crate::positioned::AbsolutelyPositionedBox;
|
||||
use crate::style_ext::ComputedValuesExt;
|
||||
use crate::PropagatedBoxTreeData;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct InlineFormattingContextBuilder {
|
||||
|
@ -271,7 +271,7 @@ impl InlineFormattingContextBuilder {
|
|||
pub(crate) fn split_around_block_and_finish(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
text_decoration_line: TextDecorationLine,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
has_first_formatted_line: bool,
|
||||
default_bidi_level: Level,
|
||||
) -> Option<InlineFormattingContext> {
|
||||
|
@ -303,7 +303,7 @@ impl InlineFormattingContextBuilder {
|
|||
|
||||
inline_builder_from_before_split.finish(
|
||||
layout_context,
|
||||
text_decoration_line,
|
||||
propagated_data,
|
||||
has_first_formatted_line,
|
||||
/* is_single_line_text_input = */ false,
|
||||
default_bidi_level,
|
||||
|
@ -314,7 +314,7 @@ impl InlineFormattingContextBuilder {
|
|||
pub(crate) fn finish(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
text_decoration_line: TextDecorationLine,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
has_first_formatted_line: bool,
|
||||
is_single_line_text_input: bool,
|
||||
default_bidi_level: Level,
|
||||
|
@ -329,7 +329,7 @@ impl InlineFormattingContextBuilder {
|
|||
Some(InlineFormattingContext::new_with_builder(
|
||||
old_builder,
|
||||
layout_context,
|
||||
text_decoration_line,
|
||||
propagated_data,
|
||||
has_first_formatted_line,
|
||||
is_single_line_text_input,
|
||||
default_bidi_level,
|
||||
|
|
|
@ -127,7 +127,7 @@ use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
|||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
||||
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{ConstraintSpace, ContainingBlock};
|
||||
use crate::{ConstraintSpace, ContainingBlock, PropagatedBoxTreeData};
|
||||
|
||||
// From gfxFontConstants.h in Firefox.
|
||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||
|
@ -1519,7 +1519,7 @@ impl InlineFormattingContext {
|
|||
pub(super) fn new_with_builder(
|
||||
builder: InlineFormattingContextBuilder,
|
||||
layout_context: &LayoutContext,
|
||||
text_decoration_line: TextDecorationLine,
|
||||
propagated_data: PropagatedBoxTreeData,
|
||||
has_first_formatted_line: bool,
|
||||
is_single_line_text_input: bool,
|
||||
starting_bidi_level: Level,
|
||||
|
@ -1570,7 +1570,7 @@ impl InlineFormattingContext {
|
|||
inline_items: builder.inline_items,
|
||||
inline_boxes: builder.inline_boxes,
|
||||
font_metrics,
|
||||
text_decoration_line,
|
||||
text_decoration_line: propagated_data.text_decoration,
|
||||
has_first_formatted_line,
|
||||
contains_floats: builder.contains_floats,
|
||||
is_single_line_text_input,
|
||||
|
|
|
@ -30,7 +30,7 @@ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
|||
use crate::replaced::ReplacedContents;
|
||||
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayInside};
|
||||
use crate::taffy::{TaffyItemBox, TaffyItemBoxInner};
|
||||
use crate::DefiniteContainingBlock;
|
||||
use crate::{DefiniteContainingBlock, PropagatedBoxTreeData};
|
||||
|
||||
pub struct BoxTree {
|
||||
/// Contains typically exactly one block-level box, which was generated by the root element.
|
||||
|
@ -289,6 +289,8 @@ fn construct_for_root_element<'dom>(
|
|||
|
||||
let contents = ReplacedContents::for_element(root_element, context)
|
||||
.map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced);
|
||||
|
||||
let propagated_data = PropagatedBoxTreeData::default().union(&info.style);
|
||||
let root_box = if box_style.position.is_absolutely_positioned() {
|
||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(ArcRefCell::new(
|
||||
AbsolutelyPositionedBox::construct(context, &info, display_inside, contents),
|
||||
|
@ -299,15 +301,15 @@ fn construct_for_root_element<'dom>(
|
|||
&info,
|
||||
display_inside,
|
||||
contents,
|
||||
propagated_data,
|
||||
))
|
||||
} else {
|
||||
let propagated_text_decoration_line = info.style.clone_text_decoration_line();
|
||||
BlockLevelBox::Independent(IndependentFormattingContext::construct(
|
||||
context,
|
||||
&info,
|
||||
display_inside,
|
||||
contents,
|
||||
propagated_text_decoration_line,
|
||||
propagated_data,
|
||||
))
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue