Auto merge of #27399 - Manishearth:auto-abspos-hoist-shared, r=SimonSapin

Handle `inset: auto` values for absolutely positioned elements

Fixes #27387

This is the same as https://github.com/servo/servo/pull/27397 , but written to share the box offset data instead of bubbling the hoisted box up based on comments from @SimonSapin.
This commit is contained in:
bors-servo 2020-07-27 18:45:42 -04:00 committed by GitHub
commit c7bdb1bcc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
105 changed files with 138 additions and 207 deletions

View file

@ -916,7 +916,7 @@ impl AbsoluteOrFixedPositionedFragment {
stacking_context: &mut StackingContext,
) {
let hoisted_fragment = self.hoisted_fragment.borrow();
let fragment_ref = match hoisted_fragment.as_ref() {
let fragment_ref = match hoisted_fragment.fragment.as_ref() {
Some(fragment_ref) => fragment_ref,
None => unreachable!("Found hoisted box with missing fragment."),
};

View file

@ -201,7 +201,18 @@ fn layout_block_level_children(
placement_state.current_margin.solve() + fragment_block_size;
placement_state.current_margin = fragment_block_margins.end;
},
Fragment::Anonymous(_) | Fragment::AbsoluteOrFixedPositioned(_) => {},
Fragment::AbsoluteOrFixedPositioned(fragment) => {
let offset = Vec2 {
block: placement_state.current_margin.solve() +
placement_state.current_block_direction_position,
inline: Length::new(0.),
};
fragment
.hoisted_fragment
.borrow_mut()
.adjust_offsets(offset);
},
Fragment::Anonymous(_) => {},
_ => unreachable!(),
}
}
@ -352,6 +363,9 @@ impl BlockLevelBox {
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
box_.clone(),
// This is incorrect, however we do not know the
// correct positioning until later, in place_block_level_fragment,
// and this value will be adjusted there
Vec2::zero(),
tree_rank,
containing_block,

View file

@ -8,6 +8,7 @@ use crate::geom::flow_relative::{Rect, Sides};
use crate::geom::{PhysicalPoint, PhysicalRect};
#[cfg(debug_assertions)]
use crate::layout_debug;
use crate::positioned::HoistedSharedFragment;
use gfx::font::FontMetrics as GfxFontMetrics;
use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree;
@ -74,7 +75,7 @@ pub(crate) enum Fragment {
#[derive(Serialize)]
pub(crate) struct AbsoluteOrFixedPositionedFragment {
pub position: ComputedPosition,
pub hoisted_fragment: ArcRefCell<Option<ArcRefCell<Fragment>>>,
pub hoisted_fragment: ArcRefCell<HoistedSharedFragment>,
}
#[derive(Serialize)]

View file

@ -41,15 +41,41 @@ pub(crate) struct HoistedAbsolutelyPositionedBox {
/// static positions when going up the tree.
pub(crate) tree_rank: usize,
box_offsets: Vec2<AbsoluteBoxOffsets>,
/// A reference to a Fragment which is shared between this `HoistedAbsolutelyPositionedBox`
/// and its placeholder `AbsoluteOrFixedPositionedFragment` in the original tree position.
/// This will be used later in order to paint this hoisted box in tree order.
pub fragment: ArcRefCell<Option<ArcRefCell<Fragment>>>,
pub fragment: ArcRefCell<HoistedSharedFragment>,
}
#[derive(Clone, Debug)]
/// A reference to a Fragment which is shared between `HoistedAbsolutelyPositionedBox`
/// and its placeholder `AbsoluteOrFixedPositionedFragment` in the original tree position.
/// This will be used later in order to paint this hoisted box in tree order.
#[derive(Serialize)]
pub(crate) struct HoistedSharedFragment {
pub(crate) fragment: Option<ArcRefCell<Fragment>>,
pub(crate) box_offsets: Vec2<AbsoluteBoxOffsets>,
}
impl HoistedSharedFragment {
pub(crate) fn new(box_offsets: Vec2<AbsoluteBoxOffsets>) -> Self {
HoistedSharedFragment {
fragment: None,
box_offsets,
}
}
}
impl HoistedSharedFragment {
/// In some cases `inset: auto`-positioned elements do not know their precise
/// position until after they're hoisted. This lets us adjust auto values
/// after the fact.
pub(crate) fn adjust_offsets(&mut self, offsets: Vec2<Length>) {
self.box_offsets.inline.adjust_offset(offsets.inline);
self.box_offsets.block.adjust_offset(offsets.block);
}
}
#[derive(Clone, Debug, Serialize)]
pub(crate) enum AbsoluteBoxOffsets {
StaticStart {
start: Length,
@ -66,6 +92,15 @@ pub(crate) enum AbsoluteBoxOffsets {
},
}
impl AbsoluteBoxOffsets {
fn adjust_offset(&mut self, new_offset: Length) {
match *self {
AbsoluteBoxOffsets::StaticStart { ref mut start } => *start = new_offset,
_ => (),
}
}
}
impl AbsolutelyPositionedBox {
pub fn construct<'dom>(
context: &LayoutContext,
@ -129,8 +164,7 @@ impl AbsolutelyPositionedBox {
};
HoistedAbsolutelyPositionedBox {
tree_rank,
box_offsets,
fragment: ArcRefCell::new(None),
fragment: ArcRefCell::new(HoistedSharedFragment::new(box_offsets)),
absolutely_positioned_box: self_,
}
}
@ -357,7 +391,7 @@ impl HoistedAbsolutelyPositionedBox {
containing_block,
)));
*box_.fragment.borrow_mut() = Some(new_fragment.clone());
box_.fragment.borrow_mut().fragment = Some(new_fragment.clone());
new_fragment
},
Vec::new,
@ -370,7 +404,7 @@ impl HoistedAbsolutelyPositionedBox {
for_nearest_containing_block_for_all_descendants,
containing_block,
)));
*box_.fragment.borrow_mut() = Some(new_fragment.clone());
box_.fragment.borrow_mut().fragment = Some(new_fragment.clone());
new_fragment
}))
}
@ -409,13 +443,15 @@ impl HoistedAbsolutelyPositionedBox {
.content_box_size(&containing_block.into(), &pbm),
};
let shared_fragment = self.fragment.borrow();
let inline_axis = solve_axis(
cbis,
pbm.padding_border_sums.inline,
pbm.margin.inline_start,
pbm.margin.inline_end,
/* avoid_negative_margin_start */ true,
&self.box_offsets.inline,
&shared_fragment.box_offsets.inline,
size.inline,
);
@ -425,7 +461,7 @@ impl HoistedAbsolutelyPositionedBox {
pbm.margin.block_start,
pbm.margin.block_end,
/* avoid_negative_margin_start */ false,
&self.box_offsets.block,
&shared_fragment.box_offsets.block,
size.block,
);
@ -655,11 +691,13 @@ fn adjust_static_positions(
_ => unreachable!(),
};
if let AbsoluteBoxOffsets::StaticStart { start } = &mut abspos_fragment.box_offsets.inline {
let mut shared_fragment = abspos_fragment.fragment.borrow_mut();
if let AbsoluteBoxOffsets::StaticStart { start } = &mut shared_fragment.box_offsets.inline {
*start += child_fragment_rect.start_corner.inline;
}
if let AbsoluteBoxOffsets::StaticStart { start } = &mut abspos_fragment.box_offsets.block {
if let AbsoluteBoxOffsets::StaticStart { start } = &mut shared_fragment.box_offsets.block {
*start += child_fragment_rect.start_corner.block;
}
}