diff options
Diffstat (limited to 'components/layout/layout_box_base.rs')
-rw-r--r-- | components/layout/layout_box_base.rs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/components/layout/layout_box_base.rs b/components/layout/layout_box_base.rs new file mode 100644 index 00000000000..71fbfdeced1 --- /dev/null +++ b/components/layout/layout_box_base.rs @@ -0,0 +1,142 @@ +/* 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, + #[conditional_malloc_size_of] + 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 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(); + } +} + +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, +} |