aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/layout_box_base.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/layout_box_base.rs')
-rw-r--r--components/layout/layout_box_base.rs142
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,
+}