mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Reconstruct the box tree incrementally in some case
This commit is contained in:
parent
c4ea4b1d77
commit
a30bdc16dd
2 changed files with 157 additions and 15 deletions
|
@ -12,6 +12,7 @@ use crate::dom_traversal::{iter_child_nodes, Contents, NodeExt};
|
||||||
use crate::element_data::LayoutBox;
|
use crate::element_data::LayoutBox;
|
||||||
use crate::flow::construct::ContainsFloats;
|
use crate::flow::construct::ContainsFloats;
|
||||||
use crate::flow::float::FloatBox;
|
use crate::flow::float::FloatBox;
|
||||||
|
use crate::flow::inline::InlineLevelBox;
|
||||||
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
|
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
|
||||||
use crate::formatting_contexts::IndependentFormattingContext;
|
use crate::formatting_contexts::IndependentFormattingContext;
|
||||||
use crate::fragments::Fragment;
|
use crate::fragments::Fragment;
|
||||||
|
@ -22,9 +23,11 @@ use crate::positioned::PositioningContext;
|
||||||
use crate::replaced::ReplacedContent;
|
use crate::replaced::ReplacedContent;
|
||||||
use crate::sizing::ContentSizesRequest;
|
use crate::sizing::ContentSizesRequest;
|
||||||
use crate::style_ext::ComputedValuesExt;
|
use crate::style_ext::ComputedValuesExt;
|
||||||
use crate::style_ext::{Display, DisplayGeneratingBox};
|
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
|
||||||
|
use crate::wrapper::GetStyleAndLayoutData;
|
||||||
use crate::DefiniteContainingBlock;
|
use crate::DefiniteContainingBlock;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
use atomic_refcell::AtomicRef;
|
||||||
use euclid::default::{Point2D, Rect, Size2D};
|
use euclid::default::{Point2D, Rect, Size2D};
|
||||||
use fxhash::FxHashSet;
|
use fxhash::FxHashSet;
|
||||||
use gfx_traits::print_tree::PrintTree;
|
use gfx_traits::print_tree::PrintTree;
|
||||||
|
@ -88,6 +91,141 @@ impl BoxTree {
|
||||||
canvas_background: CanvasBackground::for_root_element(context, root_element),
|
canvas_background: CanvasBackground::for_root_element(context, root_element),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method attempts to incrementally update the box tree from an
|
||||||
|
/// arbitrary node that is not necessarily the document's root element.
|
||||||
|
///
|
||||||
|
/// If the node is not a valid candidate for incremental update, the method
|
||||||
|
/// loops over its parent. The only valid candidates for now are absolutely
|
||||||
|
/// positioned boxes which don't change their outside display mode (i.e. it
|
||||||
|
/// will not attempt to update from an absolutely positioned inline element
|
||||||
|
/// which became an absolutely positioned block element). The value `true`
|
||||||
|
/// is returned if an incremental update could be done, and `false`
|
||||||
|
/// otherwise.
|
||||||
|
///
|
||||||
|
/// There are various pain points that need to be taken care of to extend
|
||||||
|
/// the set of valid candidates:
|
||||||
|
/// * it is not obvious how to incrementally check whether a block
|
||||||
|
/// formatting context still contains floats or not;
|
||||||
|
/// * the propagation of text decorations towards node descendants is
|
||||||
|
/// hard to do incrementally with our current representation of boxes
|
||||||
|
/// * how intrinsic content sizes are computed eagerly makes it hard
|
||||||
|
/// to update those sizes for ancestors of the node from which we
|
||||||
|
/// made an incremental update.
|
||||||
|
pub fn update<'dom, Node>(context: &LayoutContext, mut dirty_node: Node) -> bool
|
||||||
|
where
|
||||||
|
Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync,
|
||||||
|
{
|
||||||
|
enum UpdatePoint {
|
||||||
|
AbsolutelyPositionedBlockLevelBox(ArcRefCell<BlockLevelBox>),
|
||||||
|
AbsolutelyPositionedInlineLevelBox(ArcRefCell<InlineLevelBox>),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_point<'dom, Node>(
|
||||||
|
node: Node,
|
||||||
|
) -> Option<(Arc<ComputedValues>, DisplayInside, UpdatePoint)>
|
||||||
|
where
|
||||||
|
Node: NodeExt<'dom>,
|
||||||
|
{
|
||||||
|
if !node.is_element() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.type_id() == LayoutNodeType::Element(LayoutElementType::HTMLBodyElement) {
|
||||||
|
// This can require changes to the canvas background.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't update unstyled nodes.
|
||||||
|
let data = node.get_style_and_layout_data()?;
|
||||||
|
|
||||||
|
// Don't update nodes that have pseudo-elements.
|
||||||
|
let element_data = data.style_data.element_data.borrow();
|
||||||
|
if !element_data.styles.pseudos.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout_data = data.layout_data.borrow();
|
||||||
|
if layout_data.pseudo_before_box.borrow().is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if layout_data.pseudo_after_box.borrow().is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let primary_style = element_data.styles.primary();
|
||||||
|
let box_style = primary_style.get_box();
|
||||||
|
|
||||||
|
if !box_style.position.is_absolutely_positioned() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let display_inside = match Display::from(box_style.display) {
|
||||||
|
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => {
|
||||||
|
inside
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let update_point =
|
||||||
|
match &*AtomicRef::filter_map(layout_data.self_box.borrow(), Option::as_ref)? {
|
||||||
|
LayoutBox::DisplayContents => return None,
|
||||||
|
LayoutBox::BlockLevel(block_level_box) => match &*block_level_box.borrow() {
|
||||||
|
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_)
|
||||||
|
if box_style.position.is_absolutely_positioned() =>
|
||||||
|
{
|
||||||
|
UpdatePoint::AbsolutelyPositionedBlockLevelBox(block_level_box.clone())
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
|
LayoutBox::InlineLevel(inline_level_box) => match &*inline_level_box.borrow() {
|
||||||
|
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_)
|
||||||
|
if box_style.position.is_absolutely_positioned() =>
|
||||||
|
{
|
||||||
|
UpdatePoint::AbsolutelyPositionedInlineLevelBox(
|
||||||
|
inline_level_box.clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Some((primary_style.clone(), display_inside, update_point))
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Some((primary_style, display_inside, update_point)) = update_point(dirty_node) {
|
||||||
|
let contents = ReplacedContent::for_element(dirty_node)
|
||||||
|
.map_or(Contents::OfElement, Contents::Replaced);
|
||||||
|
let out_of_flow_absolutely_positioned_box =
|
||||||
|
Arc::new(AbsolutelyPositionedBox::construct(
|
||||||
|
context,
|
||||||
|
dirty_node,
|
||||||
|
primary_style,
|
||||||
|
display_inside,
|
||||||
|
contents,
|
||||||
|
));
|
||||||
|
match update_point {
|
||||||
|
UpdatePoint::AbsolutelyPositionedBlockLevelBox(block_level_box) => {
|
||||||
|
*block_level_box.borrow_mut() =
|
||||||
|
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
||||||
|
out_of_flow_absolutely_positioned_box,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
UpdatePoint::AbsolutelyPositionedInlineLevelBox(inline_level_box) => {
|
||||||
|
*inline_level_box.borrow_mut() =
|
||||||
|
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
|
||||||
|
out_of_flow_absolutely_positioned_box,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
dirty_node = match dirty_node.parent_node() {
|
||||||
|
Some(parent) => parent,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_for_root_element<'dom>(
|
fn construct_for_root_element<'dom>(
|
||||||
|
|
|
@ -1081,39 +1081,43 @@ impl LayoutThread {
|
||||||
let rayon_pool = STYLE_THREAD_POOL.pool();
|
let rayon_pool = STYLE_THREAD_POOL.pool();
|
||||||
let rayon_pool = rayon_pool.as_ref();
|
let rayon_pool = rayon_pool.as_ref();
|
||||||
|
|
||||||
let box_tree = if token.should_traverse() {
|
if token.should_traverse() {
|
||||||
driver::traverse_dom(&traversal, token, rayon_pool);
|
let dirty_root = driver::traverse_dom(&traversal, token, rayon_pool).as_node();
|
||||||
|
|
||||||
let root_node = root_element.as_node();
|
let root_node = root_element.as_node();
|
||||||
let build_box_tree = || BoxTree::construct(traversal.context(), root_node);
|
let mut box_tree = self.box_tree.borrow_mut();
|
||||||
let box_tree = if let Some(pool) = rayon_pool {
|
let box_tree = &mut *box_tree;
|
||||||
|
let mut build_box_tree = || {
|
||||||
|
if !BoxTree::update(traversal.context(), dirty_root) {
|
||||||
|
*box_tree = Some(Arc::new(BoxTree::construct(traversal.context(), root_node)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(pool) = rayon_pool {
|
||||||
pool.install(build_box_tree)
|
pool.install(build_box_tree)
|
||||||
} else {
|
} else {
|
||||||
build_box_tree()
|
build_box_tree()
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Arc::new(box_tree))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
layout_context = traversal.destroy();
|
|
||||||
|
|
||||||
if let Some(box_tree) = box_tree {
|
|
||||||
let viewport_size = Size2D::new(
|
let viewport_size = Size2D::new(
|
||||||
self.viewport_size.width.to_f32_px(),
|
self.viewport_size.width.to_f32_px(),
|
||||||
self.viewport_size.height.to_f32_px(),
|
self.viewport_size.height.to_f32_px(),
|
||||||
);
|
);
|
||||||
let run_layout = || box_tree.layout(&layout_context, viewport_size);
|
let run_layout = || {
|
||||||
|
box_tree
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.layout(traversal.context(), viewport_size)
|
||||||
|
};
|
||||||
let fragment_tree = Arc::new(if let Some(pool) = rayon_pool {
|
let fragment_tree = Arc::new(if let Some(pool) = rayon_pool {
|
||||||
pool.install(run_layout)
|
pool.install(run_layout)
|
||||||
} else {
|
} else {
|
||||||
run_layout()
|
run_layout()
|
||||||
});
|
});
|
||||||
*self.box_tree.borrow_mut() = Some(box_tree);
|
|
||||||
*self.fragment_tree.borrow_mut() = Some(fragment_tree);
|
*self.fragment_tree.borrow_mut() = Some(fragment_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layout_context = traversal.destroy();
|
||||||
|
|
||||||
for element in elements_with_snapshot {
|
for element in elements_with_snapshot {
|
||||||
unsafe { element.unset_snapshot_flags() }
|
unsafe { element.unset_snapshot_flags() }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue