mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Currently, we just rebuild boxes for all nodes from the update point downward, and the unique valid candidates as update point is just the absolutely positioned ancestor of the style recalc dirty dom root node. It is quite crude way for incremental box tree update and incremental layout, because it will lead to a lot of boxes to be rebuilt even though their originating nodes have no style change, i.e. only some child nodes are newly added or removed. Meanwhile, all cached fragments need to be invalidated from the update point downward, even though there is no any change of the layout constraits and containing block for some of those rebuilt boxes. To preserve more boxes and cached fragments as much as possible, this PR try to rebuild those boxes whose originating node has `REBUILD_BOX` restyle damage and try to repair those boxes whose originating node has `REPAIR_BOX` damage. It is a relative big task. To implement it step by step, this PR only repair and reuse the block level boxes. In the future, the others kind of boxes will be repaired or reused. Signed-off-by: coding-joedow <ibluegalaxy_taoj@163.com>
154 lines
5.8 KiB
Rust
154 lines
5.8 KiB
Rust
/* 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 std::fmt::{Debug, Formatter};
|
|
|
|
use app_units::Au;
|
|
use atomic_refcell::AtomicRefCell;
|
|
use malloc_size_of_derive::MallocSizeOf;
|
|
use servo_arc::Arc;
|
|
use style::properties::ComputedValues;
|
|
|
|
use crate::context::LayoutContext;
|
|
use crate::formatting_contexts::Baselines;
|
|
use crate::fragment_tree::{BaseFragmentInfo, CollapsedBlockMargins, Fragment, SpecificLayoutInfo};
|
|
use crate::geom::SizeConstraint;
|
|
use crate::positioned::PositioningContext;
|
|
use crate::sizing::{ComputeInlineContentSizes, InlineContentSizesResult};
|
|
use crate::{ConstraintSpace, ContainingBlockSize};
|
|
|
|
/// A box tree node that handles containing information about style and the original DOM
|
|
/// node or pseudo-element that it is based on. This also handles caching of layout values
|
|
/// such as the inline content sizes to avoid recalculating these values during layout
|
|
/// passes.
|
|
///
|
|
/// In the future, this will hold layout results to support incremental layout.
|
|
#[derive(MallocSizeOf)]
|
|
pub(crate) struct LayoutBoxBase {
|
|
pub base_fragment_info: BaseFragmentInfo,
|
|
pub style: Arc<ComputedValues>,
|
|
pub cached_inline_content_size:
|
|
AtomicRefCell<Option<Box<(SizeConstraint, InlineContentSizesResult)>>>,
|
|
pub cached_layout_result: AtomicRefCell<Option<Box<CacheableLayoutResultAndInputs>>>,
|
|
pub fragments: AtomicRefCell<Vec<Fragment>>,
|
|
}
|
|
|
|
impl LayoutBoxBase {
|
|
pub(crate) fn new(base_fragment_info: BaseFragmentInfo, style: Arc<ComputedValues>) -> Self {
|
|
Self {
|
|
base_fragment_info,
|
|
style,
|
|
cached_inline_content_size: AtomicRefCell::default(),
|
|
cached_layout_result: AtomicRefCell::default(),
|
|
fragments: AtomicRefCell::default(),
|
|
}
|
|
}
|
|
|
|
/// Get the inline content sizes of a box tree node that extends this [`LayoutBoxBase`], fetch
|
|
/// the result from a cache when possible.
|
|
pub(crate) fn inline_content_sizes(
|
|
&self,
|
|
layout_context: &LayoutContext,
|
|
constraint_space: &ConstraintSpace,
|
|
layout_box: &impl ComputeInlineContentSizes,
|
|
) -> InlineContentSizesResult {
|
|
let mut cache = self.cached_inline_content_size.borrow_mut();
|
|
if let Some(cached_inline_content_size) = cache.as_ref() {
|
|
let (previous_cb_block_size, result) = **cached_inline_content_size;
|
|
if !result.depends_on_block_constraints ||
|
|
previous_cb_block_size == constraint_space.block_size
|
|
{
|
|
return result;
|
|
}
|
|
// TODO: Should we keep multiple caches for various block sizes?
|
|
}
|
|
|
|
let result =
|
|
layout_box.compute_inline_content_sizes_with_fixup(layout_context, constraint_space);
|
|
*cache = Some(Box::new((constraint_space.block_size, result)));
|
|
result
|
|
}
|
|
|
|
pub(crate) fn invalidate_cached_fragment(&self) {
|
|
let _ = self.cached_layout_result.borrow_mut().take();
|
|
}
|
|
|
|
pub(crate) fn invalidate_all_caches(&self) {
|
|
let _ = self.cached_inline_content_size.borrow_mut().take();
|
|
self.invalidate_cached_fragment();
|
|
self.clear_fragments();
|
|
}
|
|
|
|
pub(crate) fn fragments(&self) -> Vec<Fragment> {
|
|
self.fragments.borrow().clone()
|
|
}
|
|
|
|
pub(crate) fn add_fragment(&self, fragment: Fragment) {
|
|
self.fragments.borrow_mut().push(fragment);
|
|
}
|
|
|
|
pub(crate) fn set_fragment(&self, fragment: Fragment) {
|
|
*self.fragments.borrow_mut() = vec![fragment];
|
|
}
|
|
|
|
pub(crate) fn clear_fragments(&self) {
|
|
self.fragments.borrow_mut().clear();
|
|
}
|
|
|
|
pub(crate) fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
|
|
self.style = new_style.clone();
|
|
for fragment in self.fragments.borrow_mut().iter_mut() {
|
|
fragment.repair_style(new_style);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Debug for LayoutBoxBase {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
f.debug_struct("LayoutBoxBase").finish()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, MallocSizeOf)]
|
|
pub(crate) struct CacheableLayoutResult {
|
|
pub fragments: Vec<Fragment>,
|
|
|
|
/// <https://drafts.csswg.org/css2/visudet.html#root-height>
|
|
pub content_block_size: Au,
|
|
|
|
/// If this layout is for a block container, this tracks the collapsable size
|
|
/// of start and end margins and whether or not the block container collapsed through.
|
|
pub collapsible_margins_in_children: CollapsedBlockMargins,
|
|
|
|
/// The contents of a table may force it to become wider than what we would expect
|
|
/// from 'width' and 'min-width'. This is the resulting inline content size,
|
|
/// or None for non-table layouts.
|
|
pub content_inline_size_for_table: Option<Au>,
|
|
|
|
/// The offset of the last inflow baseline of this layout in the content area, if
|
|
/// there was one. This is used to propagate baselines to the ancestors of `display:
|
|
/// inline-block`.
|
|
pub baselines: Baselines,
|
|
|
|
/// Whether or not this layout depends on the containing block size.
|
|
pub depends_on_block_constraints: bool,
|
|
|
|
/// Additional information of this layout that could be used by Javascripts and devtools.
|
|
pub specific_layout_info: Option<SpecificLayoutInfo>,
|
|
}
|
|
|
|
/// A collection of layout inputs and a cached layout result for a [`LayoutBoxBase`].
|
|
#[derive(MallocSizeOf)]
|
|
pub(crate) struct CacheableLayoutResultAndInputs {
|
|
/// The [`CacheableLayoutResult`] for this layout.
|
|
pub result: CacheableLayoutResult,
|
|
|
|
/// The [`ContainingBlockSize`] to use for this box's contents, but not
|
|
/// for the box itself.
|
|
pub containing_block_for_children_size: ContainingBlockSize,
|
|
|
|
/// A [`PositioningContext`] holding absolutely-positioned descendants
|
|
/// collected during the layout of this box.
|
|
pub positioning_context: PositioningContext,
|
|
}
|