mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Do not hoist floated fragments
Instead of hoisting floated fragments to be siblings of the fragment created by their containing block formatting context, keep them in "normal" fragment tree position and adjust their positioning to be relative to the containing block. This means that float fragments follow the existing invariants of the fragment tree and properly handle hit testing, painting order, and relative positioning. The tradeoff here is more complexity tracking the containing block offsets from the block formatting context (including handling collapsed margins), but less complexity dealing with hoisting / shared ownership in addition to the correctness benefits. Some tests are failing now because this change revealed some additional shortcomings with clearing block formatting context content size past the end of their contained floats. This will be fixed in a followup change. Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
cdec48328e
commit
25f6cc04a2
22 changed files with 250 additions and 296 deletions
|
@ -26,11 +26,12 @@ use webrender_api::{FontInstanceKey, ImageKey};
|
|||
#[derive(Serialize)]
|
||||
pub(crate) enum Fragment {
|
||||
Box(BoxFragment),
|
||||
// The original document position of a float in the document tree.
|
||||
Float,
|
||||
// A float hoisted up from its original position (where a placeholder `Fragment::Float` is) to
|
||||
// its containing block.
|
||||
HoistedFloat(HoistedFloatFragment),
|
||||
/// Floating content. A floated fragment is very similar to a normal
|
||||
/// [BoxFragment] but it isn't positioned using normal in block flow
|
||||
/// positioning rules (margin collapse, etc). Instead, they are laid out by
|
||||
/// the [SequentialLayoutState] of their float containing block formatting
|
||||
/// context.
|
||||
Float(BoxFragment),
|
||||
Anonymous(AnonymousFragment),
|
||||
/// Absolute and fixed position fragments are hoisted up so that they
|
||||
/// are children of the BoxFragment that establishes their containing
|
||||
|
@ -45,13 +46,6 @@ pub(crate) enum Fragment {
|
|||
IFrame(IFrameFragment),
|
||||
}
|
||||
|
||||
// A float hoisted up from its original position (where a placeholder `Fragment::Float` is) to its
|
||||
// containing block.
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct HoistedFloatFragment {
|
||||
pub fragment: ArcRefCell<Fragment>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct BoxFragment {
|
||||
pub base: BaseFragment,
|
||||
|
@ -171,9 +165,7 @@ impl Fragment {
|
|||
pub fn offset_inline(&mut self, offset: &Length) {
|
||||
let position = match self {
|
||||
Fragment::Box(f) => &mut f.content_rect.start_corner,
|
||||
Fragment::HoistedFloat(_) |
|
||||
Fragment::Float |
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => return,
|
||||
Fragment::Float(_) | Fragment::AbsoluteOrFixedPositioned(_) => return,
|
||||
Fragment::Anonymous(f) => &mut f.rect.start_corner,
|
||||
Fragment::Text(f) => &mut f.rect.start_corner,
|
||||
Fragment::Image(f) => &mut f.rect.start_corner,
|
||||
|
@ -187,12 +179,11 @@ impl Fragment {
|
|||
Some(match self {
|
||||
Fragment::Box(fragment) => &fragment.base,
|
||||
Fragment::Text(fragment) => &fragment.base,
|
||||
Fragment::Float => return None,
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => return None,
|
||||
Fragment::Anonymous(fragment) => &fragment.base,
|
||||
Fragment::Image(fragment) => &fragment.base,
|
||||
Fragment::IFrame(fragment) => &fragment.base,
|
||||
Fragment::HoistedFloat(_) => return None,
|
||||
Fragment::Float(fragment) => &fragment.base,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -203,8 +194,11 @@ impl Fragment {
|
|||
pub fn print(&self, tree: &mut PrintTree) {
|
||||
match self {
|
||||
Fragment::Box(fragment) => fragment.print(tree),
|
||||
Fragment::HoistedFloat(fragment) => fragment.print(tree),
|
||||
Fragment::Float => tree.add_item(format!("Float")),
|
||||
Fragment::Float(fragment) => {
|
||||
tree.new_level(format!("Float"));
|
||||
fragment.print(tree);
|
||||
tree.end_level();
|
||||
},
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => {
|
||||
tree.add_item("AbsoluteOrFixedPositioned".to_string());
|
||||
},
|
||||
|
@ -220,11 +214,10 @@ impl Fragment {
|
|||
containing_block: &PhysicalRect<Length>,
|
||||
) -> PhysicalRect<Length> {
|
||||
match self {
|
||||
Fragment::Box(fragment) => fragment.scrollable_overflow_for_parent(&containing_block),
|
||||
Fragment::HoistedFloat(fragment) => {
|
||||
(*fragment.fragment.borrow()).scrollable_overflow(&containing_block)
|
||||
Fragment::Box(fragment) | Fragment::Float(fragment) => {
|
||||
fragment.scrollable_overflow_for_parent(&containing_block)
|
||||
},
|
||||
Fragment::Float | Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
|
||||
Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(),
|
||||
Fragment::Text(fragment) => fragment
|
||||
.rect
|
||||
|
@ -250,7 +243,7 @@ impl Fragment {
|
|||
}
|
||||
|
||||
match self {
|
||||
Fragment::Box(fragment) => {
|
||||
Fragment::Box(fragment) | Fragment::Float(fragment) => {
|
||||
let content_rect = fragment
|
||||
.content_rect
|
||||
.to_physical(fragment.style.writing_mode, containing_block)
|
||||
|
@ -294,15 +287,6 @@ impl Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
impl HoistedFloatFragment {
|
||||
#[allow(dead_code)]
|
||||
pub fn print(&self, tree: &mut PrintTree) {
|
||||
tree.new_level(format!("HoistedFloatFragment"));
|
||||
self.fragment.borrow().print(tree);
|
||||
tree.end_level();
|
||||
}
|
||||
}
|
||||
|
||||
impl AnonymousFragment {
|
||||
pub fn new(rect: Rect<Length>, children: Vec<Fragment>, mode: WritingMode) -> Self {
|
||||
// FIXME(mrobinson, bug 25564): We should be using the containing block
|
||||
|
@ -450,19 +434,17 @@ impl BoxFragment {
|
|||
\ncontent={:?}\
|
||||
\npadding rect={:?}\
|
||||
\nborder rect={:?}\
|
||||
\nclearance={:?}\
|
||||
\nscrollable_overflow={:?}\
|
||||
\noverflow={:?} / {:?}\
|
||||
\noverconstrained={:?}
|
||||
\nstyle={:p}",
|
||||
\noverflow={:?} / {:?}",
|
||||
self.base,
|
||||
self.content_rect,
|
||||
self.padding_rect(),
|
||||
self.border_rect(),
|
||||
self.clearance,
|
||||
self.scrollable_overflow(&PhysicalRect::zero()),
|
||||
self.style.get_box().overflow_x,
|
||||
self.style.get_box().overflow_y,
|
||||
self.overconstrained,
|
||||
self.style,
|
||||
));
|
||||
|
||||
for child in &self.children {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue