aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/fragment_tree/box_fragment.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/fragment_tree/box_fragment.rs')
-rw-r--r--components/layout/fragment_tree/box_fragment.rs106
1 files changed, 87 insertions, 19 deletions
diff --git a/components/layout/fragment_tree/box_fragment.rs b/components/layout/fragment_tree/box_fragment.rs
index e87826ec3ca..65ad1c4aa93 100644
--- a/components/layout/fragment_tree/box_fragment.rs
+++ b/components/layout/fragment_tree/box_fragment.rs
@@ -2,11 +2,12 @@
* 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 app_units::Au;
+use app_units::{Au, MAX_AU, MIN_AU};
use atomic_refcell::AtomicRefCell;
use base::print_tree::PrintTree;
use malloc_size_of_derive::MallocSizeOf;
use servo_arc::Arc as ServoArc;
+use servo_geometry::f32_rect_to_au_rect;
use style::Zero;
use style::computed_values::border_collapse::T as BorderCollapse;
use style::computed_values::overflow_x::T as ComputedOverflow;
@@ -16,6 +17,7 @@ use style::properties::ComputedValues;
use style::values::specified::box_::DisplayOutside;
use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment};
+use crate::display_list::ToWebRender;
use crate::formatting_contexts::Baselines;
use crate::geom::{
AuOrAuto, LengthPercentageOrAuto, PhysicalPoint, PhysicalRect, PhysicalSides, ToLogical,
@@ -116,7 +118,7 @@ impl BoxFragment {
) -> BoxFragment {
let scrollable_overflow_from_children =
children.iter().fold(PhysicalRect::zero(), |acc, child| {
- acc.union(&child.scrollable_overflow())
+ acc.union(&child.scrollable_overflow_for_parent())
});
BoxFragment {
@@ -267,30 +269,96 @@ impl BoxFragment {
pub fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> {
let mut overflow = self.border_rect();
- if self.style.establishes_scroll_container(self.base.flags) {
- return overflow;
+ if !self.style.establishes_scroll_container(self.base.flags) {
+ // https://www.w3.org/TR/css-overflow-3/#scrollable
+ // Only include the scrollable overflow of a child box if it has overflow: visible.
+ let scrollable_overflow = self.scrollable_overflow();
+ let bottom_right = PhysicalPoint::new(
+ overflow.max_x().max(scrollable_overflow.max_x()),
+ overflow.max_y().max(scrollable_overflow.max_y()),
+ );
+
+ let overflow_style = self.style.effective_overflow(self.base.flags);
+ if overflow_style.y == ComputedOverflow::Visible {
+ overflow.origin.y = overflow.origin.y.min(scrollable_overflow.origin.y);
+ overflow.size.height = bottom_right.y - overflow.origin.y;
+ }
+
+ if overflow_style.x == ComputedOverflow::Visible {
+ overflow.origin.x = overflow.origin.x.min(scrollable_overflow.origin.x);
+ overflow.size.width = bottom_right.x - overflow.origin.x;
+ }
}
- // https://www.w3.org/TR/css-overflow-3/#scrollable
- // Only include the scrollable overflow of a child box if it has overflow: visible.
- let scrollable_overflow = self.scrollable_overflow();
- let bottom_right = PhysicalPoint::new(
- overflow.max_x().max(scrollable_overflow.max_x()),
- overflow.max_y().max(scrollable_overflow.max_y()),
- );
+ // <https://drafts.csswg.org/css-overflow-3/#scrollable-overflow-region>
+ // > ...accounting for transforms by projecting each box onto the plane of
+ // > the element that establishes its 3D rendering context. [CSS3-TRANSFORMS]
+ // Both boxes and its scrollable overflow (if it is included) should be transformed accordingly.
+ //
+ // TODO(stevennovaryo): We are supposed to handle perspective transform and 3d context, but it is yet to happen.
+ if self
+ .style
+ .has_effective_transform_or_perspective(self.base.flags)
+ {
+ if let Some(transform) =
+ self.calculate_transform_matrix(&self.border_rect().to_untyped())
+ {
+ if let Some(transformed_overflow_box) =
+ transform.outer_transformed_rect(&overflow.to_webrender().to_rect())
+ {
+ overflow =
+ f32_rect_to_au_rect(transformed_overflow_box.to_untyped()).cast_unit();
+ }
+ }
+ }
+
+ overflow
+ }
- let overflow_style = self.style.effective_overflow(self.base.flags);
- if overflow_style.y == ComputedOverflow::Visible {
- overflow.origin.y = overflow.origin.y.min(scrollable_overflow.origin.y);
- overflow.size.height = bottom_right.y - overflow.origin.y;
+ /// <https://drafts.csswg.org/css-overflow/#unreachable-scrollable-overflow-region>
+ /// > area beyond the scroll origin in either axis is considered the unreachable scrollable overflow region
+ ///
+ /// Return the clipped the scrollable overflow based on its scroll origin, determined by overflow direction.
+ /// For an element, the clip rect is the padding rect and for viewport, it is the initial containing block.
+ pub fn clip_unreachable_scrollable_overflow_region(
+ &self,
+ scrollable_overflow: PhysicalRect<Au>,
+ clipping_rect: PhysicalRect<Au>,
+ ) -> PhysicalRect<Au> {
+ let scrolling_direction = self.style.overflow_direction();
+ let mut scrollable_overflow_box = scrollable_overflow.to_box2d();
+ let mut clipping_box = clipping_rect.to_box2d();
+
+ if scrolling_direction.rightward {
+ clipping_box.max.x = MAX_AU;
+ } else {
+ clipping_box.min.x = MIN_AU;
}
- if overflow_style.x == ComputedOverflow::Visible {
- overflow.origin.x = overflow.origin.x.min(scrollable_overflow.origin.x);
- overflow.size.width = bottom_right.x - overflow.origin.x;
+ if scrolling_direction.downward {
+ clipping_box.max.y = MAX_AU;
+ } else {
+ clipping_box.min.y = MIN_AU;
}
- overflow
+ scrollable_overflow_box = scrollable_overflow_box.intersection_unchecked(&clipping_box);
+
+ match scrollable_overflow_box.is_negative() {
+ true => PhysicalRect::zero(),
+ false => scrollable_overflow_box.to_rect(),
+ }
+ }
+
+ /// <https://drafts.csswg.org/css-overflow/#unreachable-scrollable-overflow-region>
+ /// > area beyond the scroll origin in either axis is considered the unreachable scrollable overflow region
+ ///
+ /// Return the clipped the scrollable overflow based on its scroll origin, determined by overflow direction.
+ /// This will coincides with the scrollport if the fragment is a scroll container.
+ pub fn reachable_scrollable_overflow_region(&self) -> PhysicalRect<Au> {
+ self.clip_unreachable_scrollable_overflow_region(
+ self.scrollable_overflow(),
+ self.padding_rect(),
+ )
}
pub(crate) fn calculate_resolved_insets_if_positioned(&self) -> PhysicalSides<AuOrAuto> {