Layout: Continue support incremental box tree reconstruction for flex&taffy level box (#37854)

Layout: Continue support incremental box tree reconstruction for
flex&taffy level box

This change reuse the flex/taffy level box from old box slot if the box
slot is valid and there is no LayoutDamage to the element.

Testing: This should not change observable behavior and is thus covered
by existing WPT tests.

Signed-off-by: sharpshooter_pt <ibluegalaxy_taoj@163.com>
This commit is contained in:
JoeDow 2025-07-04 17:35:09 +08:00 committed by GitHub
parent 934b3341d7
commit 068406ee6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 59 additions and 32 deletions

View file

@ -12,7 +12,7 @@ use style::selector_parser::PseudoElement;
use crate::PropagatedBoxTreeData; use crate::PropagatedBoxTreeData;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom::BoxSlot; use crate::dom::{BoxSlot, LayoutBox};
use crate::dom_traversal::{Contents, NodeAndStyleInfo, TraversalHandler}; use crate::dom_traversal::{Contents, NodeAndStyleInfo, TraversalHandler};
use crate::flow::inline::construct::InlineFormattingContextBuilder; use crate::flow::inline::construct::InlineFormattingContextBuilder;
use crate::flow::{BlockContainer, BlockFormattingContext}; use crate::flow::{BlockContainer, BlockFormattingContext};
@ -78,10 +78,9 @@ impl<'dom> ModernContainerJob<'dom> {
}; };
Some(ModernItem { Some(ModernItem {
kind: ModernItemKind::InFlow, kind: ModernItemKind::InFlow(formatting_context),
order: 0, order: 0,
box_slot: None, box_slot: None,
formatting_context,
}) })
}, },
ModernContainerJob::ElementOrPseudoElement { ModernContainerJob::ElementOrPseudoElement {
@ -91,6 +90,25 @@ impl<'dom> ModernContainerJob<'dom> {
box_slot, box_slot,
} => { } => {
let is_abspos = info.style.get_box().position.is_absolutely_positioned(); let is_abspos = info.style.get_box().position.is_absolutely_positioned();
let order = if is_abspos {
0
} else {
info.style.clone_order()
};
if let Some(layout_box) = box_slot
.take_layout_box_if_undamaged(info.damage)
.and_then(|layout_box| match &layout_box {
LayoutBox::FlexLevel(_) | LayoutBox::TaffyItemBox(_) => Some(layout_box),
_ => None,
})
{
return Some(ModernItem {
kind: ModernItemKind::ReusedBox(layout_box),
order,
box_slot: Some(box_slot),
});
}
// Text decorations are not propagated to any out-of-flow descendants. In addition, // Text decorations are not propagated to any out-of-flow descendants. In addition,
// absolutes don't affect the size of ancestors so it is fine to allow descendent // absolutes don't affect the size of ancestors so it is fine to allow descendent
@ -108,21 +126,16 @@ impl<'dom> ModernContainerJob<'dom> {
propagated_data, propagated_data,
); );
if is_abspos { let kind = if is_abspos {
Some(ModernItem { ModernItemKind::OutOfFlow(formatting_context)
kind: ModernItemKind::OutOfFlow,
order: 0,
box_slot: Some(box_slot),
formatting_context,
})
} else { } else {
ModernItemKind::InFlow(formatting_context)
};
Some(ModernItem { Some(ModernItem {
kind: ModernItemKind::InFlow, kind,
order: info.style.clone_order(), order,
box_slot: Some(box_slot), box_slot: Some(box_slot),
formatting_context,
}) })
}
}, },
} }
} }
@ -146,15 +159,15 @@ impl ModernContainerTextRun<'_> {
} }
pub(crate) enum ModernItemKind { pub(crate) enum ModernItemKind {
InFlow, InFlow(IndependentFormattingContext),
OutOfFlow, OutOfFlow(IndependentFormattingContext),
ReusedBox(LayoutBox),
} }
pub(crate) struct ModernItem<'dom> { pub(crate) struct ModernItem<'dom> {
pub kind: ModernItemKind, pub kind: ModernItemKind,
pub order: i32, pub order: i32,
pub box_slot: Option<BoxSlot<'dom>>, pub box_slot: Option<BoxSlot<'dom>>,
pub formatting_context: IndependentFormattingContext,
} }
impl<'dom> TraversalHandler<'dom> for ModernContainerBuilder<'_, 'dom> { impl<'dom> TraversalHandler<'dom> for ModernContainerBuilder<'_, 'dom> {

View file

@ -113,14 +113,21 @@ impl FlexContainer {
.into_iter() .into_iter()
.map(|item| { .map(|item| {
let box_ = match item.kind { let box_ = match item.kind {
ModernItemKind::InFlow => ArcRefCell::new(FlexLevelBox::FlexItem( ModernItemKind::InFlow(independent_formatting_context) => ArcRefCell::new(
FlexItemBox::new(item.formatting_context), FlexLevelBox::FlexItem(FlexItemBox::new(independent_formatting_context)),
)), ),
ModernItemKind::OutOfFlow => { ModernItemKind::OutOfFlow(independent_formatting_context) => {
let abs_pos_box = let abs_pos_box = ArcRefCell::new(AbsolutelyPositionedBox::new(
ArcRefCell::new(AbsolutelyPositionedBox::new(item.formatting_context)); independent_formatting_context,
));
ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(abs_pos_box)) ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(abs_pos_box))
}, },
ModernItemKind::ReusedBox(layout_box) => match layout_box {
LayoutBox::FlexLevel(flex_level_box) => flex_level_box,
_ => unreachable!(
"Undamaged flex level element should be associated with flex level box"
),
},
}; };
if let Some(box_slot) = item.box_slot { if let Some(box_slot) = item.box_slot {

View file

@ -46,16 +46,23 @@ impl TaffyContainer {
.into_iter() .into_iter()
.map(|item| { .map(|item| {
let box_ = match item.kind { let box_ = match item.kind {
ModernItemKind::InFlow => ArcRefCell::new(TaffyItemBox::new( ModernItemKind::InFlow(independent_formatting_context) => {
TaffyItemBoxInner::InFlowBox(item.formatting_context), ArcRefCell::new(TaffyItemBox::new(TaffyItemBoxInner::InFlowBox(
)), independent_formatting_context,
ModernItemKind::OutOfFlow => { )))
let abs_pos_box = },
ArcRefCell::new(AbsolutelyPositionedBox::new(item.formatting_context)); ModernItemKind::OutOfFlow(independent_formatting_context) => {
let abs_pos_box = ArcRefCell::new(AbsolutelyPositionedBox::new(
independent_formatting_context,
));
ArcRefCell::new(TaffyItemBox::new( ArcRefCell::new(TaffyItemBox::new(
TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(abs_pos_box), TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(abs_pos_box),
)) ))
}, },
ModernItemKind::ReusedBox(layout_box) => match layout_box {
LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box,
_ => unreachable!("Undamaged taffy level element should be associated with taffy level box"),
},
}; };
if let Some(box_slot) = item.box_slot { if let Some(box_slot) = item.box_slot {