mirror of
https://github.com/servo/servo.git
synced 2025-09-20 11:50:09 +01:00
layout: Make bottom table captions obey relative positioning offsets (#39388)
#33426 only added support for relative positioning on captions with `caption-side: top`, but forgot about `caption-side: bottom`. This unifies the logic for both kinds of captions to avoid divergences. Testing: Modifying an existing test to also cover this case. Fixes: #39386 Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
d08be14c7a
commit
754c938722
5 changed files with 109 additions and 129 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4881,6 +4881,7 @@ dependencies = [
|
|||
"servo_malloc_size_of",
|
||||
"servo_url",
|
||||
"smallvec",
|
||||
"strum",
|
||||
"stylo",
|
||||
"stylo_atoms",
|
||||
"stylo_traits",
|
||||
|
|
|
@ -54,6 +54,7 @@ servo_config = { path = "../config" }
|
|||
servo_geometry = { path = "../geometry" }
|
||||
servo_url = { path = "../url" }
|
||||
smallvec = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
stylo = { workspace = true }
|
||||
stylo_atoms = { workspace = true }
|
||||
stylo_traits = { workspace = true }
|
||||
|
|
|
@ -11,6 +11,7 @@ use atomic_refcell::AtomicRef;
|
|||
use log::warn;
|
||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||
use servo_arc::Arc;
|
||||
use strum::{EnumIter, IntoEnumIterator};
|
||||
use style::Zero;
|
||||
use style::computed_values::border_collapse::T as BorderCollapse;
|
||||
use style::computed_values::box_sizing::T as BoxSizing;
|
||||
|
@ -1593,155 +1594,129 @@ impl<'a> TableLayout<'a> {
|
|||
collapsible_margins_in_children: CollapsedBlockMargins::zero(),
|
||||
};
|
||||
|
||||
table_layout
|
||||
.fragments
|
||||
.extend(self.table.captions.iter().filter_map(|caption| {
|
||||
let caption = caption.borrow();
|
||||
if caption.context.style().clone_caption_side() != CaptionSide::Top {
|
||||
return None;
|
||||
#[derive(EnumIter, PartialEq)]
|
||||
enum TableWrapperSection {
|
||||
TopCaptions,
|
||||
Grid,
|
||||
BottomCaptions,
|
||||
}
|
||||
impl TableWrapperSection {
|
||||
fn accepts_caption(&self, caption: &TableCaption) -> bool {
|
||||
match caption.context.style().clone_caption_side() {
|
||||
CaptionSide::Top => *self == TableWrapperSection::TopCaptions,
|
||||
CaptionSide::Bottom => *self == TableWrapperSection::BottomCaptions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for section in TableWrapperSection::iter() {
|
||||
if section == TableWrapperSection::Grid {
|
||||
let original_positioning_context_length = positioning_context.len();
|
||||
let mut caption_fragment =
|
||||
self.layout_caption(&caption, layout_context, positioning_context);
|
||||
let mut grid_fragment = self.layout_grid(
|
||||
layout_context,
|
||||
positioning_context,
|
||||
&containing_block_for_logical_conversion,
|
||||
containing_block_for_children,
|
||||
);
|
||||
|
||||
// The caption is not placed yet. Construct a rectangle for it in the adjusted containing block
|
||||
// for the table children and only then convert the result to physical geometry.
|
||||
let caption_pbm = caption_fragment
|
||||
// Take the baseline of the grid fragment, after adjusting it to be in the coordinate system
|
||||
// of the table wrapper.
|
||||
let logical_grid_content_rect = grid_fragment
|
||||
.content_rect
|
||||
.to_logical(&containing_block_for_logical_conversion);
|
||||
let grid_pbm = grid_fragment
|
||||
.padding_border_margin()
|
||||
.to_logical(table_writing_mode);
|
||||
table_layout.baselines = grid_fragment.baselines(table_writing_mode).offset(
|
||||
current_block_offset +
|
||||
logical_grid_content_rect.start_corner.block +
|
||||
grid_pbm.block_start,
|
||||
);
|
||||
|
||||
let caption_relative_offset = match caption_fragment.style.clone_position() {
|
||||
Position::Relative => {
|
||||
relative_adjustement(&caption_fragment.style, containing_block_for_children)
|
||||
},
|
||||
_ => LogicalVec2::zero(),
|
||||
};
|
||||
|
||||
caption_fragment.content_rect = LogicalRect {
|
||||
grid_fragment.content_rect = LogicalRect {
|
||||
start_corner: LogicalVec2 {
|
||||
inline: offset_from_wrapper.inline_start + caption_pbm.inline_start,
|
||||
block: current_block_offset + caption_pbm.block_start,
|
||||
} + caption_relative_offset,
|
||||
size: caption_fragment
|
||||
inline: offset_from_wrapper.inline_start + grid_pbm.inline_start,
|
||||
block: current_block_offset + grid_pbm.block_start,
|
||||
},
|
||||
size: grid_fragment
|
||||
.content_rect
|
||||
.size
|
||||
.to_logical(table_writing_mode),
|
||||
}
|
||||
.as_physical(Some(&containing_block_for_logical_conversion));
|
||||
|
||||
current_block_offset += caption_fragment
|
||||
.margin_rect()
|
||||
current_block_offset += grid_fragment
|
||||
.border_rect()
|
||||
.size
|
||||
.to_logical(table_writing_mode)
|
||||
.block;
|
||||
|
||||
let caption_fragment = Fragment::Box(ArcRefCell::new(caption_fragment));
|
||||
positioning_context.adjust_static_position_of_hoisted_fragments(
|
||||
&caption_fragment,
|
||||
original_positioning_context_length,
|
||||
);
|
||||
|
||||
caption.context.base.set_fragment(caption_fragment.clone());
|
||||
Some(caption_fragment)
|
||||
}));
|
||||
|
||||
let original_positioning_context_length = positioning_context.len();
|
||||
let mut grid_fragment = self.layout_grid(
|
||||
layout_context,
|
||||
positioning_context,
|
||||
&containing_block_for_logical_conversion,
|
||||
containing_block_for_children,
|
||||
);
|
||||
|
||||
// Take the baseline of the grid fragment, after adjusting it to be in the coordinate system
|
||||
// of the table wrapper.
|
||||
let logical_grid_content_rect = grid_fragment
|
||||
.content_rect
|
||||
.to_logical(&containing_block_for_logical_conversion);
|
||||
let grid_pbm = grid_fragment
|
||||
.padding_border_margin()
|
||||
.to_logical(table_writing_mode);
|
||||
table_layout.baselines = grid_fragment.baselines(table_writing_mode).offset(
|
||||
current_block_offset +
|
||||
logical_grid_content_rect.start_corner.block +
|
||||
grid_pbm.block_start,
|
||||
);
|
||||
|
||||
grid_fragment.content_rect = LogicalRect {
|
||||
start_corner: LogicalVec2 {
|
||||
inline: offset_from_wrapper.inline_start + grid_pbm.inline_start,
|
||||
block: current_block_offset + grid_pbm.block_start,
|
||||
},
|
||||
size: grid_fragment
|
||||
.content_rect
|
||||
.size
|
||||
.to_logical(table_writing_mode),
|
||||
}
|
||||
.as_physical(Some(&containing_block_for_logical_conversion));
|
||||
|
||||
current_block_offset += grid_fragment
|
||||
.border_rect()
|
||||
.size
|
||||
.to_logical(table_writing_mode)
|
||||
.block;
|
||||
if logical_grid_content_rect.size.inline < self.table_width {
|
||||
// This can happen when collapsing columns
|
||||
table_layout.content_inline_size_for_table =
|
||||
Some(logical_grid_content_rect.size.inline);
|
||||
}
|
||||
|
||||
let grid_fragment = Fragment::Box(ArcRefCell::new(grid_fragment));
|
||||
positioning_context.adjust_static_position_of_hoisted_fragments(
|
||||
&grid_fragment,
|
||||
original_positioning_context_length,
|
||||
);
|
||||
table_layout.fragments.push(grid_fragment);
|
||||
|
||||
table_layout
|
||||
.fragments
|
||||
.extend(self.table.captions.iter().filter_map(|caption| {
|
||||
let caption = caption.borrow();
|
||||
if caption.context.style().clone_caption_side() != CaptionSide::Bottom {
|
||||
return None;
|
||||
if logical_grid_content_rect.size.inline < self.table_width {
|
||||
// This can happen when collapsing columns
|
||||
table_layout.content_inline_size_for_table =
|
||||
Some(logical_grid_content_rect.size.inline);
|
||||
}
|
||||
|
||||
let original_positioning_context_length = positioning_context.len();
|
||||
let mut caption_fragment =
|
||||
self.layout_caption(&caption, layout_context, positioning_context);
|
||||
let grid_fragment = Fragment::Box(ArcRefCell::new(grid_fragment));
|
||||
positioning_context.adjust_static_position_of_hoisted_fragments(
|
||||
&grid_fragment,
|
||||
original_positioning_context_length,
|
||||
);
|
||||
table_layout.fragments.push(grid_fragment);
|
||||
} else {
|
||||
let caption_fragments = self.table.captions.iter().filter_map(|caption| {
|
||||
let caption = caption.borrow();
|
||||
if !section.accepts_caption(&caption) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// The caption is not placed yet. Construct a rectangle for it in the adjusted containing block
|
||||
// for the table children and only then convert the result to physical geometry.
|
||||
let caption_pbm = caption_fragment
|
||||
.padding_border_margin()
|
||||
.to_logical(table_writing_mode);
|
||||
caption_fragment.content_rect = LogicalRect {
|
||||
start_corner: LogicalVec2 {
|
||||
inline: offset_from_wrapper.inline_start + caption_pbm.inline_start,
|
||||
block: current_block_offset + caption_pbm.block_start,
|
||||
},
|
||||
size: caption_fragment
|
||||
.content_rect
|
||||
let original_positioning_context_length = positioning_context.len();
|
||||
let mut caption_fragment =
|
||||
self.layout_caption(&caption, layout_context, positioning_context);
|
||||
|
||||
// The caption is not placed yet. Construct a rectangle for it in the adjusted containing block
|
||||
// for the table children and only then convert the result to physical geometry.
|
||||
let caption_pbm = caption_fragment
|
||||
.padding_border_margin()
|
||||
.to_logical(table_writing_mode);
|
||||
|
||||
let caption_relative_offset = match caption_fragment.style.clone_position() {
|
||||
Position::Relative => relative_adjustement(
|
||||
&caption_fragment.style,
|
||||
containing_block_for_children,
|
||||
),
|
||||
_ => LogicalVec2::zero(),
|
||||
};
|
||||
|
||||
caption_fragment.content_rect = LogicalRect {
|
||||
start_corner: LogicalVec2 {
|
||||
inline: offset_from_wrapper.inline_start + caption_pbm.inline_start,
|
||||
block: current_block_offset + caption_pbm.block_start,
|
||||
} + caption_relative_offset,
|
||||
size: caption_fragment
|
||||
.content_rect
|
||||
.size
|
||||
.to_logical(table_writing_mode),
|
||||
}
|
||||
.as_physical(Some(&containing_block_for_logical_conversion));
|
||||
|
||||
current_block_offset += caption_fragment
|
||||
.margin_rect()
|
||||
.size
|
||||
.to_logical(table_writing_mode),
|
||||
}
|
||||
.as_physical(Some(&containing_block_for_logical_conversion));
|
||||
.to_logical(table_writing_mode)
|
||||
.block;
|
||||
|
||||
current_block_offset += caption_fragment
|
||||
.margin_rect()
|
||||
.size
|
||||
.to_logical(table_writing_mode)
|
||||
.block;
|
||||
let caption_fragment = Fragment::Box(ArcRefCell::new(caption_fragment));
|
||||
positioning_context.adjust_static_position_of_hoisted_fragments(
|
||||
&caption_fragment,
|
||||
original_positioning_context_length,
|
||||
);
|
||||
|
||||
let caption_fragment = Fragment::Box(ArcRefCell::new(caption_fragment));
|
||||
positioning_context.adjust_static_position_of_hoisted_fragments(
|
||||
&caption_fragment,
|
||||
original_positioning_context_length,
|
||||
);
|
||||
|
||||
caption.context.base.set_fragment(caption_fragment.clone());
|
||||
Some(caption_fragment)
|
||||
}));
|
||||
caption.context.base.set_fragment(caption_fragment.clone());
|
||||
Some(caption_fragment)
|
||||
});
|
||||
table_layout.fragments.extend(caption_fragments);
|
||||
}
|
||||
}
|
||||
|
||||
table_layout.content_block_size = current_block_offset + offset_from_wrapper.block_end;
|
||||
table_layout
|
||||
|
|
2
tests/wpt/meta/MANIFEST.json
vendored
2
tests/wpt/meta/MANIFEST.json
vendored
|
@ -257401,7 +257401,7 @@
|
|||
]
|
||||
],
|
||||
"caption-relative-positioning.html": [
|
||||
"2be1e86bc077f1293ccc9ea851f23123ae679157",
|
||||
"083a39fdf6800bfbec43a418068573f014c8adc5",
|
||||
[
|
||||
null,
|
||||
[
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
position: relative;
|
||||
background: green;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
height: 50px;
|
||||
margin-left: 200px;
|
||||
left: -200px;
|
||||
}
|
||||
|
@ -20,7 +20,10 @@
|
|||
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||
<div style="width: 100px; background: red;">
|
||||
<table>
|
||||
<caption></caption>
|
||||
<caption style="caption-side: top"></caption>
|
||||
</table>
|
||||
<table>
|
||||
<caption style="caption-side: bottom"></caption>
|
||||
</table>
|
||||
</div>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue