aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/fragment_tree/containing_block.rs
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2023-04-28 17:17:43 +0200
committerMartin Robinson <mrobinson@igalia.com>2023-05-09 12:07:20 +0200
commite1675266187fa2eb8686c06724919bb7b4f8db76 (patch)
tree3a03bd46814523916049df2cfd286bc6b1193b48 /components/layout_2020/fragment_tree/containing_block.rs
parent4e37d07ea4f2bba124f78f17873fbb02c66d1cdb (diff)
downloadservo-e1675266187fa2eb8686c06724919bb7b4f8db76.tar.gz
servo-e1675266187fa2eb8686c06724919bb7b4f8db76.zip
Better implement getComputedStyle() for positioned insets
The specification dictates quite quite idiosyncratic return values when querying insets of positioned elements via getComputedStyle(). These depend on whether or not the elements size was overconstrained. This change adds a better implementation of that in preparation for returning proper values for position: sticky.
Diffstat (limited to 'components/layout_2020/fragment_tree/containing_block.rs')
-rw-r--r--components/layout_2020/fragment_tree/containing_block.rs99
1 files changed, 99 insertions, 0 deletions
diff --git a/components/layout_2020/fragment_tree/containing_block.rs b/components/layout_2020/fragment_tree/containing_block.rs
new file mode 100644
index 00000000000..5bd02a67867
--- /dev/null
+++ b/components/layout_2020/fragment_tree/containing_block.rs
@@ -0,0 +1,99 @@
+/* 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 crate::fragments::Fragment;
+use style::computed_values::position::T as ComputedPosition;
+
+/// A data structure used to track the containing block when recursing
+/// through the Fragment tree. It tracks the three types of containing
+/// blocks (for all descendants, for absolute and fixed position
+/// descendants, and for fixed position descendants).
+pub(crate) struct ContainingBlockManager<'a, T> {
+ // The containing block for all non-absolute descendants. "...if the element's
+ // position is 'relative' or 'static', the containing block is formed by the
+ // content edge of the nearest block container ancestor box." This is also
+ // the case for 'position: sticky' elements.
+ // https://www.w3.org/TR/CSS2/visudet.html#containing-block-details
+ pub for_non_absolute_descendants: &'a T,
+
+ // The containing block for absolute descendants. "If the element has
+ // 'position: absolute', the containing block is
+ // established by the nearest ancestor with a 'position' of 'absolute',
+ // 'relative' or 'fixed', in the following way:
+ // 1. In the case that the ancestor is an inline element, the containing
+ // block is the bounding box around the padding boxes of the first and the
+ // last inline boxes generated for that element. In CSS 2.1, if the inline
+ // element is split across multiple lines, the containing block is
+ // undefined.
+ // 2. Otherwise, the containing block is formed by the padding edge of the
+ // ancestor."
+ // https://www.w3.org/TR/CSS2/visudet.html#containing-block-details
+ // If the ancestor forms a containing block for all descendants (see below),
+ // this value will be None and absolute descendants will use the containing
+ // block for fixed descendants.
+ pub for_absolute_descendants: Option<&'a T>,
+
+ // The containing block for fixed and absolute descendants.
+ // "For elements whose layout is governed by the CSS box model, any value
+ // other than none for the transform property also causes the element to
+ // establish a containing block for all descendants. Its padding box will be
+ // used to layout for all of its absolute-position descendants,
+ // fixed-position descendants, and descendant fixed background attachments."
+ // https://w3c.github.io/csswg-drafts/css-transforms-1/#containing-block-for-all-descendants
+ // See `ComputedValues::establishes_containing_block_for_all_descendants`
+ // for a list of conditions where an element forms a containing block for
+ // all descendants.
+ pub for_absolute_and_fixed_descendants: &'a T,
+}
+
+impl<'a, T> ContainingBlockManager<'a, T> {
+ pub(crate) fn get_containing_block_for_fragment(&self, fragment: &Fragment) -> &T {
+ if let Fragment::Box(box_fragment) = fragment {
+ match box_fragment.style.clone_position() {
+ ComputedPosition::Fixed => self.for_absolute_and_fixed_descendants,
+ ComputedPosition::Absolute => self
+ .for_absolute_descendants
+ .unwrap_or(self.for_absolute_and_fixed_descendants),
+ _ => self.for_non_absolute_descendants,
+ }
+ } else {
+ self.for_non_absolute_descendants
+ }
+ }
+
+ pub(crate) fn new_for_non_absolute_descendants(
+ &self,
+ for_non_absolute_descendants: &'a T,
+ ) -> Self {
+ return ContainingBlockManager {
+ for_non_absolute_descendants,
+ for_absolute_descendants: self.for_absolute_descendants,
+ for_absolute_and_fixed_descendants: self.for_absolute_and_fixed_descendants,
+ };
+ }
+
+ pub(crate) fn new_for_absolute_descendants(
+ &self,
+ for_non_absolute_descendants: &'a T,
+ for_absolute_descendants: &'a T,
+ ) -> Self {
+ return ContainingBlockManager {
+ for_non_absolute_descendants,
+ for_absolute_descendants: Some(for_absolute_descendants),
+ for_absolute_and_fixed_descendants: self.for_absolute_and_fixed_descendants,
+ };
+ }
+
+ pub(crate) fn new_for_absolute_and_fixed_descendants(
+ &self,
+ for_non_absolute_descendants: &'a T,
+ for_absolute_and_fixed_descendants: &'a T,
+ ) -> Self {
+ return ContainingBlockManager {
+ for_non_absolute_descendants,
+ for_absolute_descendants: None,
+ for_absolute_and_fixed_descendants,
+ };
+ }
+}