mirror of
https://github.com/servo/servo.git
synced 2025-08-12 17:05:33 +01:00
script/compositor: Handle cursor updates from script (#38518)
Instead of using WebRender hit testing to update the cursor, base it on layout hit tests. This allows removing the majority of WebRender hit test items and finally opens up the possibility of adding support for custom cursors. In addition, this change fixes an issue where cursors were not set properly on areas of the viewport that extended past the page content. Testing: This is difficult to test as verifying that the cursor changed properly is beyond the capabilities of Servo's test harnesses. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
87538282db
commit
6651f37c05
21 changed files with 279 additions and 259 deletions
|
@ -6,6 +6,7 @@ use std::collections::HashMap;
|
|||
|
||||
use app_units::Au;
|
||||
use base::id::ScrollTreeNodeId;
|
||||
use embedder_traits::Cursor;
|
||||
use euclid::{Box2D, Point2D, Point3D, Vector2D};
|
||||
use kurbo::{Ellipse, Shape};
|
||||
use layout_api::{ElementsFromPointFlags, ElementsFromPointResult};
|
||||
|
@ -13,6 +14,7 @@ use style::computed_values::backface_visibility::T as BackfaceVisibility;
|
|||
use style::computed_values::pointer_events::T as PointerEvents;
|
||||
use style::computed_values::visibility::T as Visibility;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::ui::CursorKind;
|
||||
use webrender_api::BorderRadius;
|
||||
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, RectExt};
|
||||
|
||||
|
@ -21,7 +23,7 @@ use crate::display_list::stacking_context::StackingContextSection;
|
|||
use crate::display_list::{
|
||||
StackingContext, StackingContextContent, StackingContextTree, ToWebRender,
|
||||
};
|
||||
use crate::fragment_tree::Fragment;
|
||||
use crate::fragment_tree::{Fragment, FragmentFlags};
|
||||
use crate::geom::PhysicalRect;
|
||||
|
||||
pub(crate) struct HitTest<'a> {
|
||||
|
@ -249,12 +251,18 @@ impl Fragment {
|
|||
let mut hit_test_fragment_inner =
|
||||
|style: &ComputedValues,
|
||||
fragment_rect: PhysicalRect<Au>,
|
||||
border_radius: BorderRadius| {
|
||||
if style.get_inherited_ui().pointer_events == PointerEvents::None {
|
||||
return false;
|
||||
}
|
||||
if style.get_inherited_box().visibility != Visibility::Visible {
|
||||
return false;
|
||||
border_radius: BorderRadius,
|
||||
fragment_flags: FragmentFlags,
|
||||
auto_cursor: Cursor| {
|
||||
let is_root_element = fragment_flags.contains(FragmentFlags::IS_ROOT_ELEMENT);
|
||||
|
||||
if !is_root_element {
|
||||
if style.get_inherited_ui().pointer_events == PointerEvents::None {
|
||||
return false;
|
||||
}
|
||||
if style.get_inherited_box().visibility != Visibility::Visible {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let (point_in_spatial_node, transform) =
|
||||
|
@ -263,14 +271,28 @@ impl Fragment {
|
|||
None => return false,
|
||||
};
|
||||
|
||||
if style.get_box().backface_visibility == BackfaceVisibility::Hidden &&
|
||||
if !is_root_element &&
|
||||
style.get_box().backface_visibility == BackfaceVisibility::Hidden &&
|
||||
transform.is_backface_visible()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let fragment_rect = fragment_rect.translate(containing_block.origin.to_vector());
|
||||
if !rounded_rect_contains_point(
|
||||
if is_root_element {
|
||||
let viewport_size = hit_test
|
||||
.stacking_context_tree
|
||||
.compositor_info
|
||||
.viewport_details
|
||||
.size;
|
||||
let viewport_rect = LayoutRect::from_origin_and_size(
|
||||
Default::default(),
|
||||
viewport_size.cast_unit(),
|
||||
);
|
||||
if !viewport_rect.contains(hit_test.point_to_test) {
|
||||
return false;
|
||||
}
|
||||
} else if !rounded_rect_contains_point(
|
||||
fragment_rect.to_webrender(),
|
||||
&border_radius,
|
||||
point_in_spatial_node,
|
||||
|
@ -283,11 +305,12 @@ impl Fragment {
|
|||
fragment_rect.origin.x.to_f32_px(),
|
||||
fragment_rect.origin.y.to_f32_px(),
|
||||
);
|
||||
|
||||
hit_test.results.push(ElementsFromPointResult {
|
||||
node: tag.node,
|
||||
point_in_target,
|
||||
cursor: cursor(style.get_inherited_ui().cursor.keyword, auto_cursor),
|
||||
});
|
||||
|
||||
!hit_test.flags.contains(ElementsFromPointFlags::FindAll)
|
||||
};
|
||||
|
||||
|
@ -298,6 +321,8 @@ impl Fragment {
|
|||
&box_fragment.style,
|
||||
box_fragment.border_rect(),
|
||||
box_fragment.border_radius(),
|
||||
box_fragment.base.flags,
|
||||
Cursor::Default,
|
||||
)
|
||||
},
|
||||
Fragment::Text(text) => {
|
||||
|
@ -306,6 +331,8 @@ impl Fragment {
|
|||
&text.inline_styles.style.borrow(),
|
||||
text.rect,
|
||||
BorderRadius::zero(),
|
||||
FragmentFlags::empty(),
|
||||
Cursor::Text,
|
||||
)
|
||||
},
|
||||
_ => false,
|
||||
|
@ -358,3 +385,44 @@ fn rounded_rect_contains_point(
|
|||
check_corner(rect.bottom_right(), &border_radius.bottom_right, true, true) &&
|
||||
check_corner(rect.bottom_left(), &border_radius.bottom_left, false, true)
|
||||
}
|
||||
|
||||
fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor {
|
||||
match kind {
|
||||
CursorKind::Auto => auto_cursor,
|
||||
CursorKind::None => Cursor::None,
|
||||
CursorKind::Default => Cursor::Default,
|
||||
CursorKind::Pointer => Cursor::Pointer,
|
||||
CursorKind::ContextMenu => Cursor::ContextMenu,
|
||||
CursorKind::Help => Cursor::Help,
|
||||
CursorKind::Progress => Cursor::Progress,
|
||||
CursorKind::Wait => Cursor::Wait,
|
||||
CursorKind::Cell => Cursor::Cell,
|
||||
CursorKind::Crosshair => Cursor::Crosshair,
|
||||
CursorKind::Text => Cursor::Text,
|
||||
CursorKind::VerticalText => Cursor::VerticalText,
|
||||
CursorKind::Alias => Cursor::Alias,
|
||||
CursorKind::Copy => Cursor::Copy,
|
||||
CursorKind::Move => Cursor::Move,
|
||||
CursorKind::NoDrop => Cursor::NoDrop,
|
||||
CursorKind::NotAllowed => Cursor::NotAllowed,
|
||||
CursorKind::Grab => Cursor::Grab,
|
||||
CursorKind::Grabbing => Cursor::Grabbing,
|
||||
CursorKind::EResize => Cursor::EResize,
|
||||
CursorKind::NResize => Cursor::NResize,
|
||||
CursorKind::NeResize => Cursor::NeResize,
|
||||
CursorKind::NwResize => Cursor::NwResize,
|
||||
CursorKind::SResize => Cursor::SResize,
|
||||
CursorKind::SeResize => Cursor::SeResize,
|
||||
CursorKind::SwResize => Cursor::SwResize,
|
||||
CursorKind::WResize => Cursor::WResize,
|
||||
CursorKind::EwResize => Cursor::EwResize,
|
||||
CursorKind::NsResize => Cursor::NsResize,
|
||||
CursorKind::NeswResize => Cursor::NeswResize,
|
||||
CursorKind::NwseResize => Cursor::NwseResize,
|
||||
CursorKind::ColResize => Cursor::ColResize,
|
||||
CursorKind::RowResize => Cursor::RowResize,
|
||||
CursorKind::AllScroll => Cursor::AllScroll,
|
||||
CursorKind::ZoomIn => Cursor::ZoomIn,
|
||||
CursorKind::ZoomOut => Cursor::ZoomOut,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ use app_units::{AU_PER_PX, Au};
|
|||
use base::id::ScrollTreeNodeId;
|
||||
use clip::{Clip, ClipId};
|
||||
use compositing_traits::display_list::{CompositorDisplayListInfo, SpatialTreeNodeInfo};
|
||||
use embedder_traits::Cursor;
|
||||
use euclid::{Point2D, Scale, SideOffsets2D, Size2D, UnknownUnit, Vector2D};
|
||||
use fonts::GlyphStore;
|
||||
use gradient::WebRenderGradient;
|
||||
|
@ -36,13 +35,12 @@ use style::values::computed::{
|
|||
use style::values::generics::NonNegative;
|
||||
use style::values::generics::rect::Rect;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
use style::values::specified::ui::CursorKind;
|
||||
use style_traits::{CSSPixel as StyloCSSPixel, DevicePixel as StyloDevicePixel};
|
||||
use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel, LayoutRect, LayoutSize};
|
||||
use webrender_api::{
|
||||
self as wr, BorderDetails, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipChainId,
|
||||
ClipMode, CommonItemProperties, ComplexClipRegion, NinePatchBorder, NinePatchBorderSource,
|
||||
PropertyBinding, SpatialId, SpatialTreeItemKey, units,
|
||||
PrimitiveFlags, PropertyBinding, SpatialId, SpatialTreeItemKey, units,
|
||||
};
|
||||
use wr::units::LayoutVector2D;
|
||||
|
||||
|
@ -164,8 +162,9 @@ impl DisplayListBuilder<'_> {
|
|||
) -> BuiltDisplayList {
|
||||
// Build the rest of the display list which inclues all of the WebRender primitives.
|
||||
let compositor_info = &mut stacking_context_tree.compositor_info;
|
||||
let pipeline_id = compositor_info.pipeline_id;
|
||||
let mut webrender_display_list_builder =
|
||||
webrender_api::DisplayListBuilder::new(compositor_info.pipeline_id);
|
||||
webrender_api::DisplayListBuilder::new(pipeline_id);
|
||||
webrender_display_list_builder.begin();
|
||||
|
||||
// `dump_serialized_display_list` doesn't actually print anything. It sets up
|
||||
|
@ -200,6 +199,8 @@ impl DisplayListBuilder<'_> {
|
|||
builder.add_clip_to_display_list(clip);
|
||||
}
|
||||
|
||||
builder.push_hit_tests_for_scrollable_areas(&stacking_context_tree.hit_test_items);
|
||||
|
||||
// Paint the canvas’ background (if any) before/under everything else
|
||||
stacking_context_tree
|
||||
.root_stacking_context
|
||||
|
@ -309,6 +310,39 @@ impl DisplayListBuilder<'_> {
|
|||
self.compositor_info.scroll_tree = scroll_tree;
|
||||
}
|
||||
|
||||
fn push_hit_tests_for_scrollable_areas(
|
||||
&mut self,
|
||||
scroll_frame_hit_test_items: &[ScrollFrameHitTestItem],
|
||||
) {
|
||||
// Add a single hit test that covers the entire viewport, so that WebRender knows
|
||||
// which pipeline it hits when doing hit testing.
|
||||
let pipeline_id = self.compositor_info.pipeline_id;
|
||||
let viewport_size = self.compositor_info.viewport_details.size;
|
||||
let viewport_rect = LayoutRect::from_size(viewport_size.cast_unit());
|
||||
self.wr().push_hit_test(
|
||||
viewport_rect,
|
||||
ClipChainId::INVALID,
|
||||
SpatialId::root_reference_frame(pipeline_id),
|
||||
PrimitiveFlags::default(),
|
||||
(0, 0), /* tag */
|
||||
);
|
||||
|
||||
for item in scroll_frame_hit_test_items {
|
||||
let spatial_id = self
|
||||
.compositor_info
|
||||
.scroll_tree
|
||||
.webrender_id(&item.scroll_node_id);
|
||||
let clip_chain_id = self.clip_chain_id(item.clip_id);
|
||||
self.wr().push_hit_test(
|
||||
item.rect,
|
||||
clip_chain_id,
|
||||
spatial_id,
|
||||
PrimitiveFlags::default(),
|
||||
(item.external_scroll_id.0, 0), /* tag */
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the given [`Clip`] to the WebRender display list and create a mapping from
|
||||
/// its [`ClipId`] to a WebRender [`ClipChainId`]. This happens:
|
||||
/// - When WebRender display list construction starts: All clips created during the
|
||||
|
@ -548,7 +582,6 @@ impl Fragment {
|
|||
builder: &mut DisplayListBuilder,
|
||||
containing_block: &PhysicalRect<Au>,
|
||||
section: StackingContextSection,
|
||||
is_hit_test_for_scrollable_overflow: bool,
|
||||
is_collapsed_table_borders: bool,
|
||||
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||
) {
|
||||
|
@ -572,7 +605,6 @@ impl Fragment {
|
|||
Visibility::Visible => BuilderForBoxFragment::new(
|
||||
box_fragment,
|
||||
containing_block,
|
||||
is_hit_test_for_scrollable_overflow,
|
||||
is_collapsed_table_borders,
|
||||
)
|
||||
.build(builder, section),
|
||||
|
@ -580,19 +612,7 @@ impl Fragment {
|
|||
Visibility::Collapse => (),
|
||||
}
|
||||
},
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => {},
|
||||
Fragment::Positioning(positioning_fragment) => {
|
||||
let positioning_fragment = positioning_fragment.borrow();
|
||||
let rect = positioning_fragment
|
||||
.rect
|
||||
.translate(containing_block.origin.to_vector());
|
||||
self.maybe_push_hit_test_for_style_and_tag(
|
||||
builder,
|
||||
&positioning_fragment.style,
|
||||
rect,
|
||||
Cursor::Default,
|
||||
);
|
||||
},
|
||||
Fragment::AbsoluteOrFixedPositioned(_) | Fragment::Positioning(_) => {},
|
||||
Fragment::Image(image) => {
|
||||
let image = image.borrow();
|
||||
match image.style.get_inherited_box().visibility {
|
||||
|
@ -674,27 +694,6 @@ impl Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
fn maybe_push_hit_test_for_style_and_tag(
|
||||
&self,
|
||||
builder: &mut DisplayListBuilder,
|
||||
style: &ComputedValues,
|
||||
rect: PhysicalRect<Au>,
|
||||
cursor: Cursor,
|
||||
) {
|
||||
let clip_chain_id = builder.clip_chain_id(builder.current_clip_id);
|
||||
let spatial_id = builder.spatial_id(builder.current_scroll_node_id);
|
||||
let external_scroll_id = builder
|
||||
.compositor_info
|
||||
.external_scroll_id_for_scroll_tree_node(builder.current_scroll_node_id);
|
||||
builder.wr().push_hit_test(
|
||||
rect.to_webrender(),
|
||||
clip_chain_id,
|
||||
spatial_id,
|
||||
style.get_webrender_primitive_flags(),
|
||||
(external_scroll_id.0, cursor as u16), /* tag */
|
||||
);
|
||||
}
|
||||
|
||||
fn build_display_list_for_text_fragment(
|
||||
&self,
|
||||
fragment: &TextFragment,
|
||||
|
@ -724,8 +723,6 @@ impl Fragment {
|
|||
}
|
||||
|
||||
let parent_style = fragment.inline_styles.style.borrow();
|
||||
self.maybe_push_hit_test_for_style_and_tag(builder, &parent_style, rect, Cursor::Text);
|
||||
|
||||
let color = parent_style.clone_color();
|
||||
let font_metrics = &fragment.font_metrics;
|
||||
let dppx = builder.device_pixel_ratio.get();
|
||||
|
@ -939,7 +936,6 @@ struct BuilderForBoxFragment<'a> {
|
|||
border_edge_clip_chain_id: RefCell<Option<ClipChainId>>,
|
||||
padding_edge_clip_chain_id: RefCell<Option<ClipChainId>>,
|
||||
content_edge_clip_chain_id: RefCell<Option<ClipChainId>>,
|
||||
is_hit_test_for_scrollable_overflow: bool,
|
||||
is_collapsed_table_borders: bool,
|
||||
}
|
||||
|
||||
|
@ -947,7 +943,6 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
fn new(
|
||||
fragment: &'a BoxFragment,
|
||||
containing_block: &'a PhysicalRect<Au>,
|
||||
is_hit_test_for_scrollable_overflow: bool,
|
||||
is_collapsed_table_borders: bool,
|
||||
) -> Self {
|
||||
let border_rect = fragment
|
||||
|
@ -964,7 +959,6 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
border_edge_clip_chain_id: RefCell::new(None),
|
||||
padding_edge_clip_chain_id: RefCell::new(None),
|
||||
content_edge_clip_chain_id: RefCell::new(None),
|
||||
is_hit_test_for_scrollable_overflow,
|
||||
is_collapsed_table_borders,
|
||||
}
|
||||
}
|
||||
|
@ -1047,11 +1041,6 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
}
|
||||
|
||||
fn build(&mut self, builder: &mut DisplayListBuilder, section: StackingContextSection) {
|
||||
if self.is_hit_test_for_scrollable_overflow {
|
||||
self.build_hit_test(builder, self.fragment.scrollable_overflow().to_webrender());
|
||||
return;
|
||||
}
|
||||
|
||||
if self.is_collapsed_table_borders {
|
||||
self.build_collapsed_table_borders(builder);
|
||||
return;
|
||||
|
@ -1062,7 +1051,6 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.build_hit_test(builder, self.border_rect);
|
||||
if self
|
||||
.fragment
|
||||
.base
|
||||
|
@ -1077,28 +1065,6 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
self.build_border(builder);
|
||||
}
|
||||
|
||||
fn build_hit_test(&self, builder: &mut DisplayListBuilder, rect: LayoutRect) {
|
||||
let cursor = cursor(
|
||||
self.fragment.style.get_inherited_ui().cursor.keyword,
|
||||
Cursor::Default,
|
||||
);
|
||||
let external_scroll_node_id = builder
|
||||
.compositor_info
|
||||
.external_scroll_id_for_scroll_tree_node(builder.current_scroll_node_id);
|
||||
|
||||
let mut common = builder.common_properties(rect, &self.fragment.style);
|
||||
if let Some(clip_chain_id) = self.border_edge_clip(builder, false) {
|
||||
common.clip_chain_id = clip_chain_id;
|
||||
}
|
||||
builder.wr().push_hit_test(
|
||||
common.clip_rect,
|
||||
common.clip_chain_id,
|
||||
common.spatial_id,
|
||||
common.flags,
|
||||
(external_scroll_node_id.0, cursor as u16), /* tag */
|
||||
);
|
||||
}
|
||||
|
||||
fn build_background_for_painter(
|
||||
&mut self,
|
||||
builder: &mut DisplayListBuilder,
|
||||
|
@ -1623,47 +1589,6 @@ fn glyphs_advance_by_index(
|
|||
point
|
||||
}
|
||||
|
||||
fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor {
|
||||
match kind {
|
||||
CursorKind::Auto => auto_cursor,
|
||||
CursorKind::None => Cursor::None,
|
||||
CursorKind::Default => Cursor::Default,
|
||||
CursorKind::Pointer => Cursor::Pointer,
|
||||
CursorKind::ContextMenu => Cursor::ContextMenu,
|
||||
CursorKind::Help => Cursor::Help,
|
||||
CursorKind::Progress => Cursor::Progress,
|
||||
CursorKind::Wait => Cursor::Wait,
|
||||
CursorKind::Cell => Cursor::Cell,
|
||||
CursorKind::Crosshair => Cursor::Crosshair,
|
||||
CursorKind::Text => Cursor::Text,
|
||||
CursorKind::VerticalText => Cursor::VerticalText,
|
||||
CursorKind::Alias => Cursor::Alias,
|
||||
CursorKind::Copy => Cursor::Copy,
|
||||
CursorKind::Move => Cursor::Move,
|
||||
CursorKind::NoDrop => Cursor::NoDrop,
|
||||
CursorKind::NotAllowed => Cursor::NotAllowed,
|
||||
CursorKind::Grab => Cursor::Grab,
|
||||
CursorKind::Grabbing => Cursor::Grabbing,
|
||||
CursorKind::EResize => Cursor::EResize,
|
||||
CursorKind::NResize => Cursor::NResize,
|
||||
CursorKind::NeResize => Cursor::NeResize,
|
||||
CursorKind::NwResize => Cursor::NwResize,
|
||||
CursorKind::SResize => Cursor::SResize,
|
||||
CursorKind::SeResize => Cursor::SeResize,
|
||||
CursorKind::SwResize => Cursor::SwResize,
|
||||
CursorKind::WResize => Cursor::WResize,
|
||||
CursorKind::EwResize => Cursor::EwResize,
|
||||
CursorKind::NsResize => Cursor::NsResize,
|
||||
CursorKind::NeswResize => Cursor::NeswResize,
|
||||
CursorKind::NwseResize => Cursor::NwseResize,
|
||||
CursorKind::ColResize => Cursor::ColResize,
|
||||
CursorKind::RowResize => Cursor::RowResize,
|
||||
CursorKind::AllScroll => Cursor::AllScroll,
|
||||
CursorKind::ZoomIn => Cursor::ZoomIn,
|
||||
CursorKind::ZoomOut => Cursor::ZoomOut,
|
||||
}
|
||||
}
|
||||
|
||||
/// Radii for the padding edge or content edge
|
||||
fn inner_radii(mut radii: wr::BorderRadius, insets: units::LayoutSideOffsets) -> wr::BorderRadius {
|
||||
assert!(insets.left >= 0.0, "left inset must not be negative");
|
||||
|
|
|
@ -33,7 +33,7 @@ use style::values::generics::box_::Perspective;
|
|||
use style::values::generics::transform::{self, GenericRotate, GenericScale, GenericTranslate};
|
||||
use style::values::specified::box_::DisplayOutside;
|
||||
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D};
|
||||
use webrender_api::{self as wr, BorderRadius};
|
||||
use webrender_api::{self as wr, BorderRadius, ExternalScrollId};
|
||||
use wr::StickyOffsetBounds;
|
||||
use wr::units::{LayoutPixel, LayoutSize};
|
||||
|
||||
|
@ -100,6 +100,22 @@ pub(crate) enum StackingContextSection {
|
|||
Outline,
|
||||
}
|
||||
|
||||
pub(crate) struct ScrollFrameHitTestItem {
|
||||
/// The [`ScrollTreeNodeId`] of the spatial node that contains this hit test item.
|
||||
pub scroll_node_id: ScrollTreeNodeId,
|
||||
|
||||
/// The [`ClipId`] of the clip that clips this [`ScrollFrameHitTestItems`].
|
||||
pub clip_id: ClipId,
|
||||
|
||||
/// The rectangle of the scroll frame in the coordinate space of [`Self::scroll_node_id`].
|
||||
pub rect: LayoutRect,
|
||||
|
||||
/// The WebRender [`ExternalScrollId`] of the scrolling spatial node that
|
||||
/// this [`ScrollFrameHitTestItem`] identifies. Note that this is a *different*
|
||||
/// spatial node than the one identified by [`Self::scroll_node_id`] (the parent).
|
||||
pub external_scroll_id: ExternalScrollId,
|
||||
}
|
||||
|
||||
pub(crate) struct StackingContextTree {
|
||||
/// The root stacking context of this [`StackingContextTree`].
|
||||
pub root_stacking_context: StackingContext,
|
||||
|
@ -114,6 +130,10 @@ pub(crate) struct StackingContextTree {
|
|||
/// for things like `overflow`. More clips may be created later during WebRender
|
||||
/// display list construction, but they are never added here.
|
||||
pub clip_store: StackingContextTreeClipStore,
|
||||
|
||||
/// A vector of hit test items, one per scroll frame. These are used for allowing
|
||||
/// renderer-side scrolling in the Servo renderer.
|
||||
pub hit_test_items: Vec<ScrollFrameHitTestItem>,
|
||||
}
|
||||
|
||||
impl StackingContextTree {
|
||||
|
@ -174,6 +194,7 @@ impl StackingContextTree {
|
|||
root_stacking_context: StackingContext::create_root(root_scroll_node_id, debug),
|
||||
compositor_info,
|
||||
clip_store: Default::default(),
|
||||
hit_test_items: Vec::new(),
|
||||
};
|
||||
|
||||
let mut root_stacking_context = StackingContext::create_root(root_scroll_node_id, debug);
|
||||
|
@ -281,7 +302,6 @@ pub(crate) enum StackingContextContent {
|
|||
section: StackingContextSection,
|
||||
containing_block: PhysicalRect<Au>,
|
||||
fragment: Fragment,
|
||||
is_hit_test_for_scrollable_overflow: bool,
|
||||
is_collapsed_table_borders: bool,
|
||||
text_decorations: Arc<Vec<FragmentTextDecoration>>,
|
||||
},
|
||||
|
@ -313,7 +333,6 @@ impl StackingContextContent {
|
|||
section,
|
||||
containing_block,
|
||||
fragment,
|
||||
is_hit_test_for_scrollable_overflow,
|
||||
is_collapsed_table_borders,
|
||||
text_decorations,
|
||||
} => {
|
||||
|
@ -324,7 +343,6 @@ impl StackingContextContent {
|
|||
builder,
|
||||
containing_block,
|
||||
*section,
|
||||
*is_hit_test_for_scrollable_overflow,
|
||||
*is_collapsed_table_borders,
|
||||
text_decorations,
|
||||
);
|
||||
|
@ -640,7 +658,6 @@ impl StackingContext {
|
|||
let mut fragment_builder = BuilderForBoxFragment::new(
|
||||
&root_fragment,
|
||||
&fragment_tree.initial_containing_block,
|
||||
false, /* is_hit_test_for_scrollable_overflow */
|
||||
false, /* is_collapsed_table_borders */
|
||||
);
|
||||
let painter = super::background::BackgroundPainter {
|
||||
|
@ -888,7 +905,6 @@ impl Fragment {
|
|||
clip_id: containing_block.clip_id,
|
||||
containing_block: containing_block.rect,
|
||||
fragment: fragment_clone,
|
||||
is_hit_test_for_scrollable_overflow: false,
|
||||
is_collapsed_table_borders: false,
|
||||
text_decorations: text_decorations.clone(),
|
||||
});
|
||||
|
@ -1088,7 +1104,6 @@ impl BoxFragment {
|
|||
BuilderForBoxFragment::new(
|
||||
self,
|
||||
&containing_block.rect,
|
||||
false, /* is_hit_test_for_scrollable_overflow */
|
||||
false, /* is_collapsed_table_borders */
|
||||
),
|
||||
)
|
||||
|
@ -1172,7 +1187,6 @@ impl BoxFragment {
|
|||
BuilderForBoxFragment::new(
|
||||
self,
|
||||
&containing_block.rect,
|
||||
false, /* is_hit_test_for_scrollable_overflow*/
|
||||
false, /* is_collapsed_table_borders */
|
||||
),
|
||||
) {
|
||||
|
@ -1205,7 +1219,6 @@ impl BoxFragment {
|
|||
section,
|
||||
containing_block: containing_block.rect,
|
||||
fragment: fragment.clone(),
|
||||
is_hit_test_for_scrollable_overflow: false,
|
||||
is_collapsed_table_borders: false,
|
||||
text_decorations: text_decorations.clone(),
|
||||
});
|
||||
|
@ -1234,21 +1247,6 @@ impl BoxFragment {
|
|||
if let Some(scroll_frame_data) = overflow_frame_data.scroll_frame_data {
|
||||
new_scroll_node_id = scroll_frame_data.scroll_tree_node_id;
|
||||
new_scroll_frame_size = Some(scroll_frame_data.scroll_frame_rect.size());
|
||||
|
||||
stacking_context
|
||||
.contents
|
||||
.push(StackingContextContent::Fragment {
|
||||
scroll_node_id: new_scroll_node_id,
|
||||
reference_frame_scroll_node_id:
|
||||
reference_frame_scroll_node_id_for_fragments,
|
||||
clip_id: new_clip_id,
|
||||
section,
|
||||
containing_block: containing_block.rect,
|
||||
fragment: fragment.clone(),
|
||||
is_hit_test_for_scrollable_overflow: true,
|
||||
is_collapsed_table_borders: false,
|
||||
text_decorations: text_decorations.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1345,7 +1343,6 @@ impl BoxFragment {
|
|||
section,
|
||||
containing_block: containing_block.rect,
|
||||
fragment: fragment.clone(),
|
||||
is_hit_test_for_scrollable_overflow: false,
|
||||
is_collapsed_table_borders: true,
|
||||
text_decorations: text_decorations.clone(),
|
||||
});
|
||||
|
@ -1417,7 +1414,7 @@ impl BoxFragment {
|
|||
// https://drafts.csswg.org/css-overflow-3/#corner-clipping
|
||||
let radii;
|
||||
if overflow.x == ComputedOverflow::Clip && overflow.y == ComputedOverflow::Clip {
|
||||
let builder = BuilderForBoxFragment::new(self, containing_block_rect, false, false);
|
||||
let builder = BuilderForBoxFragment::new(self, containing_block_rect, false);
|
||||
radii = offset_radii(builder.border_radius, clip_margin);
|
||||
} else if overflow.x != ComputedOverflow::Clip {
|
||||
overflow_clip_rect.min.x = f32::MIN;
|
||||
|
@ -1467,14 +1464,14 @@ impl BoxFragment {
|
|||
.to_webrender();
|
||||
|
||||
let clip_id = stacking_context_tree.clip_store.add(
|
||||
BuilderForBoxFragment::new(self, containing_block_rect, false, false).border_radius,
|
||||
BuilderForBoxFragment::new(self, containing_block_rect, false).border_radius,
|
||||
scroll_frame_rect,
|
||||
*parent_scroll_node_id,
|
||||
parent_clip_id,
|
||||
);
|
||||
|
||||
let tag = self.base.tag?;
|
||||
let external_id = wr::ExternalScrollId(
|
||||
let external_scroll_id = wr::ExternalScrollId(
|
||||
tag.to_display_list_fragment_id(),
|
||||
stacking_context_tree.compositor_info.pipeline_id,
|
||||
);
|
||||
|
@ -1486,12 +1483,21 @@ impl BoxFragment {
|
|||
|
||||
let scroll_tree_node_id = stacking_context_tree.define_scroll_frame(
|
||||
parent_scroll_node_id,
|
||||
external_id,
|
||||
external_scroll_id,
|
||||
self.scrollable_overflow().to_webrender(),
|
||||
scroll_frame_rect,
|
||||
sensitivity,
|
||||
);
|
||||
|
||||
stacking_context_tree
|
||||
.hit_test_items
|
||||
.push(ScrollFrameHitTestItem {
|
||||
scroll_node_id: *parent_scroll_node_id,
|
||||
clip_id,
|
||||
rect: scroll_frame_rect,
|
||||
external_scroll_id,
|
||||
});
|
||||
|
||||
Some(OverflowFrameData {
|
||||
clip_id,
|
||||
scroll_frame_data: Some(ScrollFrameData {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue