mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
layout: Implement overflow scroll support for different axes (#35414)
* layout: Add AxesScrollSensitivity to enable control of scroll in axis Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout_2013: Be compatible with AxesScrollSensitivity Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout: update struct AxesScrollSensitivity to euclid::Vector2D Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * display_list: implement From<Overflow> for ScrollSensitivity Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout: simplify and reuse scroll related logic Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout_2013: simplify and reuse scroll related logic Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout, layout_2013: revert AxesScrollSensitivity to pair struct Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout: Reimport ComputedOverflow as #35103 depends on it Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout: Add AxesOverflow to replace PhysicalVec Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout: implement scroll of viewport for different axes Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * layout: explicitly handle overflow match Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> * Update components/shared/webrender/Cargo.toml Co-authored-by: Martin Robinson <mrobinson@igalia.com> Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> --------- Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
9b3e23633d
commit
03fc54e682
12 changed files with 111 additions and 63 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -8611,6 +8611,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"servo-media",
|
"servo-media",
|
||||||
"servo_geometry",
|
"servo_geometry",
|
||||||
|
"style",
|
||||||
"surfman",
|
"surfman",
|
||||||
"webrender_api",
|
"webrender_api",
|
||||||
]
|
]
|
||||||
|
|
|
@ -51,7 +51,7 @@ use webrender_api::{
|
||||||
FilterOp, GlyphInstance, ImageRendering, LineStyle, NinePatchBorder, NinePatchBorderSource,
|
FilterOp, GlyphInstance, ImageRendering, LineStyle, NinePatchBorder, NinePatchBorderSource,
|
||||||
NormalBorder, PropertyBinding, StickyOffsetBounds,
|
NormalBorder, PropertyBinding, StickyOffsetBounds,
|
||||||
};
|
};
|
||||||
use webrender_traits::display_list::ScrollSensitivity;
|
use webrender_traits::display_list::AxesScrollSensitivity;
|
||||||
|
|
||||||
use super::StackingContextId;
|
use super::StackingContextId;
|
||||||
use crate::block::BlockFlow;
|
use crate::block::BlockFlow;
|
||||||
|
@ -2535,14 +2535,6 @@ impl BlockFlow {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sensitivity = if StyleOverflow::Hidden == self.fragment.style.get_box().overflow_x &&
|
|
||||||
StyleOverflow::Hidden == self.fragment.style.get_box().overflow_y
|
|
||||||
{
|
|
||||||
ScrollSensitivity::Script
|
|
||||||
} else {
|
|
||||||
ScrollSensitivity::ScriptAndInputEvents
|
|
||||||
};
|
|
||||||
|
|
||||||
let border_widths = self
|
let border_widths = self
|
||||||
.fragment
|
.fragment
|
||||||
.style
|
.style
|
||||||
|
@ -2572,7 +2564,13 @@ impl BlockFlow {
|
||||||
parent_index: self.clipping_and_scrolling().scrolling,
|
parent_index: self.clipping_and_scrolling().scrolling,
|
||||||
clip,
|
clip,
|
||||||
content_rect: Rect::new(content_box.origin, content_size).to_layout(),
|
content_rect: Rect::new(content_box.origin, content_size).to_layout(),
|
||||||
node_type: ClipScrollNodeType::ScrollFrame(sensitivity, external_id),
|
node_type: ClipScrollNodeType::ScrollFrame(
|
||||||
|
AxesScrollSensitivity {
|
||||||
|
x: self.fragment.style.get_box().overflow_x.into(),
|
||||||
|
y: self.fragment.style.get_box().overflow_y.into(),
|
||||||
|
},
|
||||||
|
external_id,
|
||||||
|
),
|
||||||
scroll_node_id: None,
|
scroll_node_id: None,
|
||||||
clip_chain_id: None,
|
clip_chain_id: None,
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,7 +32,7 @@ use webrender_api::{
|
||||||
FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, PrimitiveFlags, Shadow,
|
FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, PrimitiveFlags, Shadow,
|
||||||
SpatialId, StickyOffsetBounds, TransformStyle,
|
SpatialId, StickyOffsetBounds, TransformStyle,
|
||||||
};
|
};
|
||||||
use webrender_traits::display_list::{ScrollSensitivity, ScrollTreeNodeId};
|
use webrender_traits::display_list::{AxesScrollSensitivity, ScrollTreeNodeId};
|
||||||
|
|
||||||
use super::StackingContextId;
|
use super::StackingContextId;
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ pub enum ClipType {
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
pub enum ClipScrollNodeType {
|
pub enum ClipScrollNodeType {
|
||||||
Placeholder,
|
Placeholder,
|
||||||
ScrollFrame(ScrollSensitivity, ExternalScrollId),
|
ScrollFrame(AxesScrollSensitivity, ExternalScrollId),
|
||||||
StickyFrame(StickyFrameData),
|
StickyFrame(StickyFrameData),
|
||||||
Clip(ClipType),
|
Clip(ClipType),
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@ use webrender_api::{
|
||||||
ReferenceFrameKind, SpaceAndClipInfo, SpatialId, SpatialTreeItemKey,
|
ReferenceFrameKind, SpaceAndClipInfo, SpatialId, SpatialTreeItemKey,
|
||||||
};
|
};
|
||||||
use webrender_traits::display_list::{
|
use webrender_traits::display_list::{
|
||||||
CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo,
|
AxesScrollSensitivity, CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId,
|
||||||
|
ScrollableNodeInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::display_list::items::{
|
use crate::display_list::items::{
|
||||||
|
@ -167,7 +168,10 @@ impl DisplayList {
|
||||||
content_size,
|
content_size,
|
||||||
webrender_pipeline,
|
webrender_pipeline,
|
||||||
epoch,
|
epoch,
|
||||||
ScrollSensitivity::ScriptAndInputEvents,
|
AxesScrollSensitivity {
|
||||||
|
x: ScrollSensitivity::ScriptAndInputEvents,
|
||||||
|
y: ScrollSensitivity::ScriptAndInputEvents,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ use webrender_api::{
|
||||||
ImageRendering, NinePatchBorder, NinePatchBorderSource,
|
ImageRendering, NinePatchBorder, NinePatchBorderSource,
|
||||||
};
|
};
|
||||||
use webrender_traits::display_list::{
|
use webrender_traits::display_list::{
|
||||||
CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId,
|
AxesScrollSensitivity, CompositorDisplayListInfo, ScrollTreeNodeId,
|
||||||
};
|
};
|
||||||
use wr::units::LayoutVector2D;
|
use wr::units::LayoutVector2D;
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ impl DisplayList {
|
||||||
content_size: units::LayoutSize,
|
content_size: units::LayoutSize,
|
||||||
pipeline_id: wr::PipelineId,
|
pipeline_id: wr::PipelineId,
|
||||||
epoch: wr::Epoch,
|
epoch: wr::Epoch,
|
||||||
root_scroll_sensitivity: ScrollSensitivity,
|
root_scroll_sensitivity: AxesScrollSensitivity,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
wr: wr::DisplayListBuilder::new(pipeline_id),
|
wr: wr::DisplayListBuilder::new(pipeline_id),
|
||||||
|
|
|
@ -26,7 +26,7 @@ use style::values::specified::box_::DisplayOutside;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D};
|
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D};
|
||||||
use webrender_api::{self as wr, BorderRadius};
|
use webrender_api::{self as wr, BorderRadius};
|
||||||
use webrender_traits::display_list::{ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo};
|
use webrender_traits::display_list::{AxesScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo};
|
||||||
use wr::units::{LayoutPixel, LayoutSize};
|
use wr::units::{LayoutPixel, LayoutSize};
|
||||||
use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds};
|
use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds};
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ use crate::fragment_tree::{
|
||||||
BoxFragment, ContainingBlockManager, Fragment, FragmentFlags, FragmentTree,
|
BoxFragment, ContainingBlockManager, Fragment, FragmentFlags, FragmentTree,
|
||||||
PositioningFragment, SpecificLayoutInfo,
|
PositioningFragment, SpecificLayoutInfo,
|
||||||
};
|
};
|
||||||
use crate::geom::{AuOrAuto, PhysicalRect, PhysicalSides, PhysicalVec};
|
use crate::geom::{AuOrAuto, PhysicalRect, PhysicalSides};
|
||||||
use crate::style_ext::ComputedValuesExt;
|
use crate::style_ext::{AxesOverflow, ComputedValuesExt};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct ContainingBlock {
|
pub(crate) struct ContainingBlock {
|
||||||
|
@ -212,7 +212,7 @@ impl DisplayList {
|
||||||
external_id: wr::ExternalScrollId,
|
external_id: wr::ExternalScrollId,
|
||||||
content_rect: LayoutRect,
|
content_rect: LayoutRect,
|
||||||
clip_rect: LayoutRect,
|
clip_rect: LayoutRect,
|
||||||
scroll_sensitivity: ScrollSensitivity,
|
scroll_sensitivity: AxesScrollSensitivity,
|
||||||
) -> ScrollTreeNodeId {
|
) -> ScrollTreeNodeId {
|
||||||
let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
|
let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
|
||||||
|
|
||||||
|
@ -1373,7 +1373,7 @@ impl BoxFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: merge this function with style.effective_overflow()
|
// TODO: merge this function with style.effective_overflow()
|
||||||
fn used_overflow(&self) -> PhysicalVec<ComputedOverflow> {
|
fn used_overflow(&self) -> AxesOverflow {
|
||||||
let mut overflow = self.style.effective_overflow();
|
let mut overflow = self.style.effective_overflow();
|
||||||
let is_replaced_element = self.base.flags.contains(FragmentFlags::IS_REPLACED);
|
let is_replaced_element = self.base.flags.contains(FragmentFlags::IS_REPLACED);
|
||||||
|
|
||||||
|
@ -1483,12 +1483,12 @@ impl BoxFragment {
|
||||||
display_list.wr.pipeline_id,
|
display_list.wr.pipeline_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
let sensitivity =
|
let overflow = self.style.effective_overflow();
|
||||||
if ComputedOverflow::Hidden == overflow.x && ComputedOverflow::Hidden == overflow.y {
|
|
||||||
ScrollSensitivity::Script
|
let sensitivity = AxesScrollSensitivity {
|
||||||
} else {
|
x: overflow.x.into(),
|
||||||
ScrollSensitivity::ScriptAndInputEvents
|
y: overflow.y.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let content_rect = self.scrollable_overflow().to_webrender();
|
let content_rect = self.scrollable_overflow().to_webrender();
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use style::dom::OpaqueNode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::Overflow;
|
use style::values::computed::Overflow;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use webrender_traits::display_list::ScrollSensitivity;
|
use webrender_traits::display_list::AxesScrollSensitivity;
|
||||||
|
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
|
@ -40,8 +40,8 @@ pub struct BoxTree {
|
||||||
/// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds>
|
/// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds>
|
||||||
canvas_background: CanvasBackground,
|
canvas_background: CanvasBackground,
|
||||||
|
|
||||||
/// Whether or not the root element should be sensitive to scrolling input events.
|
/// Whether or not the viewport should be sensitive to scrolling input events in two axes
|
||||||
sensitive_to_scroll_input: bool,
|
scroll_sensitivity: AxesScrollSensitivity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxTree {
|
impl BoxTree {
|
||||||
|
@ -54,7 +54,7 @@ impl BoxTree {
|
||||||
// Zero box for `:root { display: none }`, one for the root element otherwise.
|
// Zero box for `:root { display: none }`, one for the root element otherwise.
|
||||||
assert!(boxes.len() <= 1);
|
assert!(boxes.len() <= 1);
|
||||||
|
|
||||||
// From https://drafts.csswg.org/css-overflow/#propdef-overflow:
|
// From https://drafts.csswg.org/css-overflow/#overflow-propagation:
|
||||||
// > UAs must apply the overflow-* values set on the root element to the viewport when the
|
// > UAs must apply the overflow-* values set on the root element to the viewport when the
|
||||||
// > root element’s display value is not none. However, when the root element is an [HTML]
|
// > root element’s display value is not none. However, when the root element is an [HTML]
|
||||||
// > html element (including XML syntax for HTML) whose overflow value is visible (in both
|
// > html element (including XML syntax for HTML) whose overflow value is visible (in both
|
||||||
|
@ -62,12 +62,13 @@ impl BoxTree {
|
||||||
// > none, user agents must instead apply the overflow-* values of the first such child
|
// > none, user agents must instead apply the overflow-* values of the first such child
|
||||||
// > element to the viewport. The element from which the value is propagated must then have a
|
// > element to the viewport. The element from which the value is propagated must then have a
|
||||||
// > used overflow value of visible.
|
// > used overflow value of visible.
|
||||||
//
|
|
||||||
// TODO: This should handle when different overflow is set multiple axes, which requires the
|
|
||||||
// compositor scroll tree to allow setting a value per axis.
|
|
||||||
let root_style = root_element.style(context);
|
let root_style = root_element.style(context);
|
||||||
let mut root_overflow = root_style.effective_overflow().y;
|
let root_overflow = root_style.effective_overflow();
|
||||||
if root_overflow == Overflow::Visible && !root_style.get_box().display.is_none() {
|
let mut viewport_overflow = root_overflow;
|
||||||
|
if root_overflow.x == Overflow::Visible &&
|
||||||
|
root_overflow.y == Overflow::Visible &&
|
||||||
|
!root_style.get_box().display.is_none()
|
||||||
|
{
|
||||||
for child in iter_child_nodes(root_element) {
|
for child in iter_child_nodes(root_element) {
|
||||||
if !child
|
if !child
|
||||||
.to_threadsafe()
|
.to_threadsafe()
|
||||||
|
@ -79,7 +80,7 @@ impl BoxTree {
|
||||||
|
|
||||||
let style = child.style(context);
|
let style = child.style(context);
|
||||||
if !style.get_box().display.is_none() {
|
if !style.get_box().display.is_none() {
|
||||||
root_overflow = style.effective_overflow().y;
|
viewport_overflow = style.effective_overflow();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +94,10 @@ impl BoxTree {
|
||||||
contains_floats,
|
contains_floats,
|
||||||
},
|
},
|
||||||
canvas_background: CanvasBackground::for_root_element(context, root_element),
|
canvas_background: CanvasBackground::for_root_element(context, root_element),
|
||||||
sensitive_to_scroll_input: root_overflow != Overflow::Hidden,
|
scroll_sensitivity: AxesScrollSensitivity {
|
||||||
|
x: viewport_overflow.x.to_scrollable().into(),
|
||||||
|
y: viewport_overflow.y.to_scrollable().into(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,18 +396,12 @@ impl BoxTree {
|
||||||
acc.union(&child_overflow)
|
acc.union(&child_overflow)
|
||||||
});
|
});
|
||||||
|
|
||||||
let root_scroll_sensitivity = if self.sensitive_to_scroll_input {
|
|
||||||
ScrollSensitivity::ScriptAndInputEvents
|
|
||||||
} else {
|
|
||||||
ScrollSensitivity::Script
|
|
||||||
};
|
|
||||||
|
|
||||||
FragmentTree {
|
FragmentTree {
|
||||||
root_fragments,
|
root_fragments,
|
||||||
scrollable_overflow,
|
scrollable_overflow,
|
||||||
initial_containing_block: physical_containing_block,
|
initial_containing_block: physical_containing_block,
|
||||||
canvas_background: self.canvas_background.clone(),
|
canvas_background: self.canvas_background.clone(),
|
||||||
root_scroll_sensitivity,
|
root_scroll_sensitivity: self.scroll_sensitivity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use fxhash::FxHashSet;
|
||||||
use style::animation::AnimationSetKey;
|
use style::animation::AnimationSetKey;
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
use webrender_api::units;
|
use webrender_api::units;
|
||||||
use webrender_traits::display_list::ScrollSensitivity;
|
use webrender_traits::display_list::AxesScrollSensitivity;
|
||||||
|
|
||||||
use super::{ContainingBlockManager, Fragment, Tag};
|
use super::{ContainingBlockManager, Fragment, Tag};
|
||||||
use crate::display_list::StackingContext;
|
use crate::display_list::StackingContext;
|
||||||
|
@ -38,7 +38,7 @@ pub struct FragmentTree {
|
||||||
pub(crate) canvas_background: CanvasBackground,
|
pub(crate) canvas_background: CanvasBackground,
|
||||||
|
|
||||||
/// Whether or not the root element is sensitive to scroll input events.
|
/// Whether or not the root element is sensitive to scroll input events.
|
||||||
pub root_scroll_sensitivity: ScrollSensitivity,
|
pub root_scroll_sensitivity: AxesScrollSensitivity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FragmentTree {
|
impl FragmentTree {
|
||||||
|
|
|
@ -30,8 +30,8 @@ use webrender_api as wr;
|
||||||
use crate::dom_traversal::Contents;
|
use crate::dom_traversal::Contents;
|
||||||
use crate::fragment_tree::FragmentFlags;
|
use crate::fragment_tree::FragmentFlags;
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize,
|
AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize, Size,
|
||||||
PhysicalVec, Size, Sizes,
|
Sizes,
|
||||||
};
|
};
|
||||||
use crate::table::TableLayoutStyle;
|
use crate::table::TableLayoutStyle;
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||||
|
@ -52,6 +52,11 @@ pub(crate) enum DisplayGeneratingBox {
|
||||||
/// <https://drafts.csswg.org/css-display-3/#layout-specific-display>
|
/// <https://drafts.csswg.org/css-display-3/#layout-specific-display>
|
||||||
LayoutInternal(DisplayLayoutInternal),
|
LayoutInternal(DisplayLayoutInternal),
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct AxesOverflow {
|
||||||
|
pub x: Overflow,
|
||||||
|
pub y: Overflow,
|
||||||
|
}
|
||||||
|
|
||||||
impl DisplayGeneratingBox {
|
impl DisplayGeneratingBox {
|
||||||
pub(crate) fn display_inside(&self) -> DisplayInside {
|
pub(crate) fn display_inside(&self) -> DisplayInside {
|
||||||
|
@ -301,7 +306,7 @@ pub(crate) trait ComputedValuesExt {
|
||||||
) -> LogicalSides<LengthPercentageOrAuto<'_>>;
|
) -> LogicalSides<LengthPercentageOrAuto<'_>>;
|
||||||
fn has_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool;
|
fn has_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool;
|
||||||
fn effective_z_index(&self, fragment_flags: FragmentFlags) -> i32;
|
fn effective_z_index(&self, fragment_flags: FragmentFlags) -> i32;
|
||||||
fn effective_overflow(&self) -> PhysicalVec<Overflow>;
|
fn effective_overflow(&self) -> AxesOverflow;
|
||||||
fn establishes_block_formatting_context(&self) -> bool;
|
fn establishes_block_formatting_context(&self) -> bool;
|
||||||
fn establishes_stacking_context(&self, fragment_flags: FragmentFlags) -> bool;
|
fn establishes_stacking_context(&self, fragment_flags: FragmentFlags) -> bool;
|
||||||
fn establishes_scroll_container(&self) -> bool;
|
fn establishes_scroll_container(&self) -> bool;
|
||||||
|
@ -517,7 +522,7 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
/// Get the effective overflow of this box. The property only applies to block containers,
|
/// Get the effective overflow of this box. The property only applies to block containers,
|
||||||
/// flex containers, and grid containers. And some box types only accept a few values.
|
/// flex containers, and grid containers. And some box types only accept a few values.
|
||||||
/// <https://www.w3.org/TR/css-overflow-3/#overflow-control>
|
/// <https://www.w3.org/TR/css-overflow-3/#overflow-control>
|
||||||
fn effective_overflow(&self) -> PhysicalVec<Overflow> {
|
fn effective_overflow(&self) -> AxesOverflow {
|
||||||
let style_box = self.get_box();
|
let style_box = self.get_box();
|
||||||
let overflow_x = style_box.overflow_x;
|
let overflow_x = style_box.overflow_x;
|
||||||
let overflow_y = style_box.overflow_y;
|
let overflow_y = style_box.overflow_y;
|
||||||
|
@ -547,9 +552,15 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if ignores_overflow {
|
if ignores_overflow {
|
||||||
PhysicalVec::new(Overflow::Visible, Overflow::Visible)
|
AxesOverflow {
|
||||||
|
x: Overflow::Visible,
|
||||||
|
y: Overflow::Visible,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PhysicalVec::new(overflow_x, overflow_y)
|
AxesOverflow {
|
||||||
|
x: overflow_x,
|
||||||
|
y: overflow_y,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,6 +594,8 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
|
|
||||||
/// Whether or not the `overflow` value of this style establishes a scroll container.
|
/// Whether or not the `overflow` value of this style establishes a scroll container.
|
||||||
fn establishes_scroll_container(&self) -> bool {
|
fn establishes_scroll_container(&self) -> bool {
|
||||||
|
// Checking one axis suffices, because the computed value ensures that
|
||||||
|
// either both axes are scrollable, or none is scrollable.
|
||||||
self.effective_overflow().x.is_scrollable()
|
self.effective_overflow().x.is_scrollable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use euclid::Size2D;
|
||||||
use webrender_api::units::LayoutVector2D;
|
use webrender_api::units::LayoutVector2D;
|
||||||
use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation, SpatialId};
|
use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation, SpatialId};
|
||||||
use webrender_traits::display_list::{
|
use webrender_traits::display_list::{
|
||||||
ScrollSensitivity, ScrollTree, ScrollTreeNodeId, ScrollableNodeInfo,
|
AxesScrollSensitivity, ScrollSensitivity, ScrollTree, ScrollTreeNodeId, ScrollableNodeInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId {
|
fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId {
|
||||||
|
@ -27,7 +27,10 @@ fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId {
|
||||||
Some(ScrollableNodeInfo {
|
Some(ScrollableNodeInfo {
|
||||||
external_id: ExternalScrollId(num_nodes as u64, pipeline_id),
|
external_id: ExternalScrollId(num_nodes as u64, pipeline_id),
|
||||||
scrollable_size: Size2D::new(100.0, 100.0),
|
scrollable_size: Size2D::new(100.0, 100.0),
|
||||||
scroll_sensitivity: ScrollSensitivity::ScriptAndInputEvents,
|
scroll_sensitivity: AxesScrollSensitivity {
|
||||||
|
x: ScrollSensitivity::ScriptAndInputEvents,
|
||||||
|
y: ScrollSensitivity::ScriptAndInputEvents,
|
||||||
|
},
|
||||||
offset: LayoutVector2D::zero(),
|
offset: LayoutVector2D::zero(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -158,7 +161,10 @@ fn test_scroll_tree_chain_through_overflow_hidden() {
|
||||||
.scroll_info
|
.scroll_info
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|info| {
|
.map(|info| {
|
||||||
info.scroll_sensitivity = ScrollSensitivity::Script;
|
info.scroll_sensitivity = AxesScrollSensitivity {
|
||||||
|
x: ScrollSensitivity::Script,
|
||||||
|
y: ScrollSensitivity::Script,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
let (scrolled_id, offset) = scroll_tree
|
let (scrolled_id, offset) = scroll_tree
|
||||||
|
|
|
@ -26,4 +26,5 @@ webrender_api = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
servo_geometry = { path = "../../geometry" }
|
servo_geometry = { path = "../../geometry" }
|
||||||
servo-media = { workspace = true }
|
servo-media = { workspace = true }
|
||||||
|
style = { workspace = true }
|
||||||
surfman = { workspace = true, features = ["sm-x11"] }
|
surfman = { workspace = true, features = ["sm-x11"] }
|
||||||
|
|
|
@ -6,17 +6,38 @@
|
||||||
|
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::Cursor;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use style::values::specified::Overflow;
|
||||||
use webrender_api::units::{LayoutSize, LayoutVector2D};
|
use webrender_api::units::{LayoutSize, LayoutVector2D};
|
||||||
use webrender_api::{Epoch, ExternalScrollId, PipelineId, ScrollLocation, SpatialId};
|
use webrender_api::{Epoch, ExternalScrollId, PipelineId, ScrollLocation, SpatialId};
|
||||||
|
|
||||||
/// The scroll sensitivity of a scroll node ie whether it can be scrolled due to input event and
|
/// The scroll sensitivity of a scroll node in a particular axis ie whether it can be scrolled due to
|
||||||
/// script events or only script events.
|
/// input events and script events or only script events.
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub enum ScrollSensitivity {
|
pub enum ScrollSensitivity {
|
||||||
/// This node can be scrolled by input and script events.
|
/// This node can be scrolled by input and script events.
|
||||||
ScriptAndInputEvents,
|
ScriptAndInputEvents,
|
||||||
/// This node can only be scrolled by script events.
|
/// This node can only be scrolled by script events.
|
||||||
Script,
|
Script,
|
||||||
|
/// This node cannot be scrolled.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert [Overflow] to [ScrollSensitivity].
|
||||||
|
impl From<Overflow> for ScrollSensitivity {
|
||||||
|
fn from(overflow: Overflow) -> Self {
|
||||||
|
match overflow {
|
||||||
|
Overflow::Hidden => ScrollSensitivity::Script,
|
||||||
|
Overflow::Scroll | Overflow::Auto => ScrollSensitivity::ScriptAndInputEvents,
|
||||||
|
Overflow::Visible | Overflow::Clip => ScrollSensitivity::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [ScrollSensitivity] of particular node in the vertical and horizontal axes.
|
||||||
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
pub struct AxesScrollSensitivity {
|
||||||
|
pub x: ScrollSensitivity,
|
||||||
|
pub y: ScrollSensitivity,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information that Servo keeps alongside WebRender display items
|
/// Information that Servo keeps alongside WebRender display items
|
||||||
|
@ -57,7 +78,7 @@ pub struct ScrollableNodeInfo {
|
||||||
pub scrollable_size: LayoutSize,
|
pub scrollable_size: LayoutSize,
|
||||||
|
|
||||||
/// Whether this `ScrollableNode` is sensitive to input events.
|
/// Whether this `ScrollableNode` is sensitive to input events.
|
||||||
pub scroll_sensitivity: ScrollSensitivity,
|
pub scroll_sensitivity: AxesScrollSensitivity,
|
||||||
|
|
||||||
/// The current offset of this scroll node.
|
/// The current offset of this scroll node.
|
||||||
pub offset: LayoutVector2D,
|
pub offset: LayoutVector2D,
|
||||||
|
@ -119,7 +140,9 @@ impl ScrollTreeNode {
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if info.scroll_sensitivity != ScrollSensitivity::ScriptAndInputEvents {
|
if info.scroll_sensitivity.x != ScrollSensitivity::ScriptAndInputEvents &&
|
||||||
|
info.scroll_sensitivity.y != ScrollSensitivity::ScriptAndInputEvents
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,11 +173,15 @@ impl ScrollTreeNode {
|
||||||
let scrollable_height = info.scrollable_size.height;
|
let scrollable_height = info.scrollable_size.height;
|
||||||
let original_layer_scroll_offset = info.offset;
|
let original_layer_scroll_offset = info.offset;
|
||||||
|
|
||||||
if scrollable_width > 0. {
|
if scrollable_width > 0. &&
|
||||||
|
info.scroll_sensitivity.x == ScrollSensitivity::ScriptAndInputEvents
|
||||||
|
{
|
||||||
info.offset.x = (info.offset.x + delta.x).min(0.0).max(-scrollable_width);
|
info.offset.x = (info.offset.x + delta.x).min(0.0).max(-scrollable_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
if scrollable_height > 0. {
|
if scrollable_height > 0. &&
|
||||||
|
info.scroll_sensitivity.y == ScrollSensitivity::ScriptAndInputEvents
|
||||||
|
{
|
||||||
info.offset.y = (info.offset.y + delta.y).min(0.0).max(-scrollable_height);
|
info.offset.y = (info.offset.y + delta.y).min(0.0).max(-scrollable_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +315,7 @@ impl CompositorDisplayListInfo {
|
||||||
content_size: LayoutSize,
|
content_size: LayoutSize,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
root_scroll_sensitivity: ScrollSensitivity,
|
root_scroll_sensitivity: AxesScrollSensitivity,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut scroll_tree = ScrollTree::default();
|
let mut scroll_tree = ScrollTree::default();
|
||||||
let root_reference_frame_id = scroll_tree.add_scroll_tree_node(
|
let root_reference_frame_id = scroll_tree.add_scroll_tree_node(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue