From 06dadaa7a67efda247fbbf488c90cdbc622907d6 Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Thu, 15 Apr 2021 18:54:38 +0000 Subject: [PATCH] Bug 1675375 Part 2: Add a polygon clips to image masks. r=gw This patch augments the pushing of an image mask to allow a polygon clip region to be attached to it. Differential Revision: https://phabricator.services.mozilla.com/D105397 --- gfx/webrender_bindings/WebRenderAPI.cpp | 6 ++-- gfx/webrender_bindings/WebRenderAPI.h | 4 ++- gfx/webrender_bindings/cbindgen.toml | 2 ++ gfx/webrender_bindings/src/bindings.rs | 18 +++++++--- gfx/wr/examples/basic.rs | 2 ++ gfx/wr/webrender/src/picture.rs | 5 ++- gfx/wr/webrender_api/src/display_item.rs | 2 ++ gfx/wr/webrender_api/src/display_list.rs | 6 ++-- gfx/wr/wrench/src/yaml_frame_reader.rs | 3 ++ layout/painting/nsDisplayList.cpp | 46 +++++++++++++++++++++++- 10 files changed, 80 insertions(+), 14 deletions(-) diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index 0c71ccd0852a..920effe698a3 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -1072,11 +1072,13 @@ wr::WrClipId DisplayListBuilder::DefineClip( } wr::WrClipId DisplayListBuilder::DefineImageMaskClip( - const wr::ImageMask& aMask) { + const wr::ImageMask& aMask, const nsTArray& aPoints, + wr::FillRule aFillRule) { CancelGroup(); WrClipId clipId = wr_dp_define_image_mask_clip_with_parent_clip_chain( - mWrState, &mCurrentSpaceAndClipChain, aMask); + mWrState, &mCurrentSpaceAndClipChain, aMask, aPoints.Elements(), + aPoints.Length(), aFillRule); return clipId; } diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index 9cbee1f9b6b4..1426642fb007 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -460,7 +460,9 @@ class DisplayListBuilder final { const Maybe& aParent, const wr::LayoutRect& aClipRect, const nsTArray* aComplex = nullptr); - wr::WrClipId DefineImageMaskClip(const wr::ImageMask& aMask); + wr::WrClipId DefineImageMaskClip(const wr::ImageMask& aMask, + const nsTArray&, + wr::FillRule); wr::WrClipId DefineRoundedRectClip(const wr::ComplexClipRegion& aComplex); wr::WrClipId DefineRectClip(wr::LayoutRect aClipRect); diff --git a/gfx/webrender_bindings/cbindgen.toml b/gfx/webrender_bindings/cbindgen.toml index b7f81cd238f5..e41bff3fd871 100644 --- a/gfx/webrender_bindings/cbindgen.toml +++ b/gfx/webrender_bindings/cbindgen.toml @@ -16,9 +16,11 @@ namespaces = ["mozilla", "wr"] [export] item_types = ["globals", "enums", "structs", "unions", "typedefs", "opaque", "functions", "constants"] +include = ["POLYGON_CLIP_VERTEX_MAX"] [parse] parse_deps = true +extra_bindings = ["webrender_api"] include = ["log", "euclid", "webrender", "webrender_api"] [fn] diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index 90c1a5448725..733a7202be1f 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -2554,7 +2554,7 @@ pub extern "C" fn wr_dp_push_stacking_context( let reference_frame_kind = match params.reference_frame_kind { WrReferenceFrameKind::Transform => ReferenceFrameKind::Transform { is_2d_scale_translation, - should_snap + should_snap, }, WrReferenceFrameKind::Perspective => ReferenceFrameKind::Perspective { scrolling_relative_to }, }; @@ -2685,13 +2685,21 @@ pub extern "C" fn wr_dp_define_image_mask_clip_with_parent_clip_chain( state: &mut WrState, parent: &WrSpaceAndClipChain, mask: ImageMask, + points: *const LayoutPoint, + point_count: usize, + fill_rule: FillRule, ) -> WrClipId { debug_assert!(unsafe { is_in_main_thread() }); - let clip_id = state - .frame_builder - .dl_builder - .define_clip_image_mask(&parent.to_webrender(state.pipeline_id), mask); + let c_points = unsafe { make_slice(points, point_count) }; + let points: Vec = c_points.iter().copied().collect(); + + let clip_id = state.frame_builder.dl_builder.define_clip_image_mask( + &parent.to_webrender(state.pipeline_id), + mask, + &points, + fill_rule, + ); WrClipId::from_webrender(clip_id) } diff --git a/gfx/wr/examples/basic.rs b/gfx/wr/examples/basic.rs index 8c7d60c60cce..549d0e39a11a 100644 --- a/gfx/wr/examples/basic.rs +++ b/gfx/wr/examples/basic.rs @@ -221,6 +221,8 @@ impl Example for App { let mask_clip_id = builder.define_clip_image_mask( &root_space_and_clip, mask, + &vec![], + FillRule::Nonzero, ); let clip_id = builder.define_clip_rounded_rect( &SpaceAndClipInfo { diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs index 870d20f61ada..27fa6d1b8235 100644 --- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -267,6 +267,9 @@ pub struct TileCoordinate; // Geometry types for tile coordinates. pub type TileOffset = Point2D; +// TileSize type is also used in used in lib.rs and cbindgen picks the wrong one when +// generating headers. +/// cbindgen:ignore pub type TileSize = Size2D; pub type TileRect = Rect; @@ -6318,7 +6321,7 @@ impl PicturePrimitive { } // Map the cluster bounding rect into the space of the surface, and - // include it in the surface bounding rect. + // include it in the surface bounding rect. surface.map_local_to_surface.set_target_spatial_node( cluster.spatial_node_index, frame_context.spatial_tree, diff --git a/gfx/wr/webrender_api/src/display_item.rs b/gfx/wr/webrender_api/src/display_item.rs index 43a392a59f1e..52125da073a6 100644 --- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -1491,6 +1491,8 @@ impl ComplexClipRegion { } } +pub const POLYGON_CLIP_VERTEX_MAX: usize = 16; + #[repr(u8)] #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] pub enum FillRule { diff --git a/gfx/wr/webrender_api/src/display_list.rs b/gfx/wr/webrender_api/src/display_list.rs index 094f3f9d4b78..26c7ce0bc723 100644 --- a/gfx/wr/webrender_api/src/display_list.rs +++ b/gfx/wr/webrender_api/src/display_list.rs @@ -1800,11 +1800,9 @@ impl DisplayListBuilder { &mut self, parent_space_and_clip: &di::SpaceAndClipInfo, image_mask: di::ImageMask, + points: &[LayoutPoint], + fill_rule: di::FillRule, ) -> di::ClipId { - // TODO(bradwerth): get points and fill_rule as parameters. - let points = Vec::::new(); - let fill_rule = di::FillRule::Nonzero; - let id = self.generate_clip_index(); let item = di::DisplayItem::ImageMaskClip(di::ImageMaskClipDisplayItem { id, diff --git a/gfx/wr/wrench/src/yaml_frame_reader.rs b/gfx/wr/wrench/src/yaml_frame_reader.rs index c79e1625535e..492f155b6679 100644 --- a/gfx/wr/wrench/src/yaml_frame_reader.rs +++ b/gfx/wr/wrench/src/yaml_frame_reader.rs @@ -17,6 +17,7 @@ use std::usize; use webrender::api::*; use webrender::render_api::*; use webrender::api::units::*; +use webrender::api::FillRule; use crate::wrench::{FontDescriptor, Wrench, WrenchThing}; use crate::yaml_helper::{StringEnum, YamlHelper, make_perspective}; use yaml_rust::{Yaml, YamlLoader}; @@ -1982,6 +1983,8 @@ impl YamlFrameReader { space_and_clip.clip_id = dl.define_clip_image_mask( &space_and_clip, image_mask, + &vec![], + FillRule::Nonzero, ); } diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 52791ce16bb9..d708e3201977 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -9514,6 +9514,43 @@ static Maybe CreateSimpleClipRegion( return Some(clipId); } +static void FillPolygonDataForDisplayItem( + const nsDisplayMasksAndClipPaths& aDisplayItem, + nsTArray& aPoints, wr::FillRule& aFillRule) { + nsIFrame* frame = aDisplayItem.Frame(); + const auto* style = frame->StyleSVGReset(); + bool isPolygon = style->HasClipPath() && style->mClipPath.IsShape() && + style->mClipPath.AsShape()._0->IsPolygon(); + if (!isPolygon) { + return; + } + + const auto& clipPath = style->mClipPath; + const auto& shape = *clipPath.AsShape()._0; + const nsRect refBox = + nsLayoutUtils::ComputeGeometryBox(frame, clipPath.AsShape()._1); + + // We only fill polygon data for polygons that are below a complexity + // limit. + nsTArray vertices = + ShapeUtils::ComputePolygonVertices(shape, refBox); + if (vertices.Length() > wr::POLYGON_CLIP_VERTEX_MAX) { + return; + } + + auto appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel(); + + for (size_t i = 0; i < vertices.Length(); ++i) { + wr::LayoutPoint point = wr::ToLayoutPoint( + LayoutDevicePoint::FromAppUnits(vertices[i], appUnitsPerDevPixel)); + aPoints.AppendElement(point); + } + + aFillRule = (shape.AsPolygon().fill == StyleFillRule::Nonzero) + ? wr::FillRule::Nonzero + : wr::FillRule::Evenodd; +} + static Maybe CreateWRClipPathAndMasks( nsDisplayMasksAndClipPaths* aDisplayItem, const LayoutDeviceRect& aBounds, wr::IpcResourceUpdateQueue& aResources, wr::DisplayListBuilder& aBuilder, @@ -9529,7 +9566,14 @@ static Maybe CreateWRClipPathAndMasks( return Nothing(); } - wr::WrClipId clipId = aBuilder.DefineImageMaskClip(mask.ref()); + // We couldn't create a simple clip region, but before we create an image + // mask clip, see if we can get a polygon clip to add to it. + nsTArray points; + wr::FillRule fillRule = wr::FillRule::Nonzero; + FillPolygonDataForDisplayItem(*aDisplayItem, points, fillRule); + + wr::WrClipId clipId = + aBuilder.DefineImageMaskClip(mask.ref(), points, fillRule); return Some(clipId); }