/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/layout/layout_root.rs
128 строк
5 KB
Martin Robinson
layout: Clear fragments and caches under layout roots after failed layout root layout (#46127)
06 июл 2026, 15:39
Не верифицирован
06 июл 2026, 15:39
a2e7b9f
Код
Авторство
О чём код?
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use script::layout_dom::ServoLayoutNode; use crate::context::LayoutContext; use crate::dom::{LayoutBox, NodeExt}; use crate::flexbox::FlexLevelBox; use crate::flow::BlockLevelBox; use crate::flow::inline::InlineItem; use crate::fragment_tree::Fragment; /// A data structure to track a layout root. /// /// Layout roots are places in the fragment tree where fragment tree layout can start. /// These are fragments that isolate fragment damage from their ancestors sufficiently /// that their ancestors can be preserved from one fragment tree layout to the next. /// **Currently, this only includes absolutely-or-fixed-positioned fragments that do not /// have any escaping fixed position fragments.**. /// /// During damage propagation, upward flowing fragment tree `Relayout` damage can be /// converted into `DescendantCollectedAsLayoutRoot` damage. When an ancestor of a layout /// root has fragment tree layout damage, `DescendantCollectedAsLayoutRoot` damage is /// converted back into `Relayout` and propagated up to the next layout root or the root /// of the DOM. /// /// This is only possible because the damage propagation traversal ensures that damage /// above the absolute (which might shift its static position) is converted back into /// `Relayout` damage. This means that the absolute should be placed with the fully /// adjusted static positioning rectangle between two layouts. /// /// It's possible that upon laying out a layout root again, a new fixed position element /// has started to escape from the layout root. In that case, a full fragment tree layout /// becomes necessary to rebuild the fragment properly. pub(crate) struct LayoutRoot<'dom> { node: ServoLayoutNode<'dom>, } impl<'dom> TryFrom<ServoLayoutNode<'dom>> for LayoutRoot<'dom> { type Error = (); fn try_from(node: ServoLayoutNode<'dom>) -> Result<Self, Self::Error> { if !node.is_absolutely_positioned() { return Err(()); } // Only accept previously known layout roots without fragmentation as compatible layout roots. let mut is_layout_root = false; node.with_layout_box_base(|base| { let fragments = base.fragments(); is_layout_root = fragments.len() == 1 && matches!(fragments.first(), Some(Fragment::LayoutRoot(..))); }); if !is_layout_root { return Err(()); } Ok(Self { node }) } } impl LayoutRoot<'_> { pub(crate) fn try_layout(&self, layout_context: &LayoutContext) -> bool { let Some(inner_layout_data) = self.node.inner_layout_data_mut() else { return false; }; let layout_box = inner_layout_data.self_box.clone(); let layout_box = layout_box.borrow(); let Some(layout_box) = &*layout_box else { return false; }; let positioned_box = match layout_box { LayoutBox::BlockLevel(block_level) => { let mut block_level = block_level.borrow_mut(); match &mut *block_level { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => { positioned_box.clone() }, _ => return false, } }, LayoutBox::InlineLevel(InlineItem::OutOfFlowAbsolutelyPositionedBox( positioned_box, _, )) => positioned_box.clone(), LayoutBox::FlexLevel(flex_level_box) => { let mut flex_level_box = flex_level_box.borrow_mut(); match &mut *flex_level_box { FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => { positioned_box.clone() }, _ => return false, } }, _ => return false, }; let positioned_box = positioned_box.borrow(); let formatting_context = &positioned_box.context; let fragments = formatting_context.base.fragments(); let Some(Fragment::LayoutRoot(layout_root_fragment)) = fragments.first() else { return false; }; let layout_inputs = formatting_context.layout_root_layout_inputs.borrow(); let Some(layout_inputs) = &*layout_inputs else { return false; }; // If an `Err` is returned here, that means that this layout root is no longer // a viable layout root and a full fragment tree layout is necessary. layout_inputs .layout( layout_context, formatting_context, &layout_root_fragment.fragment, ) .is_ok() } pub(crate) fn handle_failed_layout_root_layout(&self) { self.node .clear_fragments_and_dirty_fragment_caches_recursively(); } }