From 439765c9541700dd6ff3f505da6c1d97e1631e07 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Mon, 28 Feb 2022 05:54:42 +0000 Subject: [PATCH] Bug 1757259 - Fix snapping on surfaces with 180 + 180 deg rotations r=gfx-reviewers,aosmond Differential Revision: https://phabricator.services.mozilla.com/D139801 --- gfx/wr/webrender/src/batch.rs | 50 +++++++++++++++---- gfx/wr/webrender/src/picture.rs | 18 ++++++- gfx/wr/wrench/reftests/text/reftest.list | 2 + .../reftests/text/rotate-snap-clip-ref.yaml | 24 +++++++++ .../reftests/text/rotate-snap-clip.yaml | 27 ++++++++++ .../reftests/text/rotate-snap-filter-ref.yaml | 14 ++++++ .../reftests/text/rotate-snap-filter.yaml | 16 ++++++ 7 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 gfx/wr/wrench/reftests/text/rotate-snap-clip-ref.yaml create mode 100644 gfx/wr/wrench/reftests/text/rotate-snap-clip.yaml create mode 100644 gfx/wr/wrench/reftests/text/rotate-snap-filter-ref.yaml create mode 100644 gfx/wr/wrench/reftests/text/rotate-snap-filter.yaml diff --git a/gfx/wr/webrender/src/batch.rs b/gfx/wr/webrender/src/batch.rs index b1b2af1b01b6..b5f2ee1f2019 100644 --- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -1541,13 +1541,6 @@ impl BatchBuilder { let blend_mode = BlendMode::PremultipliedAlpha; let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle); - let prim_header = PrimitiveHeader { - local_rect: prim_rect, - local_clip_rect: prim_info.combined_local_clip_rect, - specific_prim_address: prim_cache_address, - transform_id, - }; - match picture.context_3d { // Convert all children of the 3D hierarchy root into batches. Picture3DContext::In { root_data: Some(_), .. } => { @@ -1568,6 +1561,45 @@ impl BatchBuilder { let surface = &ctx.surfaces[raster_config.surface_index.0]; + // If we are drawing with snapping enabled, the local rect of the prim must be in the raster + // space, to avoid situations where there is a 180deg rotation in between the root and primitive + // space not being correctly applied. + let prim_header = if surface.surface_spatial_node_index == surface.raster_spatial_node_index { + PrimitiveHeader { + local_rect: prim_rect, + local_clip_rect: prim_info.combined_local_clip_rect, + specific_prim_address: prim_cache_address, + transform_id, + } + } else { + let map_local_to_raster = SpaceMapper::new_with_target( + surface.raster_spatial_node_index, + surface.surface_spatial_node_index, + LayoutRect::max_rect(), + ctx.spatial_tree, + ); + + let prim_rect = map_local_to_raster + .map(&prim_rect) + .unwrap(); + let local_clip_rect = map_local_to_raster + .map(&prim_info.combined_local_clip_rect) + .unwrap(); + let transform_id = transforms + .get_id( + surface.raster_spatial_node_index, + root_spatial_node_index, + ctx.spatial_tree, + ); + + PrimitiveHeader { + local_rect: prim_rect, + local_clip_rect, + specific_prim_address: prim_cache_address, + transform_id, + } + }; + let mut is_opaque = prim_info.clip_task_index == ClipTaskIndex::INVALID && surface.is_opaque && transform_kind == TransformedRectKind::AxisAligned; @@ -2110,10 +2142,8 @@ impl BatchBuilder { }; let prim_header = PrimitiveHeader { - local_rect: prim_rect, - local_clip_rect: prim_info.combined_local_clip_rect, specific_prim_address: prim_cache_address, - transform_id, + ..prim_header }; let prim_header_index = prim_headers.push( diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs index 84ca4a2e0acf..1f1ab91c436c 100644 --- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -5867,11 +5867,27 @@ impl PicturePrimitive { shadow.blur_radius, ); - let shadow_rect = prim_rect.inflate( + let mut shadow_rect = prim_rect.inflate( blur_inflation_x * BLUR_SAMPLE_SCALE, blur_inflation_y * BLUR_SAMPLE_SCALE, ).translate(shadow.offset); + // If we are drawing with snapping enabled, the local rect of the prim must be in the raster + // space, to avoid situations where there is a 180deg rotation in between the root and primitive + // space not being correctly applied. + if surface.surface_spatial_node_index != surface.raster_spatial_node_index { + let map_local_to_raster = SpaceMapper::new_with_target( + surface.raster_spatial_node_index, + surface.surface_spatial_node_index, + LayoutRect::max_rect(), + frame_context.spatial_tree, + ); + + shadow_rect = map_local_to_raster + .map(&shadow_rect) + .unwrap(); + } + // ImageBrush colors request.push(shadow.color.premultiplied()); request.push(PremultipliedColorF::WHITE); diff --git a/gfx/wr/wrench/reftests/text/reftest.list b/gfx/wr/wrench/reftests/text/reftest.list index 6a6791d6366c..56b0291059ed 100644 --- a/gfx/wr/wrench/reftests/text/reftest.list +++ b/gfx/wr/wrench/reftests/text/reftest.list @@ -83,3 +83,5 @@ fuzzy(1,15) platform(linux) force_subpixel_aa_where_possible(false) == text-fixe # despite 4x on-the-fly scale change. skip_on(android) fuzzy(220,7600) == raster_root_C_8192.yaml raster_root_C_ref.yaml == subpx-bg-mask.yaml subpx-bg-mask-ref.yaml +platform(linux,mac) == rotate-snap-clip.yaml rotate-snap-clip-ref.yaml +platform(linux,mac) == rotate-snap-filter.yaml rotate-snap-filter-ref.yaml diff --git a/gfx/wr/wrench/reftests/text/rotate-snap-clip-ref.yaml b/gfx/wr/wrench/reftests/text/rotate-snap-clip-ref.yaml new file mode 100644 index 000000000000..5251fd89e5eb --- /dev/null +++ b/gfx/wr/wrench/reftests/text/rotate-snap-clip-ref.yaml @@ -0,0 +1,24 @@ +--- +root: + items: + - type: clip + id: 2 + bounds: [0, 0, 400, 30] + complex: + - rect: [0, 0, 400, 30] + radius: { + top-left: 2, + top-right: 2, + bottom-left: 2, + bottom-right: 2, + } + - type: stacking-context + clip-node: 2 + items: + - type: stacking-context + items: + - text: "Should be upright" + origin: 20 24 + size: 18 + color: black + font: "VeraBd.ttf" diff --git a/gfx/wr/wrench/reftests/text/rotate-snap-clip.yaml b/gfx/wr/wrench/reftests/text/rotate-snap-clip.yaml new file mode 100644 index 000000000000..4ae7dda83d51 --- /dev/null +++ b/gfx/wr/wrench/reftests/text/rotate-snap-clip.yaml @@ -0,0 +1,27 @@ +# Verify that snapping on a clipped surface with a 180 deg rotation + a local 180 deg rotation works correctly +--- +root: + items: + - type: clip + id: 2 + bounds: [0, 0, 400, 30] + complex: + - rect: [0, 0, 400, 30] + radius: { + top-left: 2, + top-right: 2, + bottom-left: 2, + bottom-right: 2, + } + - type: stacking-context + clip-node: 2 + transform: rotate(180) + items: + - type: stacking-context + transform: rotate(180) + items: + - text: "Should be upright" + origin: 20 24 + size: 18 + color: black + font: "VeraBd.ttf" diff --git a/gfx/wr/wrench/reftests/text/rotate-snap-filter-ref.yaml b/gfx/wr/wrench/reftests/text/rotate-snap-filter-ref.yaml new file mode 100644 index 000000000000..ae230425ac1d --- /dev/null +++ b/gfx/wr/wrench/reftests/text/rotate-snap-filter-ref.yaml @@ -0,0 +1,14 @@ +# Verify that snapping on a filtered surface with a 180 deg rotation + a local 180 deg rotation works correctly +--- +root: + items: + - type: stacking-context + filters: [opacity(0.5)] + items: + - type: stacking-context + items: + - text: "Should be upright" + origin: 20 24 + size: 18 + color: black + font: "VeraBd.ttf" diff --git a/gfx/wr/wrench/reftests/text/rotate-snap-filter.yaml b/gfx/wr/wrench/reftests/text/rotate-snap-filter.yaml new file mode 100644 index 000000000000..48be649aa24c --- /dev/null +++ b/gfx/wr/wrench/reftests/text/rotate-snap-filter.yaml @@ -0,0 +1,16 @@ +# Verify that snapping on a filtered surface with a 180 deg rotation + a local 180 deg rotation works correctly +--- +root: + items: + - type: stacking-context + filters: [opacity(0.5)] + transform: rotate(180) + items: + - type: stacking-context + transform: rotate(180) + items: + - text: "Should be upright" + origin: 20 24 + size: 18 + color: black + font: "VeraBd.ttf"