Separate computing a WR reference frame from adding it to the display list

This commit is contained in:
Simon Sapin 2020-05-13 17:45:57 +02:00
parent 3e8623332b
commit c7acfc37ed

View file

@ -364,6 +364,12 @@ impl Fragment {
} }
} }
struct ReferenceFrameData {
origin: crate::geom::PhysicalPoint<Length>,
transform: LayoutTransform,
kind: wr::ReferenceFrameKind,
}
impl BoxFragment { impl BoxFragment {
fn get_stacking_context_type(&self) -> Option<StackingContextType> { fn get_stacking_context_type(&self) -> Option<StackingContextType> {
if self.style.establishes_stacking_context() { if self.style.establishes_stacking_context() {
@ -464,22 +470,24 @@ impl BoxFragment {
) { ) {
// If we are creating a stacking context, we may also need to create a reference // If we are creating a stacking context, we may also need to create a reference
// frame first. // frame first.
let relative_border_rect = self let reference_frame_data = self.reference_frame_data_if_necessary(containing_block_info);
.border_rect()
.to_physical(self.style.writing_mode, &containing_block_info.rect);
let border_rect =
relative_border_rect.translate(containing_block_info.rect.origin.to_vector());
let established_reference_frame =
self.build_reference_frame_if_necessary(builder, &border_rect);
// WebRender reference frames establish a new coordinate system at their origin // WebRender reference frames establish a new coordinate system at their origin
// (the border box of the fragment). We need to ensure that any coordinates we // (the border box of the fragment). We need to ensure that any coordinates we
// give to WebRender in this reference frame are relative to the fragment border // give to WebRender in this reference frame are relative to the fragment border
// box. We do this by adjusting the containing block origin. // box. We do this by adjusting the containing block origin.
let mut new_containing_block_info = containing_block_info.clone(); let mut new_containing_block_info = containing_block_info.clone();
if established_reference_frame {
new_containing_block_info.rect.origin = if let Some(reference_frame_data) = &reference_frame_data {
(-relative_border_rect.origin.to_vector()).to_point(); new_containing_block_info.rect.origin -= reference_frame_data.origin.to_vector();
builder.current_space_and_clip.spatial_id = builder.wr.push_reference_frame(
reference_frame_data.origin.to_webrender(),
builder.current_space_and_clip.spatial_id,
self.style.get_box().transform_style.to_webrender(),
wr::PropertyBinding::Value(reference_frame_data.transform),
reference_frame_data.kind,
);
builder.nearest_reference_frame = builder.current_space_and_clip.spatial_id;
} }
let mut child_stacking_context = StackingContext::new( let mut child_stacking_context = StackingContext::new(
@ -510,7 +518,7 @@ impl BoxFragment {
.stacking_contexts .stacking_contexts
.append(&mut stolen_children); .append(&mut stolen_children);
if established_reference_frame { if reference_frame_data.is_some() {
builder.wr.pop_reference_frame(); builder.wr.pop_reference_frame();
} }
} }
@ -611,17 +619,22 @@ impl BoxFragment {
} }
} }
/// Build a reference frame for this fragment if it is necessary. Returns `true` if /// Optionally returns the data for building a reference frame, without yet building it.
/// a reference was built and `false` otherwise. fn reference_frame_data_if_necessary(
fn build_reference_frame_if_necessary(
&self, &self,
builder: &mut StackingContextBuilder, containing_block_info: &ContainingBlockInfo,
border_rect: &PhysicalRect<Length>, ) -> Option<ReferenceFrameData> {
) -> bool {
if !self.style.has_transform_or_perspective() { if !self.style.has_transform_or_perspective() {
return false; return None;
} }
let relative_border_rect = self
.border_rect()
.to_physical(self.style.writing_mode, &containing_block_info.rect);
let border_rect = relative_border_rect
.translate(containing_block_info.rect.origin.to_vector());
let untyped_border_rect = border_rect.to_untyped(); let untyped_border_rect = border_rect.to_untyped();
let transform = self.calculate_transform_matrix(&untyped_border_rect); let transform = self.calculate_transform_matrix(&untyped_border_rect);
let perspective = self.calculate_perspective_matrix(&untyped_border_rect); let perspective = self.calculate_perspective_matrix(&untyped_border_rect);
let (reference_frame_transform, reference_frame_kind) = match (transform, perspective) { let (reference_frame_transform, reference_frame_kind) = match (transform, perspective) {
@ -641,15 +654,11 @@ impl BoxFragment {
(None, None) => unreachable!(), (None, None) => unreachable!(),
}; };
builder.current_space_and_clip.spatial_id = builder.wr.push_reference_frame( Some(ReferenceFrameData {
border_rect.origin.to_webrender(), origin: border_rect.origin,
builder.current_space_and_clip.spatial_id, transform: reference_frame_transform,
self.style.get_box().transform_style.to_webrender(), kind: reference_frame_kind,
wr::PropertyBinding::Value(reference_frame_transform), })
reference_frame_kind,
);
builder.nearest_reference_frame = builder.current_space_and_clip.spatial_id;
true
} }
/// Returns the 4D matrix representing this fragment's transform. /// Returns the 4D matrix representing this fragment's transform.