dependencies: Upgrade to WebRender 0.64 (#31486)

This brings the version of WebRender used in Servo up-to-date with Gecko
upstream. The big change here is that HiDPI is no longer handled via
WebRender. Instead this happens via a scale applied to the root layer in
the compositor. In addition to this change, various changes are made to
Servo to adapt to the new WebRender API.

Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
Martin Robinson 2024-03-14 18:40:54 +01:00 committed by GitHub
parent 4597aeae5f
commit ad37a54f59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
102 changed files with 704 additions and 600 deletions

View file

@ -66,7 +66,7 @@ impl<'a> BackgroundPainter<'a> {
// The 'backgound-clip' property maps directly to `clip_rect` in `CommonItemProperties`:
let mut common = builder.common_properties(*painting_area, &fb.fragment.style);
if let Some(clip_chain_id) = clip {
common.clip_id = wr::ClipId::ClipChain(clip_chain_id)
common.clip_chain_id = clip_chain_id;
}
(painting_area, common)
}
@ -105,9 +105,9 @@ pub(super) fn layout_layer(
Cover,
}
let size_contain_or_cover = |background_size| {
let mut tile_size = positioning_area.size;
let mut tile_size = positioning_area.size();
if let Some(intrinsic_ratio) = intrinsic.ratio {
let positioning_ratio = positioning_area.size.width / positioning_area.size.height;
let positioning_ratio = positioning_area.size().width / positioning_area.size().height;
// Whether the tile width (as opposed to height)
// is scaled to that of the positioning area
let fit_width = match background_size {
@ -130,10 +130,10 @@ pub(super) fn layout_layer(
Size::Cover => size_contain_or_cover(ContainOrCover::Cover),
Size::ExplicitSize { width, height } => {
let mut width = width.non_auto().map(|lp| {
lp.0.percentage_relative_to(Length::new(positioning_area.size.width))
lp.0.percentage_relative_to(Length::new(positioning_area.size().width))
});
let mut height = height.non_auto().map(|lp| {
lp.0.percentage_relative_to(Length::new(positioning_area.size.height))
lp.0.percentage_relative_to(Length::new(positioning_area.size().height))
});
if width.is_none() && height.is_none() {
@ -152,7 +152,7 @@ pub(super) fn layout_layer(
intrinsic_height.into()
} else {
// Treated as 100%
Au::from_f32_px(positioning_area.size.height).into()
Au::from_f32_px(positioning_area.size().height).into()
};
units::LayoutSize::new(w.px(), h.px())
},
@ -163,7 +163,7 @@ pub(super) fn layout_layer(
intrinsic_width.into()
} else {
// Treated as 100%
Au::from_f32_px(positioning_area.size.width).into()
Au::from_f32_px(positioning_area.size().width).into()
};
units::LayoutSize::new(w.px(), h.px())
},
@ -182,20 +182,20 @@ pub(super) fn layout_layer(
&mut tile_size.width,
repeat_x,
get_cyclic(&b.background_position_x.0, layer_index),
painting_area.origin.x - positioning_area.origin.x,
painting_area.size.width,
positioning_area.size.width,
painting_area.min.x - positioning_area.min.x,
painting_area.size().width,
positioning_area.size().width,
);
let result_y = layout_1d(
&mut tile_size.height,
repeat_y,
get_cyclic(&b.background_position_y.0, layer_index),
painting_area.origin.y - positioning_area.origin.y,
painting_area.size.height,
positioning_area.size.height,
painting_area.min.y - positioning_area.min.y,
painting_area.size().height,
positioning_area.size().height,
);
let bounds = units::LayoutRect::new(
positioning_area.origin + Vector2D::new(result_x.bounds_origin, result_y.bounds_origin),
let bounds = units::LayoutRect::from_origin_and_size(
positioning_area.min + Vector2D::new(result_x.bounds_origin, result_y.bounds_origin),
Size2D::new(result_x.bounds_size, result_y.bounds_size),
);
let tile_spacing = units::LayoutSize::new(result_x.tile_spacing, result_y.tile_spacing);

View file

@ -111,14 +111,20 @@ impl ToWebRender for PhysicalSize<Au> {
impl ToWebRender for PhysicalRect<Length> {
type Type = units::LayoutRect;
fn to_webrender(&self) -> Self::Type {
units::LayoutRect::new(self.origin.to_webrender(), self.size.to_webrender())
units::LayoutRect::from_origin_and_size(
self.origin.to_webrender(),
self.size.to_webrender(),
)
}
}
impl ToWebRender for PhysicalRect<Au> {
type Type = units::LayoutRect;
fn to_webrender(&self) -> Self::Type {
units::LayoutRect::new(self.origin.to_webrender(), self.size.to_webrender())
units::LayoutRect::from_origin_and_size(
self.origin.to_webrender(),
self.size.to_webrender(),
)
}
}

View file

@ -12,7 +12,7 @@ use gfx::text::glyph::GlyphStore;
use gfx_traits::WebRenderEpochToU16;
use msg::constellation_msg::BrowsingContextId;
use net_traits::image_cache::UsePlaceholder;
use script_traits::compositor::{CompositorDisplayListInfo, ScrollTreeNodeId};
use script_traits::compositor::{CompositorDisplayListInfo, ScrollSensitivity, ScrollTreeNodeId};
use servo_geometry::MaxRect;
use style::color::{AbsoluteColor, ColorSpace};
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
@ -23,9 +23,8 @@ use style::values::computed::{BorderStyle, Color, Length, LengthPercentage, Outl
use style::values::specified::text::TextDecorationLine;
use style::values::specified::ui::CursorKind;
use style_traits::CSSPixel;
use webrender_api::{self as wr, units, ClipChainId, ClipId, CommonItemProperties};
use webrender_api::{self as wr, units, BoxShadowClipMode, ClipChainId};
use wr::units::LayoutVector2D;
use wr::{BoxShadowClipMode, ScrollSensitivity};
use crate::context::LayoutContext;
use crate::display_list::conversions::ToWebRender;
@ -69,6 +68,11 @@ pub struct DisplayList {
/// data structure that the compositor uses to map hit tests to information
/// about the item hit.
pub compositor_info: CompositorDisplayListInfo,
/// A count of the number of SpatialTree nodes pushed to the WebRender display
/// list. This is merely to ensure that the currently-unused SpatialTreeItemKey
/// produced for every SpatialTree node is unique.
pub spatial_tree_count: u64,
}
impl DisplayList {
@ -90,8 +94,25 @@ impl DisplayList {
epoch,
root_scroll_sensitivity,
),
spatial_tree_count: 0,
}
}
pub fn define_clip_chain<I>(&mut self, parent: ClipChainId, clips: I) -> ClipChainId
where
I: IntoIterator<Item = wr::ClipId>,
I::IntoIter: ExactSizeIterator + Clone,
{
// WebRender has two different ways of expressing "no clip." ClipChainId::INVALID should be
// used for primitives, but `None` is used for stacking contexts and clip chains. We convert
// to the `Option<ClipChainId>` representation here. Just passing Some(ClipChainId::INVALID)
// leads to a crash.
let parent = match parent {
ClipChainId::INVALID => None,
parent => Some(parent),
};
self.wr.define_clip_chain(parent, clips)
}
}
pub(crate) struct DisplayListBuilder<'a> {
@ -139,7 +160,7 @@ impl DisplayList {
) -> (FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>, bool) {
let mut builder = DisplayListBuilder {
current_scroll_node_id: self.compositor_info.root_reference_frame_id,
current_clip_chain_id: ClipChainId(0, self.compositor_info.pipeline_id),
current_clip_chain_id: ClipChainId::INVALID,
element_for_canvas_background: fragment_tree.canvas_background.from_element,
is_contentful: false,
context,
@ -167,7 +188,7 @@ impl<'a> DisplayListBuilder<'a> {
wr::CommonItemProperties {
clip_rect,
spatial_id: self.current_scroll_node_id.spatial_id,
clip_id: ClipId::ClipChain(self.current_clip_chain_id),
clip_chain_id: self.current_clip_chain_id,
flags: style.get_webrender_primitive_flags(),
}
}
@ -268,7 +289,7 @@ impl Fragment {
common.clip_rect,
&wr::SpaceAndClipInfo {
spatial_id: common.spatial_id,
clip_id: common.clip_id,
clip_chain_id: common.clip_chain_id,
},
iframe.pipeline_id.to_webrender(),
true,
@ -304,12 +325,10 @@ impl Fragment {
let clip_chain_id = builder.current_clip_chain_id;
let spatial_id = builder.current_scroll_node_id.spatial_id;
builder.wr().push_hit_test(
&CommonItemProperties {
clip_rect: rect.to_webrender(),
clip_id: ClipId::ClipChain(clip_chain_id),
spatial_id,
flags: style.get_webrender_primitive_flags(),
},
rect.to_webrender(),
clip_chain_id,
spatial_id,
style.get_webrender_primitive_flags(),
hit_info,
);
}
@ -405,7 +424,7 @@ impl Fragment {
color: &AbsoluteColor,
) {
let rect = rect.to_webrender();
let wavy_line_thickness = (0.33 * rect.size.height).ceil();
let wavy_line_thickness = (0.33 * rect.size().height).ceil();
let text_decoration_color = fragment
.parent_style
.clone_text_decoration_color()
@ -452,8 +471,8 @@ impl<'a> BuilderForBoxFragment<'a> {
};
let corner = |corner: &style::values::computed::BorderCornerRadius| {
Size2D::new(
resolve(&corner.0.width.0, border_rect.size.width),
resolve(&corner.0.height.0, border_rect.size.height),
resolve(&corner.0.width.0, border_rect.size().width),
resolve(&corner.0.height.0, border_rect.size().height),
)
};
let b = fragment.style.get_border();
@ -577,9 +596,15 @@ impl<'a> BuilderForBoxFragment<'a> {
let mut common = builder.common_properties(self.border_rect, &self.fragment.style);
if let Some(clip_chain_id) = self.border_edge_clip(builder) {
common.clip_id = ClipId::ClipChain(clip_chain_id);
common.clip_chain_id = clip_chain_id;
}
builder.wr().push_hit_test(&common, hit_info);
builder.wr().push_hit_test(
common.clip_rect,
common.clip_chain_id,
common.spatial_id,
common.flags,
hit_info,
);
}
fn build_background_for_painter(
@ -1011,13 +1036,10 @@ fn clip_for_radii(
if radii.is_zero() {
None
} else {
let clip_chain_id = builder.current_clip_chain_id;
let parent_space_and_clip = wr::SpaceAndClipInfo {
spatial_id: builder.current_scroll_node_id.spatial_id,
clip_id: ClipId::ClipChain(clip_chain_id),
};
let spatial_id = builder.current_scroll_node_id.spatial_id;
let parent_clip_chain_id = builder.current_clip_chain_id;
let new_clip_id = builder.wr().define_clip_rounded_rect(
&parent_space_and_clip,
spatial_id,
wr::ComplexClipRegion {
rect,
radii,
@ -1026,8 +1048,8 @@ fn clip_for_radii(
);
Some(
builder
.wr()
.define_clip_chain(Some(clip_chain_id), [new_clip_id]),
.display_list
.define_clip_chain(parent_clip_chain_id, [new_clip_id]),
)
}
}

View file

@ -9,7 +9,7 @@ use euclid::default::Rect;
use euclid::SideOffsets2D;
use gfx_traits::print_tree::PrintTree;
use log::warn;
use script_traits::compositor::{ScrollTreeNodeId, ScrollableNodeInfo};
use script_traits::compositor::{ScrollSensitivity, ScrollTreeNodeId, ScrollableNodeInfo};
use servo_arc::Arc as ServoArc;
use servo_config::opts::DebugOptions;
use style::computed_values::float::T as ComputedFloat;
@ -23,9 +23,8 @@ use style::values::generics::transform;
use style::values::specified::box_::DisplayOutside;
use webrender_api as wr;
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D};
use webrender_api::ScrollSensitivity;
use wr::units::{LayoutPixel, LayoutSize};
use wr::StickyOffsetBounds;
use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds};
use super::DisplayList;
use crate::cell::ArcRefCell;
@ -90,26 +89,30 @@ pub(crate) enum StackingContextSection {
}
impl DisplayList {
/// Produce a new SpatialTreeItemKey. This is currently unused by WebRender,
/// but has to be unique to the entire scene.
fn get_next_spatial_tree_item_key(&mut self) -> SpatialTreeItemKey {
self.spatial_tree_count += 1;
let pipeline_tag = (self.wr.pipeline_id.0 as u64) << 32 | self.wr.pipeline_id.1 as u64;
SpatialTreeItemKey::new(pipeline_tag, self.spatial_tree_count)
}
pub fn build_stacking_context_tree(
&mut self,
fragment_tree: &FragmentTree,
debug: &DebugOptions,
) -> StackingContext {
let root_clip_chain_id = self
.wr
.define_clip_chain(None, [wr::ClipId::root(self.wr.pipeline_id)]);
let cb_for_non_fixed_descendants = ContainingBlock::new(
fragment_tree.initial_containing_block,
self.compositor_info.root_scroll_node_id,
Some(self.compositor_info.viewport_size),
root_clip_chain_id,
ClipChainId::INVALID,
);
let cb_for_fixed_descendants = ContainingBlock::new(
fragment_tree.initial_containing_block,
self.compositor_info.root_reference_frame_id,
None,
root_clip_chain_id,
ClipChainId::INVALID,
);
// We need to specify all three containing blocks here, because absolute
@ -146,12 +149,14 @@ impl DisplayList {
transform: wr::PropertyBinding<LayoutTransform>,
kind: wr::ReferenceFrameKind,
) -> ScrollTreeNodeId {
let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
let new_spatial_id = self.wr.push_reference_frame(
origin,
parent_scroll_node_id.spatial_id,
transform_style,
transform,
kind,
spatial_tree_item_key,
);
self.compositor_info.scroll_tree.add_scroll_tree_node(
Some(parent_scroll_node_id),
@ -173,36 +178,29 @@ impl DisplayList {
clip_rect: LayoutRect,
scroll_sensitivity: ScrollSensitivity,
) -> (ScrollTreeNodeId, wr::ClipChainId) {
let parent_space_and_clip_info = wr::SpaceAndClipInfo {
spatial_id: parent_scroll_node_id.spatial_id,
clip_id: wr::ClipId::root(self.wr.pipeline_id),
};
let new_clip_id = self
.wr
.define_clip_rect(&parent_space_and_clip_info, clip_rect);
.define_clip_rect(parent_scroll_node_id.spatial_id, clip_rect);
let new_clip_chain_id = self.define_clip_chain(*parent_clip_chain_id, [new_clip_id]);
let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
let new_clip_chain_id = self
.wr
.define_clip_chain(Some(*parent_clip_chain_id), [new_clip_id]);
let new_spatial_id = self
.wr
.define_scroll_frame(
&parent_space_and_clip_info,
external_id,
content_rect,
clip_rect,
scroll_sensitivity,
LayoutVector2D::zero(), /* external_scroll_offset */
)
.spatial_id;
let new_spatial_id = self.wr.define_scroll_frame(
parent_scroll_node_id.spatial_id,
external_id,
content_rect,
clip_rect,
LayoutVector2D::zero(), /* external_scroll_offset */
0, /* scroll_offset_generation */
wr::HasScrollLinkedEffect::No,
spatial_tree_item_key,
);
let new_scroll_node_id = self.compositor_info.scroll_tree.add_scroll_tree_node(
Some(parent_scroll_node_id),
new_spatial_id,
Some(ScrollableNodeInfo {
external_id,
scrollable_size: content_rect.size - clip_rect.size,
scrollable_size: content_rect.size() - clip_rect.size(),
scroll_sensitivity,
offset: LayoutVector2D::zero(),
}),
@ -218,13 +216,15 @@ impl DisplayList {
vertical_offset_bounds: StickyOffsetBounds,
horizontal_offset_bounds: StickyOffsetBounds,
) -> ScrollTreeNodeId {
let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
let new_spatial_id = self.wr.define_sticky_frame(
parent_scroll_node_id.spatial_id,
frame_rect,
margins,
vertical_offset_bounds,
horizontal_offset_bounds,
LayoutVector2D::zero(),
LayoutVector2D::zero(), /* previously_applied_offset */
spatial_tree_item_key,
);
self.compositor_info.scroll_tree.add_scroll_tree_node(
Some(parent_scroll_node_id),
@ -368,10 +368,18 @@ impl StackingContext {
fn create_descendant(
&self,
spatial_id: wr::SpatialId,
clip_chain_id: Option<wr::ClipChainId>,
clip_chain_id: wr::ClipChainId,
initializing_fragment_style: ServoArc<ComputedValues>,
context_type: StackingContextType,
) -> Self {
// WebRender has two different ways of expressing "no clip." ClipChainId::INVALID should be
// used for primitives, but `None` is used for stacking contexts and clip chains. We convert
// to the `Option<ClipChainId>` representation here. Just passing Some(ClipChainId::INVALID)
// leads to a crash.
let clip_chain_id: Option<ClipChainId> = match clip_chain_id {
ClipChainId::INVALID => None,
clip_chain_id => Some(clip_chain_id),
};
Self {
spatial_id,
clip_chain_id,
@ -471,8 +479,6 @@ impl StackingContext {
return false;
}
let clip_id = self.clip_chain_id.map(wr::ClipId::ClipChain);
// Create the filter pipeline.
let current_color = style.clone_color();
let mut filters: Vec<wr::FilterOp> = effects
@ -498,7 +504,7 @@ impl StackingContext {
LayoutPoint::zero(), // origin
self.spatial_id,
style.get_webrender_primitive_flags(),
clip_id,
self.clip_chain_id,
style.get_used_transform_style().to_webrender(),
effects.mix_blend_mode.to_webrender(),
&filters,
@ -621,13 +627,13 @@ impl StackingContext {
if let Some(reference_frame_data) =
box_fragment.reference_frame_data_if_necessary(containing_block_rect)
{
painting_area.origin -= reference_frame_data.origin.to_webrender().to_vector();
painting_area.min -= reference_frame_data.origin.to_webrender().to_vector();
if let Some(transformed) = reference_frame_data
.transform
.inverse()
.and_then(|inversed| inversed.outer_transformed_rect(&painting_area))
.and_then(|inversed| inversed.outer_transformed_rect(&painting_area.to_rect()))
{
painting_area = transformed
painting_area = transformed.to_box2d();
} else {
// The desired rect cannot be represented, so skip painting this background-image
return;
@ -1038,7 +1044,7 @@ impl BoxFragment {
let mut child_stacking_context = parent_stacking_context.create_descendant(
containing_block.scroll_node_id.spatial_id,
Some(containing_block.clip_chain_id),
containing_block.clip_chain_id,
self.style.clone(),
context_type,
);
@ -1219,19 +1225,10 @@ impl BoxFragment {
.translate(containing_block_rect.origin.to_vector())
.to_webrender();
let parent_space_and_clip = &wr::SpaceAndClipInfo {
spatial_id: parent_scroll_node_id.spatial_id,
clip_id: wr::ClipId::root(display_list.wr.pipeline_id),
};
let clip_id = display_list
.wr
.define_clip_rect(parent_space_and_clip, clip_rect);
Some(
display_list
.wr
.define_clip_chain(Some(*parent_clip_chain_id), [clip_id]),
)
.define_clip_rect(parent_scroll_node_id.spatial_id, clip_rect);
Some(display_list.define_clip_chain(*parent_clip_chain_id, [clip_id]))
}
fn build_scroll_frame_if_necessary(
@ -1294,7 +1291,7 @@ impl BoxFragment {
sensitivity,
);
Some((scroll_tree_node_id, clip_chain_id, padding_rect.size))
Some((scroll_tree_node_id, clip_chain_id, padding_rect.size()))
}
fn build_sticky_frame_if_necessary(
@ -1361,12 +1358,12 @@ impl BoxFragment {
// This is the minimum negative offset and then the maximum positive offset. We just
// specify every edge, but if the corresponding margin is None, that offset has no effect.
let vertical_offset_bounds = wr::StickyOffsetBounds::new(
containing_block_rect.min_y() - frame_rect.min_y(),
containing_block_rect.max_y() - frame_rect.max_y(),
containing_block_rect.min.y - frame_rect.min.y,
containing_block_rect.max.y - frame_rect.max.y,
);
let horizontal_offset_bounds = wr::StickyOffsetBounds::new(
containing_block_rect.min_x() - frame_rect.min_x(),
containing_block_rect.max_x() - frame_rect.max_x(),
containing_block_rect.min.x - frame_rect.min.x,
containing_block_rect.max.x - frame_rect.max.x,
);
let margins = SideOffsets2D::new(
@ -1416,6 +1413,7 @@ impl BoxFragment {
wr::ReferenceFrameKind::Transform {
is_2d_scale_translation: false,
should_snap: false,
paired_with_perspective: false,
},
),
(Some(transform), Some(perspective)) => (

View file

@ -7,13 +7,13 @@ use script_layout_interface::wrapper_traits::{
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
use script_layout_interface::{LayoutElementType, LayoutNodeType};
use script_traits::compositor::ScrollSensitivity;
use serde::Serialize;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{Length, Overflow};
use style_traits::CSSPixel;
use webrender_api::ScrollSensitivity;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;

View file

@ -6,11 +6,12 @@ use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use fxhash::FxHashSet;
use gfx_traits::print_tree::PrintTree;
use script_traits::compositor::ScrollSensitivity;
use serde::Serialize;
use style::animation::AnimationSetKey;
use style::dom::OpaqueNode;
use style::values::computed::Length;
use webrender_api::{units, ScrollSensitivity};
use webrender_api::units;
use super::{ContainingBlockManager, Fragment, Tag};
use crate::cell::ArcRefCell;