From a4046ec4586141e5978e8bbcf2acc1be6105fbfd Mon Sep 17 00:00:00 2001 From: Ciure Andrei Date: Fri, 13 Sep 2019 19:26:50 +0300 Subject: [PATCH] Backed out 6 changesets (bug 1574493) for causing nested-sticky-2.html to perma fail CLOSED TREE Backed out changeset 358746636448 (bug 1574493) Backed out changeset 34aef5498237 (bug 1574493) Backed out changeset 1f88e2031c76 (bug 1574493) Backed out changeset 07c588b5ea10 (bug 1574493) Backed out changeset 0685e8d3510e (bug 1574493) Backed out changeset 15d4390220c4 (bug 1574493) --- gfx/layers/apz/test/reftest/reftest.list | 12 +- gfx/layers/wr/AsyncImagePipelineManager.cpp | 9 +- gfx/layers/wr/ClipManager.cpp | 8 +- gfx/layers/wr/WebRenderCommandBuilder.cpp | 6 +- gfx/layers/wr/WebRenderLayerManager.cpp | 2 +- gfx/layers/wr/WebRenderUserData.cpp | 2 +- gfx/tests/reftest/reftest.list | 2 +- gfx/webrender_bindings/WebRenderAPI.cpp | 19 +- gfx/webrender_bindings/WebRenderAPI.h | 11 +- gfx/webrender_bindings/src/bindings.rs | 46 +- gfx/wr/examples/blob.rs | 4 + gfx/wr/examples/frame_output.rs | 2 + gfx/wr/examples/image_resize.rs | 4 + gfx/wr/examples/texture_cache_stress.rs | 6 + gfx/wr/webrender/res/brush.glsl | 4 +- gfx/wr/webrender/res/clip_shared.glsl | 18 +- gfx/wr/webrender/res/cs_clip_box_shadow.glsl | 1 + gfx/wr/webrender/res/cs_clip_image.glsl | 1 + gfx/wr/webrender/res/cs_clip_rectangle.glsl | 1 + gfx/wr/webrender/res/prim_shared.glsl | 21 +- gfx/wr/webrender/res/snap.glsl | 22 + gfx/wr/webrender/src/batch.rs | 43 +- gfx/wr/webrender/src/box_shadow.rs | 11 +- gfx/wr/webrender/src/clip.rs | 4 +- gfx/wr/webrender/src/clip_scroll_tree.rs | 22 +- .../webrender/src/display_list_flattener.rs | 207 +------- gfx/wr/webrender/src/frame_builder.rs | 3 +- gfx/wr/webrender/src/gpu_types.rs | 31 ++ gfx/wr/webrender/src/picture.rs | 130 ++--- gfx/wr/webrender/src/prim_store/mod.rs | 494 +++++++++++++----- gfx/wr/webrender/src/render_backend.rs | 10 - gfx/wr/webrender/src/render_target.rs | 1 + gfx/wr/webrender/src/render_task.rs | 5 +- gfx/wr/webrender/src/renderer.rs | 5 + gfx/wr/webrender/src/spatial_node.rs | 87 +-- gfx/wr/webrender/src/util.rs | 63 --- gfx/wr/webrender_api/src/display_item.rs | 25 +- gfx/wr/webrender_api/src/display_list.rs | 25 +- .../reftests/border/degenerate-curve.png | Bin 20581 -> 21390 bytes .../reftests/boxshadow/inset-mask-region.png | Bin 23384 -> 24531 bytes .../wrench/reftests/boxshadow/inset-subpx.png | Bin 1810 -> 1258 bytes gfx/wr/wrench/reftests/boxshadow/scale.png | Bin 13527 -> 13536 bytes .../clip/clip-45-degree-rotation-ref.png | Bin 4228 -> 4314 bytes gfx/wr/wrench/reftests/clip/reftest.list | 4 +- ...tion-with-other-coordinate-system-clip.png | Bin 763 -> 778 bytes .../filters/backdrop-filter-perspective.png | Bin 60307 -> 60137 bytes .../filters/filter-drop-shadow-clip.png | Bin 11200 -> 11151 bytes .../reftests/performance/no-clip-mask.yaml | 1 - .../reftests/transforms/near-plane-clip.yaml | 1 - .../transforms/nested-preserve-3d.png | Bin 3830 -> 3830 bytes .../reftests/transforms/nested-rotate-x.png | Bin 3832 -> 3832 bytes .../transforms/perspective-clip-1.png | Bin 2016 -> 2024 bytes .../transforms/perspective-shadow.png | Bin 10536 -> 10583 bytes .../wrench/reftests/transforms/reftest.list | 2 +- gfx/wr/wrench/src/rawtest.rs | 36 +- gfx/wr/wrench/src/yaml_frame_reader.rs | 37 +- gfx/wr/wrench/src/yaml_frame_writer.rs | 23 - layout/base/nsLayoutUtils.cpp | 49 +- layout/forms/nsButtonFrameRenderer.cpp | 4 +- layout/forms/nsFieldSetFrame.cpp | 4 +- layout/generic/TextDrawTarget.h | 13 +- layout/generic/nsBulletFrame.cpp | 3 +- layout/generic/nsCanvasFrame.cpp | 4 +- layout/generic/nsFrame.cpp | 7 +- layout/generic/nsHTMLCanvasFrame.cpp | 2 +- layout/generic/nsImageFrame.cpp | 8 +- layout/generic/nsSubDocumentFrame.cpp | 4 +- layout/painting/nsCSSRenderingBorders.cpp | 6 +- layout/painting/nsDisplayList.cpp | 38 +- layout/painting/nsImageRenderer.cpp | 75 +-- layout/reftests/async-scrolling/reftest.list | 38 +- layout/reftests/border-image/reftest.list | 6 +- layout/reftests/box-shadow/reftest.list | 4 +- layout/reftests/bugs/reftest.list | 7 +- layout/reftests/css-blending/reftest.list | 2 +- layout/reftests/css-break/reftest.list | 2 +- layout/reftests/mathml/reftest.list | 2 +- layout/reftests/position-sticky/reftest.list | 6 +- layout/reftests/writing-mode/reftest.list | 6 +- layout/tables/nsTableFrame.cpp | 21 +- layout/xul/nsImageBoxFrame.cpp | 8 +- ...ent-and-blended-with-3D-transform.html.ini | 2 - ...end-mode-parent-with-3D-transform.html.ini | 3 - widget/cocoa/nsNativeThemeCocoa.mm | 4 +- widget/gtk/nsNativeThemeGTK.cpp | 5 +- 85 files changed, 846 insertions(+), 958 deletions(-) create mode 100644 gfx/wr/webrender/res/snap.glsl delete mode 100644 testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini diff --git a/gfx/layers/apz/test/reftest/reftest.list b/gfx/layers/apz/test/reftest/reftest.list index 310ac350689d..7ac8461f77be 100644 --- a/gfx/layers/apz/test/reftest/reftest.list +++ b/gfx/layers/apz/test/reftest/reftest.list @@ -1,11 +1,11 @@ # The following tests test the async positioning of the scrollbars. # Basic root-frame scrollbar with async scrolling -fuzzy-if(Android,0-1,0-2) fuzzy-if(webrender&>kWidget,14-14,24-24) fuzzy-if(webrender&&cocoaWidget,23-23,44-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html -fuzzy-if(Android,0-4,0-5) fuzzy-if(webrender&>kWidget,53-53,14-14) fuzzy-if(webrender&&cocoaWidget,22-22,44-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html -fuzzy-if(Android,0-6,0-6) fuzzy-if(webrender&>kWidget,15-15,38-38) fuzzy-if(webrender&&cocoaWidget,18-18,79-79) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html -fuzzy-if(Android,0-1,0-2) fuzzy-if(webrender&>kWidget,14-14,24-24) fuzzy-if(webrender&&cocoaWidget,23-23,44-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html -fuzzy-if(Android,0-14,0-5) fuzzy-if(webrender&>kWidget,53-53,14-14) fuzzy-if(webrender&&cocoaWidget,22-22,44-44) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html -fuzzy-if(Android,0-8,0-8) fuzzy-if(webrender&>kWidget,39-39,38-38) fuzzy-if(webrender&&cocoaWidget,18-18,43-43) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html +fuzzy-if(Android,0-1,0-2) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html +fuzzy-if(Android,0-4,0-5) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html +fuzzy-if(Android,0-3,0-5) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html +fuzzy-if(Android,0-1,0-2) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html +fuzzy-if(Android,0-4,0-5) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html +fuzzy-if(Android,0-3,0-7) skip-if(!asyncPan) pref(apz.allow_zooming,true) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html # Different async zoom levels. Since the scrollthumb gets async-scaled in the # compositor, the border-radius ends of the scrollthumb are going to be a little diff --git a/gfx/layers/wr/AsyncImagePipelineManager.cpp b/gfx/layers/wr/AsyncImagePipelineManager.cpp index 0d5062a5ea7b..e7d256959ef1 100644 --- a/gfx/layers/wr/AsyncImagePipelineManager.cpp +++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp @@ -381,7 +381,7 @@ void AsyncImagePipelineManager::ApplyAsyncImageForPipeline( params.mix_blend_mode = aPipeline->mMixBlendMode; Maybe referenceFrameId = builder.PushStackingContext( - params, wr::ToLayoutRect(aPipeline->mScBounds), + params, wr::ToRoundedLayoutRect(aPipeline->mScBounds), // This is fine to do unconditionally because we only push images here. wr::RasterSpace::Screen()); @@ -402,13 +402,14 @@ void AsyncImagePipelineManager::ApplyAsyncImageForPipeline( MOZ_ASSERT(aPipeline->mCurrentTexture->AsWebRenderTextureHost()); Range range_keys(&keys[0], keys.Length()); aPipeline->mCurrentTexture->PushDisplayItems( - builder, wr::ToLayoutRect(rect), wr::ToLayoutRect(rect), + builder, wr::ToRoundedLayoutRect(rect), wr::ToRoundedLayoutRect(rect), aPipeline->mFilter, range_keys); HoldExternalImage(aPipelineId, aEpoch, aPipeline->mCurrentTexture); } else { MOZ_ASSERT(keys.Length() == 1); - builder.PushImage(wr::ToLayoutRect(rect), wr::ToLayoutRect(rect), true, - aPipeline->mFilter, keys[0]); + builder.PushImage(wr::ToRoundedLayoutRect(rect), + wr::ToRoundedLayoutRect(rect), true, aPipeline->mFilter, + keys[0]); } } diff --git a/gfx/layers/wr/ClipManager.cpp b/gfx/layers/wr/ClipManager.cpp index 8f227831208b..2d5a5f421157 100644 --- a/gfx/layers/wr/ClipManager.cpp +++ b/gfx/layers/wr/ClipManager.cpp @@ -304,8 +304,8 @@ Maybe ClipManager::DefineScrollLayers( LayoutDevicePoint scrollOffset = metrics.GetScrollOffset() * metrics.GetDevPixelsPerCSSPixel(); return Some(mBuilder->DefineScrollLayer( - viewId, parent, wr::ToLayoutRect(contentRect), - wr::ToLayoutRect(clipBounds), wr::ToLayoutPoint(scrollOffset))); + viewId, parent, wr::ToRoundedLayoutRect(contentRect), + wr::ToRoundedLayoutRect(clipBounds), wr::ToLayoutPoint(scrollOffset))); } Maybe ClipManager::DefineClipChain( @@ -342,7 +342,7 @@ Maybe ClipManager::DefineClipChain( // Define the clip spaceAndClip->space = SpatialIdAfterOverride(spaceAndClip->space); wr::WrClipId clipId = mBuilder->DefineClip( - spaceAndClip, wr::ToLayoutRect(clip), &wrRoundedRects); + spaceAndClip, wr::ToRoundedLayoutRect(clip), &wrRoundedRects); clipIds.AppendElement(clipId); cache[chain] = clipId; CLIP_LOG("cache[%p] <= %zu\n", chain, clipId.id); @@ -373,7 +373,7 @@ void ClipManager::ItemClips::UpdateSeparateLeaf( Maybe clipLeaf; if (mSeparateLeaf) { MOZ_ASSERT(mChain); - clipLeaf.emplace(wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits( + clipLeaf.emplace(wr::ToRoundedLayoutRect(LayoutDeviceRect::FromAppUnits( mChain->mClip.GetClipRect(), aAppUnitsPerDevPixel))); } diff --git a/gfx/layers/wr/WebRenderCommandBuilder.cpp b/gfx/layers/wr/WebRenderCommandBuilder.cpp index 9f13af4e229f..0b505d01d1ab 100644 --- a/gfx/layers/wr/WebRenderCommandBuilder.cpp +++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp @@ -1927,8 +1927,8 @@ bool WebRenderCommandBuilder::PushImage( return false; } - auto r = wr::ToLayoutRect(aRect); - auto c = wr::ToLayoutRect(aClip); + auto r = wr::ToRoundedLayoutRect(aRect); + auto c = wr::ToRoundedLayoutRect(aClip); aBuilder.PushImage(r, c, !aItem->BackfaceIsHidden(), rendering, key.value()); return true; @@ -2563,7 +2563,7 @@ bool WebRenderCommandBuilder::PushItemAsImage( return false; } - wr::LayoutRect dest = wr::ToLayoutRect(imageRect); + wr::LayoutRect dest = wr::ToRoundedLayoutRect(imageRect); gfx::SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()); aBuilder.PushImage(dest, dest, !aItem->BackfaceIsHidden(), diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index a519bb214880..fc135e7b4269 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -315,7 +315,7 @@ void WebRenderLayerManager::EndTransactionWithoutLayer( renderRoot == wr::RenderRoot::Default ? LayoutDeviceSize(size) : LayoutDeviceSize()); - wrRects[renderRoot] = wr::ToLayoutRect(rects[renderRoot]); + wrRects[renderRoot] = wr::ToRoundedLayoutRect(rects[renderRoot]); } wr::DisplayListBuilder builder( diff --git a/gfx/layers/wr/WebRenderUserData.cpp b/gfx/layers/wr/WebRenderUserData.cpp index 34ef0edefd21..11b20b9075e1 100644 --- a/gfx/layers/wr/WebRenderUserData.cpp +++ b/gfx/layers/wr/WebRenderUserData.cpp @@ -263,7 +263,7 @@ void WebRenderImageData::CreateAsyncImageWebRenderCommands( // context need to be done manually and pushed over to the parent side, // where it will be done when we build the display list for the iframe. // That happens in AsyncImagePipelineManager. - wr::LayoutRect r = wr::ToLayoutRect(aBounds); + wr::LayoutRect r = wr::ToRoundedLayoutRect(aBounds); aBuilder.PushIFrame(r, aIsBackfaceVisible, mPipelineId.ref(), /*ignoreMissingPipelines*/ false); diff --git a/gfx/tests/reftest/reftest.list b/gfx/tests/reftest/reftest.list index a4bb5778eedb..735af7011e21 100644 --- a/gfx/tests/reftest/reftest.list +++ b/gfx/tests/reftest/reftest.list @@ -14,7 +14,7 @@ fuzzy(0-100,0-30) == 1149923.html 1149923-ref.html # use fuzzy due to few distor == 1444904.html 1444904-ref.html == 1451168.html 1451168-ref.html == 1461313.html 1461313-ref.html -fuzzy(5-32,21908-26621) fuzzy-if(webrender,5-5,868-1039) == 1463802.html 1463802-ref.html +fuzzy(5-32,21908-26621) fuzzy-if(webrender,0-9,0-100) == 1463802.html 1463802-ref.html fuzzy(0-11,0-4) == 1474722.html 1474722-ref.html == 1501195.html 1501195-ref.html == 1519754.html 1519754-ref.html diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index 19651a9bdbbc..95f907e429e3 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -1091,15 +1091,14 @@ void DisplayListBuilder::PushImage( const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, bool aIsBackfaceVisible, wr::ImageRendering aFilter, wr::ImageKey aImage, bool aPremultipliedAlpha, const wr::ColorF& aColor) { - wr::LayoutRect clip = MergeClipLeaf(aClip); - WRDL_LOG("PushImage b=%s cl=%s\n", mWrState, Stringify(aBounds).c_str(), - Stringify(clip).c_str()); - wr_dp_push_image(mWrState, aBounds, clip, aIsBackfaceVisible, - &mCurrentSpaceAndClipChain, aFilter, aImage, - aPremultipliedAlpha, aColor); + wr::LayoutSize size; + size.width = aBounds.size.width; + size.height = aBounds.size.height; + PushImage(aBounds, aClip, aIsBackfaceVisible, size, size, aFilter, aImage, + aPremultipliedAlpha, aColor); } -void DisplayListBuilder::PushRepeatingImage( +void DisplayListBuilder::PushImage( const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize, const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter, @@ -1108,9 +1107,9 @@ void DisplayListBuilder::PushRepeatingImage( WRDL_LOG("PushImage b=%s cl=%s s=%s t=%s\n", mWrState, Stringify(aBounds).c_str(), Stringify(clip).c_str(), Stringify(aStretchSize).c_str(), Stringify(aTileSpacing).c_str()); - wr_dp_push_repeating_image( - mWrState, aBounds, clip, aIsBackfaceVisible, &mCurrentSpaceAndClipChain, - aStretchSize, aTileSpacing, aFilter, aImage, aPremultipliedAlpha, aColor); + wr_dp_push_image(mWrState, aBounds, clip, aIsBackfaceVisible, + &mCurrentSpaceAndClipChain, aStretchSize, aTileSpacing, + aFilter, aImage, aPremultipliedAlpha, aColor); } void DisplayListBuilder::PushYCbCrPlanarImage( diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index e32cac082767..1a67f61677d6 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -479,12 +479,11 @@ class DisplayListBuilder final { wr::ImageKey aImage, bool aPremultipliedAlpha = true, const wr::ColorF& aColor = wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}); - void PushRepeatingImage( - const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, - bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize, - const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter, - wr::ImageKey aImage, bool aPremultipliedAlpha = true, - const wr::ColorF& aColor = wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}); + void PushImage(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, + bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize, + const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter, + wr::ImageKey aImage, bool aPremultipliedAlpha = true, + const wr::ColorF& aColor = wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}); void PushYCbCrPlanarImage( const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index b0d078d91f0d..396e42edd922 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -2570,6 +2570,8 @@ pub extern "C" fn wr_dp_push_image(state: &mut WrState, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, + stretch_size: LayoutSize, + tile_spacing: LayoutSize, image_rendering: ImageRendering, key: WrImageKey, premultiplied_alpha: bool, @@ -2596,54 +2598,14 @@ pub extern "C" fn wr_dp_push_image(state: &mut WrState, .dl_builder .push_image(&prim_info, bounds, + stretch_size, + tile_spacing, image_rendering, alpha_type, key, color); } -#[no_mangle] -pub extern "C" fn wr_dp_push_repeating_image(state: &mut WrState, - bounds: LayoutRect, - clip: LayoutRect, - is_backface_visible: bool, - parent: &WrSpaceAndClipChain, - stretch_size: LayoutSize, - tile_spacing: LayoutSize, - image_rendering: ImageRendering, - key: WrImageKey, - premultiplied_alpha: bool, - color: ColorF) { - debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() }); - - let space_and_clip = parent.to_webrender(state.pipeline_id); - - let prim_info = CommonItemProperties { - clip_rect: clip, - clip_id: space_and_clip.clip_id, - spatial_id: space_and_clip.spatial_id, - is_backface_visible, - hit_info: state.current_tag, - }; - - let alpha_type = if premultiplied_alpha { - AlphaType::PremultipliedAlpha - } else { - AlphaType::Alpha - }; - - state.frame_builder - .dl_builder - .push_repeating_image(&prim_info, - bounds, - stretch_size, - tile_spacing, - image_rendering, - alpha_type, - key, - color); -} - /// Push a 3 planar yuv image. #[no_mangle] pub extern "C" fn wr_dp_push_yuv_planar_image(state: &mut WrState, diff --git a/gfx/wr/examples/blob.rs b/gfx/wr/examples/blob.rs index 470e9587c415..01cc48cdebed 100644 --- a/gfx/wr/examples/blob.rs +++ b/gfx/wr/examples/blob.rs @@ -236,6 +236,8 @@ impl Example for App { builder.push_image( &CommonItemProperties::new(bounds, space_and_clip), bounds, + LayoutSize::new(500.0, 500.0), + LayoutSize::new(0.0, 0.0), api::ImageRendering::Auto, api::AlphaType::PremultipliedAlpha, blob_img1.as_image(), @@ -246,6 +248,8 @@ impl Example for App { builder.push_image( &CommonItemProperties::new(bounds, space_and_clip), bounds, + LayoutSize::new(200.0, 200.0), + LayoutSize::new(0.0, 0.0), api::ImageRendering::Auto, api::AlphaType::PremultipliedAlpha, blob_img2.as_image(), diff --git a/gfx/wr/examples/frame_output.rs b/gfx/wr/examples/frame_output.rs index c3e1e190b681..7bdf3e17ddc1 100644 --- a/gfx/wr/examples/frame_output.rs +++ b/gfx/wr/examples/frame_output.rs @@ -170,6 +170,8 @@ impl Example for App { builder.push_image( &CommonItemProperties::new(bounds, space_and_clip), bounds, + bounds.size, + LayoutSize::zero(), ImageRendering::Auto, AlphaType::PremultipliedAlpha, self.external_image_key.unwrap(), diff --git a/gfx/wr/examples/image_resize.rs b/gfx/wr/examples/image_resize.rs index e71e9bc2aa86..23b7e538f572 100644 --- a/gfx/wr/examples/image_resize.rs +++ b/gfx/wr/examples/image_resize.rs @@ -55,6 +55,8 @@ impl Example for App { space_and_clip, ), bounds, + image_size, + LayoutSize::zero(), ImageRendering::Auto, AlphaType::PremultipliedAlpha, self.image_key, @@ -67,6 +69,8 @@ impl Example for App { space_and_clip, ), bounds, + image_size, + LayoutSize::zero(), ImageRendering::Pixelated, AlphaType::PremultipliedAlpha, self.image_key, diff --git a/gfx/wr/examples/texture_cache_stress.rs b/gfx/wr/examples/texture_cache_stress.rs index 1fed7793457e..f2bde6294b2a 100644 --- a/gfx/wr/examples/texture_cache_stress.rs +++ b/gfx/wr/examples/texture_cache_stress.rs @@ -147,6 +147,8 @@ impl Example for App { builder.push_image( &info, bounds, + image_size, + LayoutSize::zero(), ImageRendering::Auto, AlphaType::PremultipliedAlpha, *key, @@ -163,6 +165,8 @@ impl Example for App { builder.push_image( &info, bounds, + image_size, + LayoutSize::zero(), ImageRendering::Auto, AlphaType::PremultipliedAlpha, image_key, @@ -179,6 +183,8 @@ impl Example for App { builder.push_image( &info, bounds, + image_size, + LayoutSize::zero(), ImageRendering::Auto, AlphaType::PremultipliedAlpha, swap_key, diff --git a/gfx/wr/webrender/res/brush.glsl b/gfx/wr/webrender/res/brush.glsl index 83c777b8dbaf..eacbac000e94 100644 --- a/gfx/wr/webrender/res/brush.glsl +++ b/gfx/wr/webrender/res/brush.glsl @@ -70,7 +70,9 @@ void main(void) { ph.local_clip_rect, ph.z, transform, - pic_task + pic_task, + ph.local_rect, + ph.snap_offsets ); // TODO(gw): transform bounds may be referenced by diff --git a/gfx/wr/webrender/res/clip_shared.glsl b/gfx/wr/webrender/res/clip_shared.glsl index a6a7d2dd50a1..030532776505 100644 --- a/gfx/wr/webrender/res/clip_shared.glsl +++ b/gfx/wr/webrender/res/clip_shared.glsl @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include rect,render_task,gpu_cache,transform +#include rect,render_task,gpu_cache,snap,transform #ifdef WR_VERTEX_SHADER @@ -11,6 +11,7 @@ in ivec4 aClipDataResourceAddress; in vec2 aClipLocalPos; in vec4 aClipTileRect; in vec4 aClipDeviceArea; +in vec4 aClipSnapOffsets; in vec4 aClipOrigins; in float aDevicePixelScale; @@ -22,6 +23,7 @@ struct ClipMaskInstance { vec2 local_pos; RectWithSize tile_rect; RectWithSize sub_rect; + vec4 snap_offsets; vec2 task_origin; vec2 screen_origin; float device_pixel_scale; @@ -37,6 +39,7 @@ ClipMaskInstance fetch_clip_item() { cmi.local_pos = aClipLocalPos; cmi.tile_rect = RectWithSize(aClipTileRect.xy, aClipTileRect.zw); cmi.sub_rect = RectWithSize(aClipDeviceArea.xy, aClipDeviceArea.zw); + cmi.snap_offsets = aClipSnapOffsets; cmi.task_origin = aClipOrigins.xy; cmi.screen_origin = aClipOrigins.zw; cmi.device_pixel_scale = aDevicePixelScale; @@ -61,10 +64,23 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect, Transform prim_transform, Transform clip_transform, RectWithSize sub_rect, + vec4 snap_offsets, vec2 task_origin, vec2 screen_origin, float device_pixel_scale) { vec2 device_pos = screen_origin + sub_rect.p0 + aPosition.xy * sub_rect.size; + + // If the primitive we are drawing a clip mask for was snapped, then + // remove the effect of that snapping, so that the local position + // interpolation below works correctly relative to the clip item. + vec2 snap_offset = mix( + snap_offsets.xy, + snap_offsets.zw, + aPosition.xy + ); + + device_pos -= snap_offset; + vec2 world_pos = device_pos / device_pixel_scale; vec4 pos = prim_transform.m * vec4(world_pos, 0.0, 1.0); diff --git a/gfx/wr/webrender/res/cs_clip_box_shadow.glsl b/gfx/wr/webrender/res/cs_clip_box_shadow.glsl index 5b4937139ef7..1dac991f21aa 100644 --- a/gfx/wr/webrender/res/cs_clip_box_shadow.glsl +++ b/gfx/wr/webrender/res/cs_clip_box_shadow.glsl @@ -52,6 +52,7 @@ void main(void) { prim_transform, clip_transform, cmi.sub_rect, + cmi.snap_offsets, cmi.task_origin, cmi.screen_origin, cmi.device_pixel_scale diff --git a/gfx/wr/webrender/res/cs_clip_image.glsl b/gfx/wr/webrender/res/cs_clip_image.glsl index 918223343d2d..9005fd7d507a 100644 --- a/gfx/wr/webrender/res/cs_clip_image.glsl +++ b/gfx/wr/webrender/res/cs_clip_image.glsl @@ -35,6 +35,7 @@ void main(void) { prim_transform, clip_transform, cmi.sub_rect, + cmi.snap_offsets, cmi.task_origin, cmi.screen_origin, cmi.device_pixel_scale diff --git a/gfx/wr/webrender/res/cs_clip_rectangle.glsl b/gfx/wr/webrender/res/cs_clip_rectangle.glsl index 3fcdd7ef04a3..85522e542a4c 100644 --- a/gfx/wr/webrender/res/cs_clip_rectangle.glsl +++ b/gfx/wr/webrender/res/cs_clip_rectangle.glsl @@ -77,6 +77,7 @@ void main(void) { prim_transform, clip_transform, cmi.sub_rect, + cmi.snap_offsets, cmi.task_origin, cmi.screen_origin, cmi.device_pixel_scale diff --git a/gfx/wr/webrender/res/prim_shared.glsl b/gfx/wr/webrender/res/prim_shared.glsl index cb52464b135b..12f6c12485a5 100644 --- a/gfx/wr/webrender/res/prim_shared.glsl +++ b/gfx/wr/webrender/res/prim_shared.glsl @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include rect,render_task,gpu_cache,transform +#include rect,render_task,gpu_cache,snap,transform #define EXTEND_MODE_CLAMP 0 #define EXTEND_MODE_REPEAT 1 @@ -47,12 +47,13 @@ uniform HIGHP_SAMPLER_FLOAT isampler2D sPrimitiveHeadersI; // Instanced attributes in ivec4 aData; -#define VECS_PER_PRIM_HEADER_F 2U +#define VECS_PER_PRIM_HEADER_F 3U #define VECS_PER_PRIM_HEADER_I 2U struct PrimitiveHeader { RectWithSize local_rect; RectWithSize local_clip_rect; + vec4 snap_offsets; float z; int specific_prim_address; int transform_id; @@ -65,6 +66,7 @@ PrimitiveHeader fetch_prim_header(int index) { ivec2 uv_f = get_fetch_uv(index, VECS_PER_PRIM_HEADER_F); vec4 local_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(0, 0)); vec4 local_clip_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(1, 0)); + ph.snap_offsets = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(2, 0)); ph.local_rect = RectWithSize(local_rect.xy, local_rect.zw); ph.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw); @@ -89,7 +91,9 @@ VertexInfo write_vertex(RectWithSize instance_rect, RectWithSize local_clip_rect, float z, Transform transform, - PictureTask task) { + PictureTask task, + RectWithSize snap_rect, + vec4 snap_offsets) { // Select the corner of the local rect that we are processing. vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy; @@ -97,6 +101,13 @@ VertexInfo write_vertex(RectWithSize instance_rect, // Clamp to the two local clip rects. vec2 clamped_local_pos = clamp_rect(local_pos, local_clip_rect); + /// Compute the snapping offset. + vec2 snap_offset = compute_snap_offset( + clamped_local_pos, + snap_rect, + snap_offsets + ); + // Transform the current vertex to world space. vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0); @@ -104,13 +115,13 @@ VertexInfo write_vertex(RectWithSize instance_rect, vec2 device_pos = world_pos.xy * task.device_pixel_scale; // Apply offsets for the render task to get correct screen location. - vec2 final_offset = -task.content_origin + task.common_data.task_rect.p0; + vec2 final_offset = snap_offset - task.content_origin + task.common_data.task_rect.p0; gl_Position = uTransform * vec4(device_pos + final_offset * world_pos.w, z * world_pos.w, world_pos.w); VertexInfo vi = VertexInfo( clamped_local_pos, - vec2(0.0, 0.0), + snap_offset, world_pos ); diff --git a/gfx/wr/webrender/res/snap.glsl b/gfx/wr/webrender/res/snap.glsl new file mode 100644 index 000000000000..1f86e199fbf6 --- /dev/null +++ b/gfx/wr/webrender/res/snap.glsl @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef WR_VERTEX_SHADER + +/// Given a point within a local rectangle, and the device space corners +/// offsets for the unsnapped primitive, return the snap offsets. This *must* +/// exactly match the logic in the Rust compute_snap_offset_impl function. +vec2 compute_snap_offset( + vec2 reference_pos, + RectWithSize reference_rect, + vec4 snap_positions +) { + /// Compute the position of this vertex inside the snap rectangle. + vec2 normalized_snap_pos = (reference_pos - reference_rect.p0) / reference_rect.size; + + /// Compute the actual world offset for this vertex needed to make it snap. + return mix(snap_positions.xy, snap_positions.zw, normalized_snap_pos); +} + +#endif //WR_VERTEX_SHADER diff --git a/gfx/wr/webrender/src/batch.rs b/gfx/wr/webrender/src/batch.rs index 90141c11506f..109e0bb2e2cb 100644 --- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -10,7 +10,7 @@ use crate::clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNo use crate::glyph_rasterizer::GlyphFormat; use crate::gpu_cache::{GpuBlockData, GpuCache, GpuCacheHandle, GpuCacheAddress}; use crate::gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, ZBufferIdGenerator}; -use crate::gpu_types::{ClipMaskInstance, SplitCompositeInstance}; +use crate::gpu_types::{ClipMaskInstance, SplitCompositeInstance, SnapOffsets}; use crate::gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance}; use crate::gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette}; use crate::internal_types::{FastHashMap, SavedTargetIndex, Swizzle, TextureSource, Filter}; @@ -18,6 +18,7 @@ use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, T use crate::prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex, PrimitiveVisibilityMask}; use crate::prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex}; use crate::prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, VECS_PER_SEGMENT}; +use crate::prim_store::{recompute_snap_offsets}; use crate::prim_store::image::ImageSource; use crate::render_backend::DataStores; use crate::render_target::RenderTargetContext; @@ -707,7 +708,7 @@ impl BatchBuilder { let prim_common_data = &ctx.data_stores.as_common_data(&prim_instance); let prim_rect = LayoutRect::new( prim_instance.prim_origin, - prim_common_data.prim_size + prim_common_data.prim_size, ); let mut batch_features = BatchFeatures::empty(); @@ -719,6 +720,7 @@ impl BatchBuilder { batch_features |= BatchFeatures::ANTIALIASING; } + let snap_offsets = prim_info.snap_offsets; let prim_vis_mask = prim_info.visibility_mask; let clip_task_address = ctx.get_prim_clip_task_address( prim_info.clip_task_index, @@ -749,6 +751,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -815,6 +818,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -866,6 +870,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -1035,6 +1040,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -1071,8 +1077,9 @@ impl BatchBuilder { let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle); let prim_header = PrimitiveHeader { - local_rect: picture.local_rect, + local_rect: picture.snapped_local_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -1097,8 +1104,9 @@ impl BatchBuilder { ); let prim_header = PrimitiveHeader { - local_rect: pic.local_rect, + local_rect: pic.snapped_local_rect, local_clip_rect: child_prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: GpuCacheAddress::INVALID, transform_id: transforms .get_id( @@ -1217,6 +1225,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: local_tile_rect, local_clip_rect: local_tile_clip_rect, + snap_offsets: SnapOffsets::empty(), specific_prim_address: prim_cache_address, transform_id, }; @@ -1286,6 +1295,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: local_tile_rect, local_clip_rect: local_tile_clip_rect, + snap_offsets: SnapOffsets::empty(), specific_prim_address: prim_cache_address, transform_id, }; @@ -1402,6 +1412,7 @@ impl BatchBuilder { let shadow_prim_header = PrimitiveHeader { local_rect: shadow_rect, + snap_offsets: prim_info.shadow_snap_offsets, specific_prim_address: shadow_prim_address, ..prim_header }; @@ -1694,8 +1705,9 @@ impl BatchBuilder { }; let prim_header = PrimitiveHeader { - local_rect: picture.local_rect, + local_rect: picture.snapped_local_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -1816,6 +1828,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -1890,6 +1903,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -1999,6 +2013,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -2104,6 +2119,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: prim_cache_address, transform_id, }; @@ -2152,6 +2168,7 @@ impl BatchBuilder { let prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: image_instance.tight_local_clip_rect, + snap_offsets, specific_prim_address: gpu_cache.get_address(&gpu_handle), transform_id, }; @@ -2195,6 +2212,7 @@ impl BatchBuilder { let mut prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: GpuCacheAddress::INVALID, transform_id, }; @@ -2322,6 +2340,7 @@ impl BatchBuilder { let mut prim_header = PrimitiveHeader { local_rect: prim_rect, local_clip_rect: prim_info.combined_local_clip_rect, + snap_offsets, specific_prim_address: GpuCacheAddress::INVALID, transform_id, }; @@ -2425,9 +2444,10 @@ impl BatchBuilder { let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle); let backdrop_picture = &ctx.prim_store.pictures[backdrop_pic_index.0]; let prim_header = PrimitiveHeader { - local_rect: backdrop_picture.local_rect, + local_rect: backdrop_picture.snapped_local_rect, local_clip_rect: prim_info.combined_local_clip_rect, transform_id, + snap_offsets: SnapOffsets::empty(), specific_prim_address: prim_cache_address, }; @@ -2648,10 +2668,18 @@ impl BatchBuilder { let user_data = [stops_handle.as_int(gpu_cache), 0, 0, 0]; for tile in visible_tiles { + // Adjust the snap offsets for the tile. + let snap_offsets = recompute_snap_offsets( + tile.local_rect, + base_prim_header.local_rect, + base_prim_header.snap_offsets, + ); + let prim_header = PrimitiveHeader { specific_prim_address: gpu_cache.get_address(&tile.handle), local_rect: tile.local_rect, local_clip_rect: tile.local_clip_rect, + snap_offsets, ..*base_prim_header }; let prim_header_index = prim_headers.push(&prim_header, z_id, user_data); @@ -2921,6 +2949,7 @@ impl ClipBatcher { local_pos, tile_rect: LayoutRect::zero(), sub_rect, + snap_offsets: SnapOffsets::empty(), task_origin, screen_origin, device_pixel_scale, @@ -3046,6 +3075,7 @@ impl ClipBatcher { actual_rect: DeviceIntRect, world_rect: &WorldRect, device_pixel_scale: DevicePixelScale, + snap_offsets: SnapOffsets, task_origin: DevicePoint, screen_origin: DevicePoint, ) { @@ -3078,6 +3108,7 @@ impl ClipBatcher { DevicePoint::zero(), actual_rect.size.to_f32(), ), + snap_offsets, task_origin, screen_origin, device_pixel_scale: device_pixel_scale.0, diff --git a/gfx/wr/webrender/src/box_shadow.rs b/gfx/wr/webrender/src/box_shadow.rs index 0ebf1a27298d..5dea6ceeefae 100644 --- a/gfx/wr/webrender/src/box_shadow.rs +++ b/gfx/wr/webrender/src/box_shadow.rs @@ -98,13 +98,10 @@ impl<'a> DisplayListFlattener<'a> { // Apply parameters that affect where the shadow rect // exists in the local space of the primitive. - let shadow_rect = self.snap_rect( - &prim_info - .rect - .translate(*box_offset) - .inflate(spread_amount, spread_amount), - clip_and_scroll.spatial_node_index, - ); + let shadow_rect = prim_info + .rect + .translate(*box_offset) + .inflate(spread_amount, spread_amount); // If blur radius is zero, we can use a fast path with // no blur applied. diff --git a/gfx/wr/webrender/src/clip.rs b/gfx/wr/webrender/src/clip.rs index 30a3d905b68e..3442fc89e0da 100644 --- a/gfx/wr/webrender/src/clip.rs +++ b/gfx/wr/webrender/src/clip.rs @@ -1002,9 +1002,9 @@ impl ClipItemKeyKind { } } - pub fn image_mask(image_mask: &ImageMask, mask_rect: LayoutRect) -> Self { + pub fn image_mask(image_mask: &ImageMask) -> Self { ClipItemKeyKind::ImageMask( - mask_rect.into(), + image_mask.rect.into(), image_mask.image, image_mask.repeat, ) diff --git a/gfx/wr/webrender/src/clip_scroll_tree.rs b/gfx/wr/webrender/src/clip_scroll_tree.rs index 3bc736262b63..7d48f9b282b1 100644 --- a/gfx/wr/webrender/src/clip_scroll_tree.rs +++ b/gfx/wr/webrender/src/clip_scroll_tree.rs @@ -441,7 +441,6 @@ impl ClipScrollTree { pub fn update_tree( &mut self, pan: WorldPoint, - global_device_pixel_scale: DevicePixelScale, scene_properties: &SceneProperties, ) { if self.spatial_nodes.is_empty() { @@ -472,7 +471,7 @@ impl ClipScrollTree { None => continue, }; - node.update(&mut state, &mut self.coord_systems, global_device_pixel_scale, scene_properties, &*previous); + node.update(&mut state, &mut self.coord_systems, scene_properties, &*previous); if !node.children.is_empty() { node.prepare_state_for_children(&mut state); @@ -571,16 +570,12 @@ impl ClipScrollTree { self.add_spatial_node(node) } - pub fn add_spatial_node(&mut self, mut node: SpatialNode) -> SpatialNodeIndex { + pub fn add_spatial_node(&mut self, node: SpatialNode) -> SpatialNodeIndex { let index = SpatialNodeIndex::new(self.spatial_nodes.len()); // When the parent node is None this means we are adding the root. if let Some(parent_index) = node.parent { - let parent_node = &mut self.spatial_nodes[parent_index.0 as usize]; - parent_node.add_child(index); - node.update_snapping(Some(parent_node)); - } else { - node.update_snapping(None); + self.spatial_nodes[parent_index.0 as usize].add_child(index); } self.spatial_nodes.push(node); @@ -645,15 +640,12 @@ impl ClipScrollTree { pt.new_level(format!("ReferenceFrame")); pt.add_item(format!("kind: {:?}", info.kind)); pt.add_item(format!("transform_style: {:?}", info.transform_style)); - pt.add_item(format!("source_transform: {:?}", info.source_transform)); - pt.add_item(format!("origin_in_parent_reference_frame: {:?}", info.origin_in_parent_reference_frame)); } } pt.add_item(format!("index: {:?}", index)); pt.add_item(format!("content_transform: {:?}", node.content_transform)); pt.add_item(format!("viewport_transform: {:?}", node.viewport_transform)); - pt.add_item(format!("snapping_transform: {:?}", node.snapping_transform)); pt.add_item(format!("coordinate_system_id: {:?}", node.coordinate_system_id)); for child_index in &node.children { @@ -765,7 +757,7 @@ fn test_cst_simple_translation() { LayoutVector2D::zero(), ); - cst.update_tree(WorldPoint::zero(), DevicePixelScale::new(1.0), &SceneProperties::new()); + cst.update_tree(WorldPoint::zero(), &SceneProperties::new()); test_pt(100.0, 100.0, &cst, child1, root, 200.0, 100.0); test_pt(100.0, 100.0, &cst, child2, root, 200.0, 150.0); @@ -807,7 +799,7 @@ fn test_cst_simple_scale() { LayoutVector2D::zero(), ); - cst.update_tree(WorldPoint::zero(), DevicePixelScale::new(1.0), &SceneProperties::new()); + cst.update_tree(WorldPoint::zero(), &SceneProperties::new()); test_pt(100.0, 100.0, &cst, child1, root, 400.0, 100.0); test_pt(100.0, 100.0, &cst, child2, root, 400.0, 200.0); @@ -857,7 +849,7 @@ fn test_cst_scale_translation() { LayoutVector2D::zero(), ); - cst.update_tree(WorldPoint::zero(), DevicePixelScale::new(1.0), &SceneProperties::new()); + cst.update_tree(WorldPoint::zero(), &SceneProperties::new()); test_pt(100.0, 100.0, &cst, child1, root, 200.0, 150.0); test_pt(100.0, 100.0, &cst, child2, root, 300.0, 450.0); @@ -891,7 +883,7 @@ fn test_cst_translation_rotate() { LayoutVector2D::zero(), ); - cst.update_tree(WorldPoint::zero(), DevicePixelScale::new(1.0), &SceneProperties::new()); + cst.update_tree(WorldPoint::zero(), &SceneProperties::new()); test_pt(100.0, 0.0, &cst, child1, root, 0.0, -100.0); } diff --git a/gfx/wr/webrender/src/display_list_flattener.rs b/gfx/wr/webrender/src/display_list_flattener.rs index e16a98ddbac5..dd3d36e421a2 100644 --- a/gfx/wr/webrender/src/display_list_flattener.rs +++ b/gfx/wr/webrender/src/display_list_flattener.rs @@ -27,7 +27,6 @@ use crate::prim_store::{PrimitiveInstanceKind, NinePatchDescriptor, PrimitiveSto use crate::prim_store::{ScrollNodeAndClipChain, PictureIndex}; use crate::prim_store::{InternablePrimitive, SegmentInstanceIndex}; use crate::prim_store::{register_prim_chase_id, get_line_decoration_sizes}; -use crate::prim_store::{SpaceSnapper}; use crate::prim_store::backdrop::Backdrop; use crate::prim_store::borders::{ImageBorder, NormalBorderPrim}; use crate::prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams}; @@ -339,13 +338,10 @@ impl<'a> DisplayListFlattener<'a> { found_explicit_tile_cache: false, }; - let device_pixel_scale = view.accumulated_scale_factor_for_snapping(); - flattener.push_root( root_pipeline_id, &root_pipeline.viewport_size, &root_pipeline.content_size, - device_pixel_scale, ); // In order to ensure we have a single root stacking context for the @@ -369,7 +365,6 @@ impl<'a> DisplayListFlattener<'a> { ClipChainId::NONE, RasterSpace::Screen, /* is_backdrop_root = */ true, - device_pixel_scale, ); flattener.flatten_items( @@ -940,7 +935,6 @@ impl<'a> DisplayListFlattener<'a> { clip_chain_id, stacking_context.raster_space, stacking_context.is_backdrop_root, - self.sc_stack.last().unwrap().snap_to_device.device_pixel_scale, ); if cfg!(debug_assertions) && apply_pipeline_clip && clip_chain_id != ClipChainId::NONE { @@ -998,18 +992,8 @@ impl<'a> DisplayListFlattener<'a> { ); self.pipeline_clip_chain_stack.push(clip_chain_index); - let snap_to_device = &mut self.sc_stack.last_mut().unwrap().snap_to_device; - snap_to_device.set_target_spatial_node( - spatial_node_index, - self.clip_scroll_tree, - ); - - let bounds = snap_to_device.snap_rect( - &info.bounds.translate(current_offset), - ); - - let content_size = snap_to_device.snap_size(&pipeline.content_size); - + let bounds = info.bounds; + let origin = current_offset + bounds.origin.to_vector(); let spatial_node_index = self.push_reference_frame( SpatialId::root_reference_frame(iframe_pipeline_id), Some(spatial_node_index), @@ -1017,7 +1001,7 @@ impl<'a> DisplayListFlattener<'a> { TransformStyle::Flat, PropertyBinding::Value(LayoutTransform::identity()), ReferenceFrameKind::Transform, - bounds.origin.to_vector(), + origin, ); let iframe_rect = LayoutRect::new(LayoutPoint::zero(), bounds.size); @@ -1027,7 +1011,7 @@ impl<'a> DisplayListFlattener<'a> { Some(ExternalScrollId(0, iframe_pipeline_id)), iframe_pipeline_id, &iframe_rect, - &content_size, + &pipeline.content_size, ScrollSensitivity::ScriptAndInputEvents, ScrollFrameKind::PipelineRoot, LayoutVector2D::zero(), @@ -1071,12 +1055,7 @@ impl<'a> DisplayListFlattener<'a> { common: &CommonItemProperties, apply_pipeline_clip: bool ) -> (LayoutPrimitiveInfo, ScrollNodeAndClipChain) { - let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds( - common, - &common.clip_rect, - apply_pipeline_clip, - ); - (layout, clip_and_scroll) + self.process_common_properties_with_bounds(common, &common.clip_rect, apply_pipeline_clip) } fn process_common_properties_with_bounds( @@ -1084,7 +1063,7 @@ impl<'a> DisplayListFlattener<'a> { common: &CommonItemProperties, bounds: &LayoutRect, apply_pipeline_clip: bool - ) -> (LayoutPrimitiveInfo, LayoutRect, ScrollNodeAndClipChain) { + ) -> (LayoutPrimitiveInfo, ScrollNodeAndClipChain) { let clip_and_scroll = self.get_clip_and_scroll( &common.clip_id, &common.spatial_id, @@ -1093,36 +1072,16 @@ impl<'a> DisplayListFlattener<'a> { let current_offset = self.current_offset(clip_and_scroll.spatial_node_index); - let snap_to_device = &mut self.sc_stack.last_mut().unwrap().snap_to_device; - snap_to_device.set_target_spatial_node( - clip_and_scroll.spatial_node_index, - self.clip_scroll_tree - ); - let clip_rect = common.clip_rect.translate(current_offset); let rect = bounds.translate(current_offset); - let layout = LayoutPrimitiveInfo { - rect: snap_to_device.snap_rect(&rect), - clip_rect: snap_to_device.snap_rect(&clip_rect), + rect, + clip_rect, is_backface_visible: common.is_backface_visible, hit_info: common.hit_info, }; - (layout, rect, clip_and_scroll) - } - - pub fn snap_rect( - &mut self, - rect: &LayoutRect, - target_spatial_node: SpatialNodeIndex, - ) -> LayoutRect { - let snap_to_device = &mut self.sc_stack.last_mut().unwrap().snap_to_device; - snap_to_device.set_target_spatial_node( - target_spatial_node, - self.clip_scroll_tree - ); - snap_to_device.snap_rect(rect) + (layout, clip_and_scroll) } fn flatten_item<'b>( @@ -1133,7 +1092,7 @@ impl<'a> DisplayListFlattener<'a> { ) -> Option> { match *item.item() { DisplayItem::Image(ref info) => { - let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.bounds, apply_pipeline_clip, @@ -1142,32 +1101,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_image( clip_and_scroll, &layout, - layout.rect.size, - LayoutSize::zero(), - None, - info.image_key, - info.image_rendering, - info.alpha_type, - info.color, - ); - } - DisplayItem::RepeatingImage(ref info) => { - let (layout, unsnapped_rect, clip_and_scroll) = self.process_common_properties_with_bounds( - &info.common, - &info.bounds, - apply_pipeline_clip, - ); - - let stretch_size = process_repeat_size( - &layout.rect, - &unsnapped_rect, info.stretch_size, - ); - - self.add_image( - clip_and_scroll, - &layout, - stretch_size, info.tile_spacing, None, info.image_key, @@ -1177,7 +1111,7 @@ impl<'a> DisplayListFlattener<'a> { ); } DisplayItem::YuvImage(ref info) => { - let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.bounds, apply_pipeline_clip, @@ -1194,7 +1128,7 @@ impl<'a> DisplayListFlattener<'a> { ); } DisplayItem::Text(ref info) => { - let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.bounds, apply_pipeline_clip, @@ -1245,7 +1179,7 @@ impl<'a> DisplayListFlattener<'a> { ); } DisplayItem::Line(ref info) => { - let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.area, apply_pipeline_clip, @@ -1261,25 +1195,19 @@ impl<'a> DisplayListFlattener<'a> { ); } DisplayItem::Gradient(ref info) => { - let (layout, unsnapped_rect, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.bounds, apply_pipeline_clip, ); - let tile_size = process_repeat_size( - &layout.rect, - &unsnapped_rect, - info.tile_size, - ); - if let Some(prim_key_kind) = self.create_linear_gradient_prim( &layout, info.gradient.start_point, info.gradient.end_point, item.gradient_stops(), info.gradient.extend_mode, - tile_size, + info.tile_size, info.tile_spacing, None, ) { @@ -1292,18 +1220,12 @@ impl<'a> DisplayListFlattener<'a> { } } DisplayItem::RadialGradient(ref info) => { - let (layout, unsnapped_rect, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.bounds, apply_pipeline_clip, ); - let tile_size = process_repeat_size( - &layout.rect, - &unsnapped_rect, - info.tile_size, - ); - let prim_key_kind = self.create_radial_gradient_prim( &layout, info.gradient.center, @@ -1312,7 +1234,7 @@ impl<'a> DisplayListFlattener<'a> { info.gradient.radius.width / info.gradient.radius.height, item.gradient_stops(), info.gradient.extend_mode, - tile_size, + info.tile_size, info.tile_spacing, None, ); @@ -1325,7 +1247,7 @@ impl<'a> DisplayListFlattener<'a> { ); } DisplayItem::BoxShadow(ref info) => { - let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.box_bounds, apply_pipeline_clip, @@ -1343,7 +1265,7 @@ impl<'a> DisplayListFlattener<'a> { ); } DisplayItem::Border(ref info) => { - let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds( + let (layout, clip_and_scroll) = self.process_common_properties_with_bounds( &info.common, &info.bounds, apply_pipeline_clip, @@ -1760,7 +1682,6 @@ impl<'a> DisplayListFlattener<'a> { clip_chain_id: ClipChainId, requested_raster_space: RasterSpace, is_backdrop_root: bool, - device_pixel_scale: DevicePixelScale, ) { // Check if this stacking context is the root of a pipeline, and the caller // has requested it as an output frame. @@ -1863,14 +1784,6 @@ impl<'a> DisplayListFlattener<'a> { current_clip_chain_id = clip_chain_node.parent_clip_chain_id; } - let snap_to_device = self.sc_stack.last().map_or( - SpaceSnapper::new( - ROOT_SPATIAL_NODE_INDEX, - device_pixel_scale, - ), - |sc| sc.snap_to_device.clone(), - ); - // Push the SC onto the stack, so we know how to handle things in // pop_stacking_context. self.sc_stack.push(FlattenedStackingContext { @@ -1887,7 +1800,6 @@ impl<'a> DisplayListFlattener<'a> { context_3d, create_tile_cache, is_backdrop_root, - snap_to_device, }); } @@ -2263,7 +2175,6 @@ impl<'a> DisplayListFlattener<'a> { pipeline_id: PipelineId, viewport_size: &LayoutSize, content_size: &LayoutSize, - device_pixel_scale: DevicePixelScale, ) { if let ChasePrimitive::Id(id) = self.config.chase_primitive { println!("Chasing {:?} by index", id); @@ -2282,27 +2193,13 @@ impl<'a> DisplayListFlattener<'a> { LayoutVector2D::zero(), ); - // We can't use this with the stacking context because it does not exist - // yet. Just create a dedicated snapper for the root. - let snap_to_device = SpaceSnapper::new_with_target( - spatial_node_index, - ROOT_SPATIAL_NODE_INDEX, - device_pixel_scale, - self.clip_scroll_tree, - ); - - let content_size = snap_to_device.snap_size(content_size); - let viewport_rect = snap_to_device.snap_rect( - &LayoutRect::new(LayoutPoint::zero(), *viewport_size), - ); - self.add_scroll_frame( SpatialId::root_scroll_node(pipeline_id), spatial_node_index, Some(ExternalScrollId(0, pipeline_id)), pipeline_id, - &viewport_rect, - &content_size, + &LayoutRect::new(LayoutPoint::zero(), *viewport_size), + content_size, ScrollSensitivity::ScriptAndInputEvents, ScrollFrameKind::PipelineRoot, LayoutVector2D::zero(), @@ -2326,14 +2223,6 @@ impl<'a> DisplayListFlattener<'a> { // Map the ClipId for the positioning node to a spatial node index. let spatial_node_index = self.id_to_index_mapper.get_spatial_node_index(space_and_clip.spatial_id); - let snap_to_device = &mut self.sc_stack.last_mut().unwrap().snap_to_device; - snap_to_device.set_target_spatial_node( - spatial_node_index, - self.clip_scroll_tree, - ); - - let snapped_clip_rect = snap_to_device.snap_rect(&clip_region.main); - let mut clip_count = 0; // Intern each clip item in this clip node, and add the interned @@ -2343,7 +2232,7 @@ impl<'a> DisplayListFlattener<'a> { // Build the clip sources from the supplied region. let item = ClipItemKey { - kind: ClipItemKeyKind::rectangle(snapped_clip_rect, ClipMode::Clip), + kind: ClipItemKeyKind::rectangle(clip_region.main, ClipMode::Clip), spatial_node_index, }; let handle = self @@ -2360,9 +2249,8 @@ impl<'a> DisplayListFlattener<'a> { clip_count += 1; if let Some(ref image_mask) = clip_region.image_mask { - let snapped_mask_rect = snap_to_device.snap_rect(&image_mask.rect); let item = ClipItemKey { - kind: ClipItemKeyKind::image_mask(image_mask, snapped_mask_rect), + kind: ClipItemKeyKind::image_mask(image_mask), spatial_node_index, }; @@ -2381,10 +2269,9 @@ impl<'a> DisplayListFlattener<'a> { } for region in clip_region.complex_clips { - let snapped_region_rect = snap_to_device.snap_rect(®ion.rect); let item = ClipItemKey { kind: ClipItemKeyKind::rounded_rect( - snapped_region_rect, + region.rect, region.radii, region.mode, ), @@ -2657,23 +2544,11 @@ impl<'a> DisplayListFlattener<'a> { P: InternablePrimitive + CreateShadow, Interners: AsMut>, { - let snap_to_device = &mut self.sc_stack.last_mut().unwrap().snap_to_device; - snap_to_device.set_target_spatial_node( - pending_primitive.clip_and_scroll.spatial_node_index, - self.clip_scroll_tree - ); - - // Offset the local rect and clip rect by the shadow offset. The pending - // primitive has already been snapped, but we will need to snap the - // shadow after translation. We don't need to worry about the size - // changing because the shadow has the same raster space as the - // primitive, and thus we know the size is already rounded. + // Offset the local rect and clip rect by the shadow offset. let mut info = pending_primitive.info.clone(); - info.rect = snap_to_device.snap_rect( - &info.rect.translate(pending_shadow.shadow.offset), - ); - info.clip_rect = snap_to_device.snap_rect( - &info.clip_rect.translate(pending_shadow.shadow.offset), + info.rect = info.rect.translate(pending_shadow.shadow.offset); + info.clip_rect = info.clip_rect.translate( + pending_shadow.shadow.offset ); // Construct and add a primitive for the given shadow. @@ -3562,13 +3437,6 @@ struct FlattenedStackingContext { /// True if this stacking context is a backdrop root. is_backdrop_root: bool, - - /// A helper struct to snap local rects in device space. During frame - /// building we may establish new raster roots, however typically that is in - /// cases where we won't be applying snapping (e.g. has perspective), or in - /// edge cases (e.g. SVG filter) where we can accept slightly incorrect - /// behaviour in favour of getting the common case right. - snap_to_device: SpaceSnapper, } impl FlattenedStackingContext { @@ -3822,22 +3690,3 @@ fn filter_primitives_for_compositing( // more efficient than cloning these here. input_filter_primitives.iter().map(|primitive| primitive.into()).collect() } - -fn process_repeat_size( - snapped_rect: &LayoutRect, - unsnapped_rect: &LayoutRect, - repeat_size: LayoutSize, -) -> LayoutSize { - LayoutSize::new( - if repeat_size.width == unsnapped_rect.size.width { - snapped_rect.size.width - } else { - repeat_size.width - }, - if repeat_size.height == unsnapped_rect.size.height { - snapped_rect.size.height - } else { - repeat_size.height - }, - ) -} diff --git a/gfx/wr/webrender/src/frame_builder.rs b/gfx/wr/webrender/src/frame_builder.rs index 525d0a07242f..e7b65fb2c7af 100644 --- a/gfx/wr/webrender/src/frame_builder.rs +++ b/gfx/wr/webrender/src/frame_builder.rs @@ -392,7 +392,7 @@ impl FrameBuilder { &frame_context, gpu_cache, &self.clip_store, - data_stores, + &data_stores.clip, ); { @@ -544,7 +544,6 @@ impl FrameBuilder { clip_scroll_tree.update_tree( pan, - global_device_pixel_scale, scene_properties, ); let mut transform_palette = clip_scroll_tree.build_transform_palette(); diff --git a/gfx/wr/webrender/src/gpu_types.rs b/gfx/wr/webrender/src/gpu_types.rs index ccad6b2f6689..0f1b9b0f9f5c 100644 --- a/gfx/wr/webrender/src/gpu_types.rs +++ b/gfx/wr/webrender/src/gpu_types.rs @@ -169,6 +169,7 @@ pub struct ClipMaskInstance { pub local_pos: LayoutPoint, pub tile_rect: LayoutRect, pub sub_rect: DeviceRect, + pub snap_offsets: SnapOffsets, pub task_origin: DevicePoint, pub screen_origin: DevicePoint, pub device_pixel_scale: f32, @@ -249,6 +250,7 @@ impl PrimitiveHeaders { self.headers_float.push(PrimitiveHeaderF { local_rect: prim_header.local_rect, local_clip_rect: prim_header.local_clip_rect, + snap_offsets: prim_header.snap_offsets, }); self.headers_int.push(PrimitiveHeaderI { @@ -269,6 +271,7 @@ impl PrimitiveHeaders { pub struct PrimitiveHeader { pub local_rect: LayoutRect, pub local_clip_rect: LayoutRect, + pub snap_offsets: SnapOffsets, pub specific_prim_address: GpuCacheAddress, pub transform_id: TransformPaletteId, } @@ -281,6 +284,7 @@ pub struct PrimitiveHeader { pub struct PrimitiveHeaderF { pub local_rect: LayoutRect, pub local_clip_rect: LayoutRect, + pub snap_offsets: SnapOffsets, } // i32 parts of a primitive header @@ -589,6 +593,33 @@ pub enum UvRectKind { }, } +/// Represents offsets in device pixels that a primitive +/// was snapped to. +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct SnapOffsets { + /// How far the top left corner was snapped + pub top_left: DeviceVector2D, + /// How far the bottom right corner was snapped + pub bottom_right: DeviceVector2D, +} + +impl SnapOffsets { + pub fn empty() -> Self { + SnapOffsets { + top_left: DeviceVector2D::zero(), + bottom_right: DeviceVector2D::zero(), + } + } + + pub fn is_empty(&self) -> bool { + let zero = DeviceVector2D::zero(); + self.top_left == zero && self.bottom_right == zero + } +} + #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs index fbc6d16b10d8..40354e79a565 100644 --- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -7,7 +7,7 @@ use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FontRenderMode}; use api::{DebugFlags, RasterSpace, ImageKey, ColorF}; use api::units::*; use crate::box_shadow::{BLUR_SAMPLE_SCALE}; -use crate::clip::{ClipStore, ClipChainInstance, ClipDataHandle, ClipChainId}; +use crate::clip::{ClipStore, ClipDataStore, ClipChainInstance, ClipDataHandle, ClipChainId}; use crate::clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace, CoordinateSystemId }; @@ -23,7 +23,7 @@ use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use crate::gpu_types::UvRectKind; use plane_split::{Clipper, Polygon, Splitter}; use crate::prim_store::{SpaceMapper, PrimitiveVisibilityMask, PointKey, PrimitiveTemplateKind}; -use crate::prim_store::{SpaceSnapper, PictureIndex, PrimitiveInstance, PrimitiveInstanceKind}; +use crate::prim_store::{PictureIndex, PrimitiveInstance, PrimitiveInstanceKind}; use crate::prim_store::{get_raster_rects, PrimitiveScratchBuffer, RectangleKey}; use crate::prim_store::{OpacityBindingStorage, ImageInstanceStorage, OpacityBindingIndex}; use crate::print_tree::PrintTreePrinter; @@ -1781,7 +1781,7 @@ impl<'a> PictureUpdateState<'a> { frame_context: &FrameBuildingContext, gpu_cache: &mut GpuCache, clip_store: &ClipStore, - data_stores: &mut DataStores, + clip_data_store: &ClipDataStore, ) { profile_marker!("UpdatePictures"); @@ -1798,7 +1798,7 @@ impl<'a> PictureUpdateState<'a> { frame_context, gpu_cache, clip_store, - data_stores, + clip_data_store, ); if !state.are_raster_roots_assigned { @@ -1861,7 +1861,7 @@ impl<'a> PictureUpdateState<'a> { frame_context: &FrameBuildingContext, gpu_cache: &mut GpuCache, clip_store: &ClipStore, - data_stores: &mut DataStores, + clip_data_store: &ClipDataStore, ) { if let Some(prim_list) = picture_primitives[pic_index.0].pre_update( self, @@ -1874,7 +1874,7 @@ impl<'a> PictureUpdateState<'a> { frame_context, gpu_cache, clip_store, - data_stores, + clip_data_store, ); } @@ -1882,7 +1882,6 @@ impl<'a> PictureUpdateState<'a> { prim_list, self, frame_context, - data_stores, ); } } @@ -2197,10 +2196,6 @@ pub struct PrimitiveClusterIndex(pub u32); #[cfg_attr(feature = "capture", derive(Serialize))] pub struct ClusterIndex(pub u16); -#[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "capture", derive(Serialize))] -pub struct PrimitiveIndex(pub u32); - impl ClusterIndex { pub const INVALID: ClusterIndex = ClusterIndex(u16::MAX); } @@ -2222,10 +2217,6 @@ pub struct PrimitiveList { pub pictures: PictureList, /// List of primitives grouped into clusters. pub clusters: SmallVec<[PrimitiveCluster; 4]>, - /// List of primitive indicies that can only update - /// the cluster during frame building. This maps to - /// primitives in the prim_instances array. - pub deferred_prims: Vec, } impl PrimitiveList { @@ -2238,7 +2229,6 @@ impl PrimitiveList { prim_instances: Vec::new(), pictures: SmallVec::new(), clusters: SmallVec::new(), - deferred_prims: Vec::new(), } } @@ -2253,11 +2243,10 @@ impl PrimitiveList { let mut pictures = SmallVec::new(); let mut clusters_map = FastHashMap::default(); let mut clusters: SmallVec<[PrimitiveCluster; 4]> = SmallVec::new(); - let mut deferred_prims = Vec::new(); // Walk the list of primitive instances and extract any that // are pictures. - for (prim_index, prim_instance) in &mut prim_instances.iter_mut().enumerate() { + for prim_instance in &mut prim_instances { // Check if this primitive is a picture. In future we should // remove this match and embed this info directly in the primitive instance. let is_pic = match prim_instance.kind { @@ -2313,12 +2302,8 @@ impl PrimitiveList { (data.is_backface_visible, data.prim_size) } PrimitiveInstanceKind::Backdrop { data_handle, .. } => { - // We don't know the actual size of the backdrop until frame - // building, so use an empty rect for now and add it to the - // deferred primitive list. let data = &interners.backdrop[data_handle]; - deferred_prims.push(PrimitiveIndex(prim_index as u32)); - (data.is_backface_visible, LayoutSize::zero()) + (data.is_backface_visible, data.prim_size) } PrimitiveInstanceKind::PushClipChain | PrimitiveInstanceKind::PopClipChain => { @@ -2373,7 +2358,6 @@ impl PrimitiveList { prim_instances, pictures, clusters, - deferred_prims, } } } @@ -2439,10 +2423,17 @@ pub struct PicturePrimitive { /// composited into the parent picture. pub spatial_node_index: SpatialNodeIndex, + /// The local rect of this picture. It is built + /// dynamically when updating visibility. It takes + /// into account snapping in device space for its + /// children. + pub snapped_local_rect: LayoutRect, + /// The local rect of this picture. It is built /// dynamically during the first picture traversal. It - /// is composed of already snapped primitives. - pub local_rect: LayoutRect, + /// does not take into account snapping in device for + /// its children. + pub unsnapped_local_rect: LayoutRect, /// If false, this picture needs to (re)build segments /// if it supports segment rendering. This can occur @@ -2467,7 +2458,8 @@ impl PicturePrimitive { ) { pt.new_level(format!("{:?}", self_index)); pt.add_item(format!("prim_count: {:?}", self.prim_list.prim_instances.len())); - pt.add_item(format!("local_rect: {:?}", self.local_rect)); + pt.add_item(format!("snapped_local_rect: {:?}", self.snapped_local_rect)); + pt.add_item(format!("unsnapped_local_rect: {:?}", self.unsnapped_local_rect)); pt.add_item(format!("spatial_node_index: {:?}", self.spatial_node_index)); pt.add_item(format!("raster_config: {:?}", self.raster_config)); pt.add_item(format!("requested_composite_mode: {:?}", self.requested_composite_mode)); @@ -2576,7 +2568,8 @@ impl PicturePrimitive { is_backface_visible, requested_raster_space, spatial_node_index, - local_rect: LayoutRect::zero(), + snapped_local_rect: LayoutRect::zero(), + unsnapped_local_rect: LayoutRect::zero(), tile_cache, options, segments_are_valid: false, @@ -2680,7 +2673,7 @@ impl PicturePrimitive { match self.raster_config { Some(ref raster_config) => { - let pic_rect = PictureRect::from_untyped(&self.local_rect.to_untyped()); + let pic_rect = PictureRect::from_untyped(&self.snapped_local_rect.to_untyped()); let device_pixel_scale = frame_state .surfaces[raster_config.surface_index.0] @@ -3451,7 +3444,6 @@ impl PicturePrimitive { prim_list: PrimitiveList, state: &mut PictureUpdateState, frame_context: &FrameBuildingContext, - data_stores: &mut DataStores, ) { // Restore the pictures list used during recursion. self.prim_list = prim_list; @@ -3459,59 +3451,6 @@ impl PicturePrimitive { // Pop the state information about this picture. state.pop_picture(); - // Update any primitives/cluster bounding rects that can only be done - // with information available during frame building. - for prim_index in &self.prim_list.deferred_prims { - let prim_instance = &mut self.prim_list.prim_instances[prim_index.0 as usize]; - match prim_instance.kind { - PrimitiveInstanceKind::Backdrop { data_handle, .. } => { - // The actual size and clip rect of this primitive are determined by computing the bounding - // box of the projected rect of the backdrop-filter element onto the backdrop. - let prim_data = &mut data_stores.backdrop[data_handle]; - let spatial_node_index = prim_data.kind.spatial_node_index; - - // We cannot use the relative transform between the backdrop and the element because - // that doesn't take into account any projection transforms that both spatial nodes are children of. - // Instead, we first project from the element to the world space and get a flattened 2D bounding rect - // in the screen space, we then map this rect from the world space to the backdrop space to get the - // proper bounding box where the backdrop-filter needs to be processed. - - let prim_to_world_mapper = SpaceMapper::new_with_target( - ROOT_SPATIAL_NODE_INDEX, - spatial_node_index, - LayoutRect::max_rect(), - frame_context.clip_scroll_tree, - ); - - let backdrop_to_world_mapper = SpaceMapper::new_with_target( - ROOT_SPATIAL_NODE_INDEX, - prim_instance.spatial_node_index, - LayoutRect::max_rect(), - frame_context.clip_scroll_tree, - ); - - // First map to the screen and get a flattened rect - let prim_rect = prim_to_world_mapper.map(&prim_data.kind.border_rect).unwrap_or_else(LayoutRect::zero); - // Backwards project the flattened rect onto the backdrop - let prim_rect = backdrop_to_world_mapper.unmap(&prim_rect).unwrap_or_else(LayoutRect::zero); - - // TODO(aosmond): Is this safe? Updating the primitive size during - // frame building is usually problematic since scene building will cache - // the primitive information in the GPU already. - prim_instance.prim_origin = prim_rect.origin; - prim_data.common.prim_size = prim_rect.size; - prim_instance.local_clip_rect = prim_rect; - - // Update the cluster bounding rect now that we have the backdrop rect. - let cluster = &mut self.prim_list.clusters[prim_instance.cluster_index.0 as usize]; - cluster.bounding_rect = cluster.bounding_rect.union(&prim_rect); - } - _ => { - panic!("BUG: unexpected deferred primitive kind for cluster updates"); - } - } - } - for cluster in &mut self.prim_list.clusters { // Skip the cluster if backface culled. if !cluster.is_backface_visible { @@ -3563,18 +3502,6 @@ impl PicturePrimitive { // This inflaction factor is to be applied to the surface itself. if self.options.inflate_if_required { surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.inflation_factor); - - // The picture's local rect is calculated as the union of the - // snapped primitive rects, which should result in a snapped - // local rect, unless it was inflated. - let snap_surface_to_raster = SpaceSnapper::new_with_target( - surface.raster_spatial_node_index, - self.spatial_node_index, - surface.device_pixel_scale, - frame_context.clip_scroll_tree, - ); - - surface.rect = snap_surface_to_raster.snap_rect(&surface.rect); } let mut surface_rect = surface.rect * Scale::new(1.0); @@ -3583,6 +3510,11 @@ impl PicturePrimitive { let surface_index = state.pop_surface(); debug_assert_eq!(surface_index, raster_config.surface_index); + // Snapping may change the local rect slightly, and as such should just be + // considered an estimated size for determining if we need raster roots and + // preparing the tile cache. + self.unsnapped_local_rect = surface_rect; + // Check if any of the surfaces can't be rasterized in local space but want to. if raster_config.establishes_raster_root { if surface_rect.size.width > MAX_SURFACE_SIZE || @@ -3593,8 +3525,6 @@ impl PicturePrimitive { } } - self.local_rect = surface_rect; - // Drop shadows draw both a content and shadow rect, so need to expand the local // rect of any surfaces to be composited in parent surfaces correctly. match raster_config.composite_mode { @@ -3663,14 +3593,14 @@ impl PicturePrimitive { // Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs) // [brush specific data] // [segment_rect, segment data] - let shadow_rect = self.local_rect.translate(shadow.offset); + let shadow_rect = self.snapped_local_rect.translate(shadow.offset); // ImageBrush colors request.push(shadow.color.premultiplied()); request.push(PremultipliedColorF::WHITE); request.push([ - self.local_rect.size.width, - self.local_rect.size.height, + self.snapped_local_rect.size.width, + self.snapped_local_rect.size.height, 0.0, 0.0, ]); diff --git a/gfx/wr/webrender/src/prim_store/mod.rs b/gfx/wr/webrender/src/prim_store/mod.rs index d67894d81ce9..db5ddf1611d8 100644 --- a/gfx/wr/webrender/src/prim_store/mod.rs +++ b/gfx/wr/webrender/src/prim_store/mod.rs @@ -22,7 +22,7 @@ use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureCont use crate::frame_builder::{FrameVisibilityContext, FrameVisibilityState}; use crate::glyph_rasterizer::GlyphKey; use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; -use crate::gpu_types::{BrushFlags}; +use crate::gpu_types::{BrushFlags, SnapOffsets}; use crate::image::{Repetition}; use crate::intern; use crate::internal_types::PlaneSplitAnchor; @@ -52,7 +52,7 @@ use std::{cmp, fmt, hash, ops, u32, usize, mem}; use std::sync::atomic::{AtomicUsize, Ordering}; use crate::storage; use crate::texture_cache::TEXTURE_REGION_DIMENSIONS; -use crate::util::{MatrixHelpers, MaxRect, Recycler, ScaleOffset, RectHelpers}; +use crate::util::{MatrixHelpers, MaxRect, Recycler}; use crate::util::{clamp_to_scale_factor, pack_as_float, project_rect, raster_rect_to_device_pixels}; use crate::internal_types::{LayoutPrimitiveInfo, Filter}; use smallvec::SmallVec; @@ -132,91 +132,6 @@ impl PrimitiveOpacity { } } -#[derive(Clone, Debug)] -pub struct SpaceSnapper { - pub ref_spatial_node_index: SpatialNodeIndex, - current_target_spatial_node_index: SpatialNodeIndex, - snapping_transform: Option, - pub device_pixel_scale: DevicePixelScale, -} - -impl SpaceSnapper { - pub fn new( - ref_spatial_node_index: SpatialNodeIndex, - device_pixel_scale: DevicePixelScale, - ) -> Self { - SpaceSnapper { - ref_spatial_node_index, - current_target_spatial_node_index: SpatialNodeIndex::INVALID, - snapping_transform: None, - device_pixel_scale, - } - } - - pub fn new_with_target( - ref_spatial_node_index: SpatialNodeIndex, - target_node_index: SpatialNodeIndex, - device_pixel_scale: DevicePixelScale, - clip_scroll_tree: &ClipScrollTree, - ) -> Self { - let mut snapper = SpaceSnapper { - ref_spatial_node_index, - current_target_spatial_node_index: SpatialNodeIndex::INVALID, - snapping_transform: None, - device_pixel_scale, - }; - - snapper.set_target_spatial_node(target_node_index, clip_scroll_tree); - snapper - } - - pub fn set_target_spatial_node( - &mut self, - target_node_index: SpatialNodeIndex, - clip_scroll_tree: &ClipScrollTree, - ) { - if target_node_index == self.current_target_spatial_node_index { - return - } - - let ref_spatial_node = &clip_scroll_tree.spatial_nodes[self.ref_spatial_node_index.0 as usize]; - let target_spatial_node = &clip_scroll_tree.spatial_nodes[target_node_index.0 as usize]; - - self.current_target_spatial_node_index = target_node_index; - self.snapping_transform = match (ref_spatial_node.snapping_transform, target_spatial_node.snapping_transform) { - (Some(ref ref_scale_offset), Some(ref target_scale_offset)) => { - Some(ref_scale_offset - .inverse() - .accumulate(target_scale_offset) - .scale(self.device_pixel_scale.0)) - } - _ => None, - }; - } - - pub fn snap_rect(&self, rect: &Rect) -> Rect where F: fmt::Debug { - debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID); - match self.snapping_transform { - Some(ref scale_offset) => { - let snapped_device_rect : DeviceRect = scale_offset.map_rect(rect).snap(); - scale_offset.unmap_rect(&snapped_device_rect) - } - None => *rect, - } - } - - pub fn snap_size(&self, size: &Size2D) -> Size2D where F: fmt::Debug { - debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID); - match self.snapping_transform { - Some(ref scale_offset) => { - let rect = Rect::::new(Point2D::::zero(), *size); - let snapped_device_rect : DeviceRect = scale_offset.map_rect(&rect).snap(); - scale_offset.unmap_rect(&snapped_device_rect).size - } - None => *size, - } - } -} #[derive(Debug, Clone)] pub struct SpaceMapper { @@ -1018,6 +933,7 @@ impl BrushSegment { frame_state: &mut FrameBuildingState, clip_data_store: &mut ClipDataStore, unclipped: &DeviceRect, + prim_snap_offsets: SnapOffsets, device_pixel_scale: DevicePixelScale, ) -> ClipMaskKind { match clip_chain { @@ -1040,8 +956,9 @@ impl BrushSegment { // Get a minimal device space rect, clipped to the screen that we // need to allocate for the clip mask, as well as interpolated // snap offsets. - let device_rect = match get_clipped_device_rect( + let (device_rect, snap_offsets) = match get_clipped_device_rect( unclipped, + prim_snap_offsets, &pic_state.map_raster_to_world, segment_world_rect, device_pixel_scale, @@ -1061,6 +978,7 @@ impl BrushSegment { frame_state.resource_cache, frame_state.render_tasks, clip_data_store, + snap_offsets, device_pixel_scale, frame_context.fb_config, ); @@ -1518,6 +1436,18 @@ pub struct PrimitiveVisibility { /// The current combined local clip for this primitive, from /// the primitive local clip above and the current clip chain. pub combined_local_clip_rect: LayoutRect, + + /// The snap offsets in device space for this primitive. They are + /// generated based on the visible rect, which is the local rect + /// clipped by the combined local clip for most primitives, or + /// just the local rect for pictures. + pub snap_offsets: SnapOffsets, + + /// The snap offsets in device space for the drop shadow for + /// picture primitives, if applicable. Similar to snap offsets, + /// they are generated based on the local rect translated by the + /// drop shadow offset. + pub shadow_snap_offsets: SnapOffsets, } #[derive(Clone, Debug)] @@ -1878,7 +1808,7 @@ impl PrimitiveStore { world_culling_rect: &WorldRect, frame_context: &FrameVisibilityContext, frame_state: &mut FrameVisibilityState, - ) { + ) -> Option { let (mut prim_list, surface_index, apply_local_clip_rect, world_culling_rect, is_composite) = { let pic = &mut self.pictures[pic_index.0]; let mut world_culling_rect = *world_culling_rect; @@ -1898,7 +1828,7 @@ impl PrimitiveStore { // relative transforms have changed, which means we need to // re-map the dependencies of any child primitives. world_culling_rect = tile_cache.pre_update( - PictureRect::from_untyped(&pic.local_rect.to_untyped()), + PictureRect::from_untyped(&pic.unsnapped_local_rect.to_untyped()), surface_index, frame_context, frame_state, @@ -1932,13 +1862,19 @@ impl PrimitiveStore { frame_context.clip_scroll_tree, ); + let mut map_local_to_raster = SpaceMapper::new( + surface.raster_spatial_node_index, + RasterRect::max_rect(), + ); + + let mut surface_rect = PictureRect::zero(); + for prim_instance in &mut prim_list.prim_instances { prim_instance.reset(); if prim_instance.is_chased() { #[cfg(debug_assertions)] // needed for ".id" part println!("\tpreparing {:?} in {:?}", prim_instance.id, pic_index); - println!("\t{:?}", prim_instance.kind); } // Get the cluster and see if is visible @@ -1954,7 +1890,12 @@ impl PrimitiveStore { frame_context.clip_scroll_tree, ); - let (is_passthrough, prim_local_rect, prim_shadow_rect) = match prim_instance.kind { + map_local_to_raster.set_target_spatial_node( + prim_instance.spatial_node_index, + frame_context.clip_scroll_tree, + ); + + let (is_passthrough, snap_to_visible, prim_local_rect, prim_shadow_rect) = match prim_instance.kind { PrimitiveInstanceKind::PushClipChain => { frame_state.clip_chain_stack.push_clip( prim_instance.clip_chain_id, @@ -1976,7 +1917,7 @@ impl PrimitiveStore { frame_state.clip_store, ); - self.update_visibility( + let pic_surface_rect = self.update_visibility( pic_index, surface_index, &world_culling_rect, @@ -1986,6 +1927,8 @@ impl PrimitiveStore { frame_state.clip_chain_stack.pop_clip(); + let pic = &self.pictures[pic_index.0]; + // The local rect of pictures is calculated dynamically based on // the content of children, which may move due to the spatial // node they are attached to. Other parts of the code (such as @@ -1995,22 +1938,74 @@ impl PrimitiveStore { // this way. In future, we could perhaps just store the // size in the picture primitive, to that there isn't // any duplicated data. - let pic = &self.pictures[pic_index.0]; - prim_instance.prim_origin = pic.local_rect.origin; + prim_instance.prim_origin = pic.snapped_local_rect.origin; - let shadow_rect = if let Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)), .. }) = pic.raster_config { - // If we have a drop shadow filter, we also need to include the shadow in - // our local rect for the purpose of calculating the size of the picture. - let mut rect = LayoutRect::zero(); - for shadow in shadows { - rect = rect.union(&pic.local_rect.translate(shadow.offset)); + let shadow_rect = match pic.raster_config { + Some(ref rc) => match rc.composite_mode { + // If we have a drop shadow filter, we also need to include the shadow in + // our local rect for the purpose of calculating the size of the picture. + PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => { + let mut rect = LayoutRect::zero(); + for shadow in shadows { + rect = rect.union(&pic.snapped_local_rect.translate(shadow.offset)); + } + + rect + } + _ => LayoutRect::zero(), + } + None => { + if let Some(ref rect) = pic_surface_rect { + surface_rect = surface_rect.union(rect); + } + LayoutRect::zero() } - rect - } else { - LayoutRect::zero() }; - (pic.raster_config.is_none(), pic.local_rect, shadow_rect) + if prim_instance.is_chased() { + if pic.unsnapped_local_rect != pic.snapped_local_rect { + println!("\tsnapped from {:?} to {:?}", pic.unsnapped_local_rect, pic.snapped_local_rect); + } + } + + (pic.raster_config.is_none(), false, pic.snapped_local_rect, shadow_rect) + } + PrimitiveInstanceKind::Backdrop { data_handle } => { + // The actual size and clip rect of this primitive are determined by computing the bounding + // box of the projected rect of the backdrop-filter element onto the backdrop. + let prim_data = &mut frame_state.data_stores.backdrop[data_handle]; + let spatial_node_index = prim_data.kind.spatial_node_index; + + // We cannot use the relative transform between the backdrop and the element because + // that doesn't take into account any projection transforms that both spatial nodes are children of. + // Instead, we first project from the element to the world space and get a flattened 2D bounding rect + // in the screen space, we then map this rect from the world space to the backdrop space to get the + // proper bounding box where the backdrop-filter needs to be processed. + + let prim_to_world_mapper = SpaceMapper::new_with_target( + ROOT_SPATIAL_NODE_INDEX, + spatial_node_index, + LayoutRect::max_rect(), + frame_context.clip_scroll_tree, + ); + + let backdrop_to_world_mapper = SpaceMapper::new_with_target( + ROOT_SPATIAL_NODE_INDEX, + prim_instance.spatial_node_index, + LayoutRect::max_rect(), + frame_context.clip_scroll_tree, + ); + + // First map to the screen and get a flattened rect + let prim_rect = prim_to_world_mapper.map(&prim_data.kind.border_rect).unwrap_or_else(LayoutRect::zero); + // Backwards project the flattened rect onto the backdrop + let prim_rect = backdrop_to_world_mapper.unmap(&prim_rect).unwrap_or_else(LayoutRect::zero); + + prim_instance.prim_origin = prim_rect.origin; + prim_data.common.prim_size = prim_rect.size; + prim_instance.local_clip_rect = prim_rect; + + (false, true, prim_rect, LayoutRect::zero()) } _ => { let prim_data = &frame_state.data_stores.as_common_data(&prim_instance); @@ -2020,7 +2015,7 @@ impl PrimitiveStore { prim_data.prim_size, ); - (false, prim_rect, LayoutRect::zero()) + (false, true, prim_rect, LayoutRect::zero()) } }; @@ -2033,6 +2028,8 @@ impl PrimitiveStore { clip_chain: ClipChainInstance::empty(), clip_task_index: ClipTaskIndex::INVALID, combined_local_clip_rect: LayoutRect::zero(), + snap_offsets: SnapOffsets::empty(), + shadow_snap_offsets: SnapOffsets::empty(), visibility_mask: PrimitiveVisibilityMask::empty(), } ); @@ -2175,6 +2172,56 @@ impl PrimitiveStore { continue; } + // All pictures must snap to their primitive rect instead of the + // visible rect like most primitives. This is because the picture's + // visible rect includes the effect of the picture's clip rect, + // which was not considered by the picture's children. The primitive + // rect however is simply the union of the visible rect of the + // children, which they snapped to, which is precisely what we also + // need to snap to in order to be consistent. + let visible_rect = if snap_to_visible { + match combined_local_clip_rect.intersection(&prim_local_rect) { + Some(r) => r, + None => { + if prim_instance.is_chased() { + println!("\tculled for zero visible rectangle"); + } + prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID; + continue; + } + } + } else { + prim_local_rect + }; + + // This is how primitives get snapped. In general, snapping a picture's + // visible rect here will have no effect, but if it is rasterized in its + // own space, or it has a blur or drop shadow effect applied, it may + // provide a snapping offset. + let (snapped_visible_rect, snap_offsets) = get_snapped_rect( + visible_rect, + &map_local_to_raster, + surface.device_pixel_scale, + ).unwrap_or((visible_rect, SnapOffsets::empty())); + + let (combined_visible_rect, shadow_snap_offsets) = if !prim_shadow_rect.is_empty() { + let (snapped_shadow_rect, shadow_snap_offsets) = get_snapped_rect( + prim_shadow_rect, + &map_local_to_raster, + surface.device_pixel_scale, + ).unwrap_or((prim_shadow_rect, SnapOffsets::empty())); + + (snapped_visible_rect.union(&snapped_shadow_rect), shadow_snap_offsets) + } else { + (snapped_visible_rect, SnapOffsets::empty()) + }; + + // Include the snapped primitive/picture local rect, including any shadows, + // in the area affected by the surface. + if let Some(rect) = map_local_to_surface.map(&combined_visible_rect) { + surface_rect = surface_rect.union(&rect); + } + // When the debug display is enabled, paint a colored rectangle around each // primitive. if frame_context.debug_flags.contains(::api::DebugFlags::PRIMITIVE_DBG) { @@ -2211,6 +2258,8 @@ impl PrimitiveStore { clip_chain, clip_task_index: ClipTaskIndex::INVALID, combined_local_clip_rect, + snap_offsets, + shadow_snap_offsets, visibility_mask: PrimitiveVisibilityMask::empty(), } ); @@ -2241,18 +2290,55 @@ impl PrimitiveStore { // TODO(gw): In future, if we support specifying a flag which gets the // stretch size from the segment rect in the shaders, we can // remove this invalidation here completely. - if let Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, .. }) = pic.raster_config { - let mut tile_cache = frame_state.tile_cache.take().unwrap(); + if let Some(ref raster_config) = pic.raster_config { + // Inflate the local bounding rect if required by the filter effect. + // This inflaction factor is to be applied to the surface itself. + if pic.options.inflate_if_required { + surface_rect = raster_config.composite_mode.inflate_picture_rect(surface_rect, surface.inflation_factor); + } - // Build the dirty region(s) for this tile cache. - tile_cache.post_update( - frame_state.resource_cache, - frame_state.gpu_cache, - frame_context, - frame_state.scratch, + // Layout space for the picture is picture space from the + // perspective of its child primitives. + let pic_local_rect = surface_rect * Scale::new(1.0); + if pic.snapped_local_rect != pic_local_rect { + match raster_config.composite_mode { + PictureCompositeMode::Filter(Filter::DropShadows(..)) => { + for handle in &pic.extra_gpu_data_handles { + frame_state.gpu_cache.invalidate(handle); + } + } + _ => {} + } + // Invalidate any segments built for this picture, since the local + // rect has changed. + pic.segments_are_valid = false; + pic.snapped_local_rect = pic_local_rect; + } + + if let PictureCompositeMode::TileCache { .. } = raster_config.composite_mode { + let mut tile_cache = frame_state.tile_cache.take().unwrap(); + + // Build the dirty region(s) for this tile cache. + tile_cache.post_update( + frame_state.resource_cache, + frame_state.gpu_cache, + frame_context, + frame_state.scratch, + ); + + pic.tile_cache = Some(tile_cache); + } + + None + } else { + let parent_surface = &frame_context.surfaces[parent_surface_index.0 as usize]; + let map_surface_to_parent_surface = SpaceMapper::new_with_target( + parent_surface.surface_spatial_node_index, + surface.surface_spatial_node_index, + PictureRect::max_rect(), + frame_context.clip_scroll_tree, ); - - pic.tile_cache = Some(tile_cache); + map_surface_to_parent_surface.map(&surface_rect) } } @@ -3230,7 +3316,7 @@ impl PrimitiveStore { splitter, frame_context.clip_scroll_tree, prim_instance.spatial_node_index, - pic.local_rect, + pic.snapped_local_rect, &prim_info.combined_local_clip_rect, frame_state.current_dirty_region().combined, plane_split_anchor, @@ -3540,15 +3626,13 @@ impl<'a> GpuDataRequest<'a> { impl PrimitiveInstance { fn build_segments_if_needed( &mut self, - prim_info: &PrimitiveVisibility, + prim_clip_chain: &ClipChainInstance, frame_state: &mut FrameBuildingState, prim_store: &mut PrimitiveStore, data_stores: &DataStores, segments_store: &mut SegmentStorage, segment_instances_store: &mut SegmentInstanceStorage, ) { - let prim_clip_chain = &prim_info.clip_chain; - // Usually, the primitive rect can be found from information // in the instance and primitive template. let mut prim_local_rect = LayoutRect::new( @@ -3592,7 +3676,7 @@ impl PrimitiveInstance { // Override the prim local rect with the dynamically calculated // local rect for the picture. - prim_local_rect = pic.local_rect; + prim_local_rect = pic.snapped_local_rect; segment_instance_index } else { @@ -3779,6 +3863,7 @@ impl PrimitiveInstance { frame_state, &mut data_stores.clip, unclipped, + prim_info.snap_offsets, device_pixel_scale, ); clip_mask_instances.push(clip_mask_kind); @@ -3799,7 +3884,10 @@ impl PrimitiveInstance { let segment_clip_chain = frame_state .clip_store .build_clip_chain_instance( - segment.local_rect.translate(self.prim_origin.to_vector()), + segment.local_rect.translate(LayoutVector2D::new( + self.prim_origin.x, + self.prim_origin.y, + )), &pic_state.map_local_to_pic, &pic_state.map_pic_to_world, &frame_context.clip_scroll_tree, @@ -3822,6 +3910,7 @@ impl PrimitiveInstance { frame_state, &mut data_stores.clip, unclipped, + prim_info.snap_offsets, device_pixel_scale, ); clip_mask_instances.push(clip_mask_kind); @@ -3860,7 +3949,7 @@ impl PrimitiveInstance { }; self.build_segments_if_needed( - &prim_info, + &prim_info.clip_chain, frame_state, prim_store, data_stores, @@ -3894,8 +3983,9 @@ impl PrimitiveInstance { // Get a minimal device space rect, clipped to the screen that we // need to allocate for the clip mask, as well as interpolated // snap offsets. - if let Some(device_rect) = get_clipped_device_rect( + if let Some((device_rect, snap_offsets)) = get_clipped_device_rect( &unclipped, + prim_info.snap_offsets, &pic_state.map_raster_to_world, prim_info.clipped_world_rect, device_pixel_scale, @@ -3909,6 +3999,7 @@ impl PrimitiveInstance { frame_state.resource_cache, frame_state.render_tasks, &mut data_stores.clip, + snap_offsets, device_pixel_scale, frame_context.fb_config, ); @@ -3931,6 +4022,80 @@ impl PrimitiveInstance { } } +/// Mimics the GLSL mix() function. +fn mix(x: f32, y: f32, a: f32) -> f32 { + x * (1.0 - a) + y * a +} + +/// Given a point within a local rectangle, and the device space corners +/// of a snapped primitive, return the snap offsets. +fn compute_snap_offset_impl( + reference_pos: Point2D, + reference_rect: Rect, + prim_top_left: DevicePoint, + prim_bottom_right: DevicePoint, +) -> DeviceVector2D { + let normalized_snap_pos = Point2D::::new( + (reference_pos.x - reference_rect.origin.x) / reference_rect.size.width, + (reference_pos.y - reference_rect.origin.y) / reference_rect.size.height, + ); + + let top_left = DeviceVector2D::new( + (prim_top_left.x + 0.5).floor() - prim_top_left.x, + (prim_top_left.y + 0.5).floor() - prim_top_left.y, + ); + + let bottom_right = DeviceVector2D::new( + (prim_bottom_right.x + 0.5).floor() - prim_bottom_right.x, + (prim_bottom_right.y + 0.5).floor() - prim_bottom_right.y, + ); + + DeviceVector2D::new( + mix(top_left.x, bottom_right.x, normalized_snap_pos.x), + mix(top_left.y, bottom_right.y, normalized_snap_pos.y), + ) +} + +/// Given the snapping offsets for a primitive rectangle, recompute +/// the snapping offsets to be relative to given local rectangle. +/// This *must* exactly match the logic in the GLSL +/// compute_snap_offset function. +pub fn recompute_snap_offsets( + local_rect: Rect, + prim_rect: Rect, + snap_offsets: SnapOffsets, +) -> SnapOffsets +{ + if prim_rect.is_empty() || snap_offsets.is_empty() { + return SnapOffsets::empty(); + } + + let normalized_top_left = Point2D::::new( + (local_rect.origin.x - prim_rect.origin.x) / prim_rect.size.width, + (local_rect.origin.y - prim_rect.origin.y) / prim_rect.size.height, + ); + + let normalized_bottom_right = Point2D::::new( + (local_rect.origin.x + local_rect.size.width - prim_rect.origin.x) / prim_rect.size.width, + (local_rect.origin.y + local_rect.size.height - prim_rect.origin.y) / prim_rect.size.height, + ); + + let top_left = DeviceVector2D::new( + mix(snap_offsets.top_left.x, snap_offsets.bottom_right.x, normalized_top_left.x), + mix(snap_offsets.top_left.y, snap_offsets.bottom_right.y, normalized_top_left.y), + ); + + let bottom_right = DeviceVector2D::new( + mix(snap_offsets.top_left.x, snap_offsets.bottom_right.x, normalized_bottom_right.x), + mix(snap_offsets.top_left.y, snap_offsets.bottom_right.y, normalized_bottom_right.y), + ); + + SnapOffsets { + top_left, + bottom_right, + } +} + /// Retrieve the exact unsnapped device space rectangle for a primitive. fn get_unclipped_device_rect( prim_rect: PictureRect, @@ -3949,10 +4114,11 @@ fn get_unclipped_device_rect( /// scale per-raster-root. fn get_clipped_device_rect( unclipped: &DeviceRect, + prim_snap_offsets: SnapOffsets, map_to_world: &SpaceMapper, prim_bounding_rect: WorldRect, device_pixel_scale: DevicePixelScale, -) -> Option { +) -> Option<(DeviceIntRect, SnapOffsets)> { let unclipped_raster_rect = { let world_rect = *unclipped * Scale::new(1.0); let raster_rect = world_rect * device_pixel_scale.inv(); @@ -3977,7 +4143,28 @@ fn get_clipped_device_rect( device_pixel_scale, ); - Some(clipped.to_i32()) + let fx0 = (clipped.origin.x - unclipped.origin.x) / unclipped.size.width; + let fy0 = (clipped.origin.y - unclipped.origin.y) / unclipped.size.height; + + let fx1 = (clipped.origin.x + clipped.size.width - unclipped.origin.x) / unclipped.size.width; + let fy1 = (clipped.origin.y + clipped.size.height - unclipped.origin.y) / unclipped.size.height; + + let top_left = DeviceVector2D::new( + mix(prim_snap_offsets.top_left.x, prim_snap_offsets.bottom_right.x, fx0), + mix(prim_snap_offsets.top_left.y, prim_snap_offsets.bottom_right.y, fy0), + ); + + let bottom_right = DeviceVector2D::new( + mix(prim_snap_offsets.top_left.x, prim_snap_offsets.bottom_right.x, fx1), + mix(prim_snap_offsets.top_left.y, prim_snap_offsets.bottom_right.y, fy1), + ); + + let snap_offsets = SnapOffsets { + top_left, + bottom_right, + }; + + Some((clipped.to_i32(), snap_offsets)) } pub fn get_raster_rects( @@ -4015,6 +4202,61 @@ pub fn get_raster_rects( Some((clipped.to_i32(), unclipped)) } +/// Snap the given rect in raster space if the transform is +/// axis-aligned. It return the snapped rect transformed back into the +/// given pixel space, and the snap offsets in device space. +pub fn get_snapped_rect( + prim_rect: Rect, + map_to_raster: &SpaceMapper, + device_pixel_scale: DevicePixelScale, +) -> Option<(Rect, SnapOffsets)> where PixelSpace: fmt::Debug { + let is_axis_aligned = match map_to_raster.kind { + CoordinateSpaceMapping::Local | + CoordinateSpaceMapping::ScaleOffset(..) => true, + CoordinateSpaceMapping::Transform(ref transform) => transform.preserves_2d_axis_alignment(), + }; + + if is_axis_aligned { + let raster_rect = map_to_raster.map(&prim_rect)?; + + let device_rect = { + let world_rect = raster_rect * Scale::new(1.0); + world_rect * device_pixel_scale + }; + + let top_left = compute_snap_offset_impl( + prim_rect.origin, + prim_rect, + device_rect.origin, + device_rect.bottom_right(), + ); + + let bottom_right = compute_snap_offset_impl( + prim_rect.bottom_right(), + prim_rect, + device_rect.origin, + device_rect.bottom_right(), + ); + + let snap_offsets = SnapOffsets { + top_left, + bottom_right, + }; + + let snapped_device_rect = DeviceRect::new( + device_rect.origin + top_left, + device_rect.size + (bottom_right - top_left).to_size() + ); + + let snapped_world_rect = snapped_device_rect / device_pixel_scale; + let snapped_raster_rect = snapped_world_rect * Scale::new(1.0); + let snapped_prim_rect = map_to_raster.unmap(&snapped_raster_rect)?; + Some((snapped_prim_rect, snap_offsets)) + } else { + None + } +} + /// Get the inline (horizontal) and block (vertical) sizes /// for a given line decoration. pub fn get_line_decoration_sizes( diff --git a/gfx/wr/webrender/src/render_backend.rs b/gfx/wr/webrender/src/render_backend.rs index 0338079cb09f..e04ef7c73ded 100644 --- a/gfx/wr/webrender/src/render_backend.rs +++ b/gfx/wr/webrender/src/render_backend.rs @@ -84,13 +84,6 @@ impl DocumentView { self.pinch_zoom_factor ) } - - pub fn accumulated_scale_factor_for_snapping(&self) -> DevicePixelScale { - DevicePixelScale::new( - self.device_pixel_ratio * - self.page_zoom_factor - ) - } } #[derive(Copy, Clone, Hash, MallocSizeOf, PartialEq, PartialOrd, Debug, Eq, Ord)] @@ -589,7 +582,6 @@ impl Document { self.clip_scroll_tree.update_tree( pan, - accumulated_scale_factor, &self.dynamic_properties, ); @@ -1758,8 +1750,6 @@ impl RenderBackend { config.serialize(doc.frame_builder.as_ref().unwrap(), file_name); let file_name = format!("scratch-{}-{}", id.namespace_id.0, id.id); config.serialize(&doc.scratch, file_name); - let file_name = format!("properties-{}-{}", id.namespace_id.0, id.id); - config.serialize(&doc.dynamic_properties, file_name); let file_name = format!("render-tasks-{}-{}.svg", id.namespace_id.0, id.id); let mut svg_file = fs::File::create(&config.file_path(file_name, "svg")) .expect("Failed to open the SVG file."); diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs index 73d6c9d7dbe8..cc83f3a9625c 100644 --- a/gfx/wr/webrender/src/render_target.rs +++ b/gfx/wr/webrender/src/render_target.rs @@ -663,6 +663,7 @@ impl RenderTarget for AlphaRenderTarget { task_info.actual_rect, &ctx.screen_world_rect, task_info.device_pixel_scale, + task_info.snap_offsets, target_rect.origin.to_f32(), task_info.actual_rect.origin.to_f32(), ); diff --git a/gfx/wr/webrender/src/render_task.rs b/gfx/wr/webrender/src/render_task.rs index a4739a40a999..3df2779a26df 100644 --- a/gfx/wr/webrender/src/render_task.rs +++ b/gfx/wr/webrender/src/render_task.rs @@ -14,7 +14,7 @@ use crate::filterdata::SFilterData; use crate::frame_builder::FrameBuilderConfig; use crate::freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; -use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind}; +use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind, SnapOffsets}; use crate::internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex, TextureSource}; use crate::prim_store::{PictureIndex, PrimitiveVisibilityMask}; use crate::prim_store::image::ImageCacheKey; @@ -125,6 +125,7 @@ pub struct CacheMaskTask { pub actual_rect: DeviceIntRect, pub root_spatial_node_index: SpatialNodeIndex, pub clip_node_range: ClipNodeRange, + pub snap_offsets: SnapOffsets, pub device_pixel_scale: DevicePixelScale, } @@ -522,6 +523,7 @@ impl RenderTask { resource_cache: &mut ResourceCache, render_tasks: &mut RenderTaskGraph, clip_data_store: &mut ClipDataStore, + snap_offsets: SnapOffsets, device_pixel_scale: DevicePixelScale, fb_config: &FrameBuilderConfig, ) -> Self { @@ -615,6 +617,7 @@ impl RenderTask { actual_rect: outer_rect, clip_node_range, root_spatial_node_index, + snap_offsets, device_pixel_scale, }), clear_mode, diff --git a/gfx/wr/webrender/src/renderer.rs b/gfx/wr/webrender/src/renderer.rs index 99381c143c9f..d49473376d86 100644 --- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -620,6 +620,11 @@ pub(crate) mod desc { count: 4, kind: VertexAttributeKind::F32, }, + VertexAttribute { + name: "aClipSnapOffsets", + count: 4, + kind: VertexAttributeKind::F32, + }, VertexAttribute { name: "aClipOrigins", count: 4, diff --git a/gfx/wr/webrender/src/spatial_node.rs b/gfx/wr/webrender/src/spatial_node.rs index 49c55a835943..6603bd9421d3 100644 --- a/gfx/wr/webrender/src/spatial_node.rs +++ b/gfx/wr/webrender/src/spatial_node.rs @@ -7,9 +7,9 @@ use api::{ExternalScrollId, PipelineId, PropertyBinding, PropertyBindingId, Refe use api::{TransformStyle, ScrollSensitivity, StickyOffsetBounds}; use api::units::*; use crate::clip_scroll_tree::{CoordinateSystem, CoordinateSystemId, SpatialNodeIndex, TransformUpdateState}; -use euclid::{Scale, SideOffsets2D}; +use euclid::SideOffsets2D; use crate::scene::SceneProperties; -use crate::util::{LayoutFastTransform, MatrixHelpers, ScaleOffset, TransformedRectKind, VectorHelpers}; +use crate::util::{LayoutFastTransform, MatrixHelpers, ScaleOffset, TransformedRectKind}; #[derive(Clone, Debug)] pub enum SpatialNodeType { @@ -38,10 +38,6 @@ pub struct SpatialNode { /// Content scale/offset relative to the coordinate system. pub content_transform: ScaleOffset, - /// Snapping scale/offset relative to the coordinate system. If None, then - /// we should not snap entities bound to this spatial node. - pub snapping_transform: Option, - /// The axis-aligned coordinate system id of this node. pub coordinate_system_id: CoordinateSystemId, @@ -106,23 +102,6 @@ fn compute_offset_from( offset } -/// Snap an offset to be incorporated into a transform, where the local space -/// may be considered the world space. We convert from world space to device -/// space using the global device pixel scale, which may not always be correct -/// if there are intermediate surfaces used, however those are either cases -/// where snapping is not important (e.g. has perspective or is not axis -/// aligned), or an edge case (e.g. SVG filters) which we can accept -/// imperfection for now. -fn snap_offset( - offset: LayoutVector2D, - global_device_pixel_scale: DevicePixelScale, -) -> LayoutVector2D { - let world_offset = offset * Scale::new(1.0); - let snapped_device_offset = (world_offset * global_device_pixel_scale).snap(); - let snapped_world_offset = snapped_device_offset / global_device_pixel_scale; - snapped_world_offset * Scale::new(1.0) -} - impl SpatialNode { pub fn new( pipeline_id: PipelineId, @@ -132,7 +111,6 @@ impl SpatialNode { SpatialNode { viewport_transform: ScaleOffset::identity(), content_transform: ScaleOffset::identity(), - snapping_transform: None, coordinate_system_id: CoordinateSystemId(0), transform_kind: TransformedRectKind::AxisAligned, parent: parent_index, @@ -265,7 +243,6 @@ impl SpatialNode { &mut self, state: &mut TransformUpdateState, coord_systems: &mut Vec, - global_device_pixel_scale: DevicePixelScale, scene_properties: &SceneProperties, previous_spatial_nodes: &[SpatialNode], ) { @@ -276,7 +253,7 @@ impl SpatialNode { return; } - self.update_transform(state, coord_systems, global_device_pixel_scale, scene_properties, previous_spatial_nodes); + self.update_transform(state, coord_systems, scene_properties, previous_spatial_nodes); //TODO: remove the field entirely? self.transform_kind = if self.coordinate_system_id.0 == 0 { TransformedRectKind::AxisAligned @@ -306,7 +283,6 @@ impl SpatialNode { &mut self, state: &mut TransformUpdateState, coord_systems: &mut Vec, - global_device_pixel_scale: DevicePixelScale, scene_properties: &SceneProperties, previous_spatial_nodes: &[SpatialNode], ) { @@ -349,7 +325,7 @@ impl SpatialNode { // between our reference frame and this node. Finally, we also include // whatever local transformation this reference frame provides. let relative_transform = resolved_transform - .post_translate(snap_offset(state.parent_accumulated_scroll_offset, global_device_pixel_scale)) + .post_translate(state.parent_accumulated_scroll_offset) .to_transform() .with_destination::(); @@ -424,13 +400,13 @@ impl SpatialNode { // provided by our own sticky positioning. let accumulated_offset = state.parent_accumulated_scroll_offset + sticky_offset; self.viewport_transform = state.coordinate_system_relative_scale_offset - .offset(snap_offset(accumulated_offset, global_device_pixel_scale).to_untyped()); + .offset(accumulated_offset.to_untyped()); // The transformation for any content inside of us is the viewport transformation, plus // whatever scrolling offset we supply as well. let added_offset = accumulated_offset + self.scroll_offset(); self.content_transform = state.coordinate_system_relative_scale_offset - .offset(snap_offset(added_offset, global_device_pixel_scale).to_untyped()); + .offset(added_offset.to_untyped()); if let SpatialNodeType::StickyFrame(ref mut info) = self.node_type { info.current_offset = sticky_offset; @@ -659,55 +635,6 @@ impl SpatialNode { } } - /// Updates the snapping transform. - pub fn update_snapping( - &mut self, - parent: Option<&SpatialNode>, - ) { - // Reset in case of an early return. - self.snapping_transform = None; - - // We need to incorporate the parent scale/offset with the child. - // If the parent does not have a scale/offset, then we know we are - // not 2d axis aligned and thus do not need to snap its children - // either. - let parent_scale_offset = match parent { - Some(parent) => { - match parent.snapping_transform { - Some(scale_offset) => scale_offset, - None => return, - } - }, - _ => ScaleOffset::identity(), - }; - - let scale_offset = match self.node_type { - SpatialNodeType::ReferenceFrame(ref info) => { - match info.source_transform { - PropertyBinding::Value(ref value) => { - // We can only get a ScaleOffset if the transform is 2d axis - // aligned. - match ScaleOffset::from_transform(value) { - Some(scale_offset) => { - let origin_offset = info.origin_in_parent_reference_frame; - ScaleOffset::from_offset(origin_offset.to_untyped()) - .accumulate(&scale_offset) - } - None => return, - } - } - - // Assume animations start at the identity transform for snapping purposes. - // TODO(aosmond): Is there a better known starting point? - PropertyBinding::Binding(..) => ScaleOffset::identity(), - } - } - _ => ScaleOffset::identity(), - }; - - self.snapping_transform = Some(parent_scale_offset.accumulate(&scale_offset)); - } - /// Returns true for ReferenceFrames whose source_transform is /// bound to the property binding id. pub fn is_transform_bound_to_property(&self, id: PropertyBindingId) -> bool { @@ -923,7 +850,7 @@ fn test_cst_perspective_relative_scroll() { pipeline_id, ); - cst.update_tree(WorldPoint::zero(), DevicePixelScale::new(1.0), &SceneProperties::new()); + cst.update_tree(WorldPoint::zero(), &SceneProperties::new()); let scroll_offset = compute_offset_from( cst.spatial_nodes[ref_frame.0 as usize].parent, diff --git a/gfx/wr/webrender/src/util.rs b/gfx/wr/webrender/src/util.rs index 28b1932e2758..e8c7095002e5 100644 --- a/gfx/wr/webrender/src/util.rs +++ b/gfx/wr/webrender/src/util.rs @@ -166,13 +166,6 @@ impl ScaleOffset { }) } - pub fn from_offset(offset: default::Vector2D) -> Self { - ScaleOffset { - scale: Vector2D::new(1.0, 1.0), - offset, - } - } - pub fn inverse(&self) -> Self { ScaleOffset { scale: Vector2D::new( @@ -195,15 +188,6 @@ impl ScaleOffset { ) } - pub fn scale(&self, scale: f32) -> Self { - self.accumulate( - &ScaleOffset { - scale: Vector2D::new(scale, scale), - offset: Vector2D::zero(), - } - ) - } - /// Produce a ScaleOffset that includes both self and other. /// The 'self' ScaleOffset is applied after other. /// This is equivalent to `Transform3D::pre_transform`. @@ -421,29 +405,12 @@ impl MatrixHelpers for Transform3D { } } -pub trait PointHelpers -where - Self: Sized, -{ - fn snap(&self) -> Self; -} - -impl PointHelpers for Point2D { - fn snap(&self) -> Self { - Point2D::new( - (self.x + 0.5).floor(), - (self.y + 0.5).floor(), - ) - } -} - pub trait RectHelpers where Self: Sized, { fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self; fn is_well_formed_and_nonempty(&self) -> bool; - fn snap(&self) -> Self; } impl RectHelpers for Rect { @@ -457,36 +424,6 @@ impl RectHelpers for Rect { fn is_well_formed_and_nonempty(&self) -> bool { self.size.width > 0.0 && self.size.height > 0.0 } - - fn snap(&self) -> Self { - let origin = Point2D::new( - (self.origin.x + 0.5).floor(), - (self.origin.y + 0.5).floor(), - ); - Rect::new( - origin, - Size2D::new( - (self.origin.x + self.size.width + 0.5).floor() - origin.x, - (self.origin.y + self.size.height + 0.5).floor() - origin.y, - ), - ) - } -} - -pub trait VectorHelpers -where - Self: Sized, -{ - fn snap(&self) -> Self; -} - -impl VectorHelpers for Vector2D { - fn snap(&self) -> Self { - Vector2D::new( - (self.x + 0.5).floor(), - (self.y + 0.5).floor(), - ) - } } pub fn lerp(a: f32, b: f32, t: f32) -> f32 { diff --git a/gfx/wr/webrender_api/src/display_item.rs b/gfx/wr/webrender_api/src/display_item.rs index 7503cdff39dd..ee79b5a3c435 100644 --- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -104,7 +104,6 @@ pub enum DisplayItem { Gradient(GradientDisplayItem), RadialGradient(RadialGradientDisplayItem), Image(ImageDisplayItem), - RepeatingImage(RepeatingImageDisplayItem), YuvImage(YuvImageDisplayItem), BackdropFilter(BackdropFilterDisplayItem), @@ -149,7 +148,6 @@ pub enum DebugDisplayItem { Gradient(GradientDisplayItem), RadialGradient(RadialGradientDisplayItem), Image(ImageDisplayItem), - RepeatingImage(RepeatingImageDisplayItem), YuvImage(YuvImageDisplayItem), BackdropFilter(BackdropFilterDisplayItem), @@ -1073,28 +1071,10 @@ pub struct IframeDisplayItem { pub ignore_missing_pipeline: bool, } -/// This describes an image that fills the specified area. It stretches or shrinks -/// the image as necessary. While RepeatingImageDisplayItem could otherwise provide -/// a superset of the functionality, it has been problematic inferring the desired -/// repetition properties when snapping changes the size of the primitive. +/// This describes an image or, more generally, a background-image and its tiling. +/// (A background-image repeats in a grid to fill the specified area). #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ImageDisplayItem { - pub common: CommonItemProperties, - /// The area to tile the image over (first tile starts at origin of this rect) - // FIXME: this should ideally just be `tile_origin` here, with the clip_rect - // defining the bounds of the item. Needs non-trivial backend changes. - pub bounds: LayoutRect, - pub image_key: ImageKey, - pub image_rendering: ImageRendering, - pub alpha_type: AlphaType, - /// A hack used by gecko to color a simple bitmap font used for tofu glyphs - pub color: ColorF, -} - -/// This describes a background-image and its tiling. It repeats in a grid to fill -/// the specified area. -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] -pub struct RepeatingImageDisplayItem { pub common: CommonItemProperties, /// The area to tile the image over (first tile starts at origin of this rect) // FIXME: this should ideally just be `tile_origin` here, with the clip_rect @@ -1426,7 +1406,6 @@ impl DisplayItem { DisplayItem::Gradient(..) => "gradient", DisplayItem::Iframe(..) => "iframe", DisplayItem::Image(..) => "image", - DisplayItem::RepeatingImage(..) => "repeating_image", DisplayItem::Line(..) => "line", DisplayItem::PopAllShadows => "pop_all_shadows", DisplayItem::PopReferenceFrame => "pop_reference_frame", diff --git a/gfx/wr/webrender_api/src/display_list.rs b/gfx/wr/webrender_api/src/display_list.rs index 2e6426a5630b..e0875af5417b 100644 --- a/gfx/wr/webrender_api/src/display_list.rs +++ b/gfx/wr/webrender_api/src/display_list.rs @@ -623,7 +623,6 @@ impl Serialize for BuiltDisplayList { Real::HitTest(v) => Debug::HitTest(v), Real::Line(v) => Debug::Line(v), Real::Image(v) => Debug::Image(v), - Real::RepeatingImage(v) => Debug::RepeatingImage(v), Real::YuvImage(v) => Debug::YuvImage(v), Real::Border(v) => Debug::Border(v), Real::BoxShadow(v) => Debug::BoxShadow(v), @@ -728,7 +727,6 @@ impl<'de> Deserialize<'de> for BuiltDisplayList { Debug::HitTest(v) => Real::HitTest(v), Debug::Line(v) => Real::Line(v), Debug::Image(v) => Real::Image(v), - Debug::RepeatingImage(v) => Real::RepeatingImage(v), Debug::YuvImage(v) => Real::YuvImage(v), Debug::Border(v) => Real::Border(v), Debug::BoxShadow(v) => Real::BoxShadow(v), @@ -1003,27 +1001,6 @@ impl DisplayListBuilder { } pub fn push_image( - &mut self, - common: &di::CommonItemProperties, - bounds: LayoutRect, - image_rendering: di::ImageRendering, - alpha_type: di::AlphaType, - key: ImageKey, - color: ColorF, - ) { - let item = di::DisplayItem::Image(di::ImageDisplayItem { - common: *common, - bounds, - image_key: key, - image_rendering, - alpha_type, - color, - }); - - self.push_item(&item); - } - - pub fn push_repeating_image( &mut self, common: &di::CommonItemProperties, bounds: LayoutRect, @@ -1034,7 +1011,7 @@ impl DisplayListBuilder { key: ImageKey, color: ColorF, ) { - let item = di::DisplayItem::RepeatingImage(di::RepeatingImageDisplayItem { + let item = di::DisplayItem::Image(di::ImageDisplayItem { common: *common, bounds, image_key: key, diff --git a/gfx/wr/wrench/reftests/border/degenerate-curve.png b/gfx/wr/wrench/reftests/border/degenerate-curve.png index 9c3805e33e58fd0a756bc8a2e77d752471958a13..d8ef6f37bca03bf9b4e0afa9affd35c4f01acf51 100644 GIT binary patch literal 21390 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 literal 20581 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

0euEXl<=hIMX7m~gn37g>O%|e`tVq(Wu^g9P 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 RfG1`%c)I$ztaD0e0s!$)aC-m% diff --git a/gfx/wr/wrench/reftests/boxshadow/inset-subpx.png b/gfx/wr/wrench/reftests/boxshadow/inset-subpx.png index b15cf63d80c0a27c4c663a358945c370ebdb2fe3..f7c9b29084c10a6d83dfda3a1ee050a6b1ae19a9 100644 GIT binary patch literal 1258 zcmeAS@N?(olHy`uVBq!ia0vp^n}N8EgAGVdTfF-%0|U!OPZ!6KiaBp@-R=~L6>Ga}ftL5HT?=PylDyKpTk72Wug$UPRm;-*4Nfo0 zwfUW2IDtuGbJ8$D#TRehEV68TJpc3ZqGNap1@Zt~2`s#O2kM}<{5=_>+ zWxU{Rp4~k@i|xia_V2#@{arM(!%+OKDBrO>zh{@0-k;BN?B?6s+aYST=WLulS@Fi{ z>H2oZKiIH6e)Hw)YlwQmvo}tj6nI;rzJ$p+{2;`ixH@02JGEH_Aa zF7a+hi`Nbw!T8-}b~evG^PGQLz3uYL&(FbTzv4@K^H}AapwUI4_r22Xhrhmlee#24 z+xpKjZSPYJ&hgE+(*+xpu9I+IBI#aR&F5!U+w+TY)Pl`eYzvqs)pqUUq`-unGuGh-Jfym_?FCP^*8>FGP~J!clX zzqYB^V5gR`&+m(JT3Ju+<3Hi=??GG`u90wEqA8_gW&r230(tv?r5&?&f8Aj%f81u- z;oI9!rz#zbxgyGS!?X=(`)*xB;Wvldvk&;sU-$XR$zL;0bk3d8Isg4_n$qAF+`Js^V#l?J@jr@NCh!fE!08iung#C`M%Sf6M*n gW{4i9HhNs|y)3CWuXJG{unc4HboFyt=akR{05TI=k^lez literal 1810 zcmeAS@N?(olHy`uVBq!ia0vp^n}N8EgAGVdTfF-%0|VPlPZ!6KiaBp@pIj^IDbV`R zoBzyb9&4Ke9BU5n-Z{X#<^YGy0fuR7CPb86U%pzvdG%E8cxU@6PS5eLaA87IfXB|<4hvYM9UsUqjp1=X9jJjE-$h$X3&>WVZY3I0Bc2E6&+cKAwxFx}2S8Vcca7DK6312_Y@A|sGJFLp} zUumzXl-*Ok9j0VP_{V8qkEv=Vc2++=X8-ukUaPOazJ%|p_+19EXSt4n|DH%s&w%+t z_YPfOKi|(hf1cm={QB;_#ou3Dd3`y*ujJ#iv)^tAPOO~h7nvm{*gA#f>owIkYopT} z-`}&H`|hsw`fum%t`1)Bzkk8Ae_HF~^T9rUDa2~p-SSA++i$+0o%*{wmfSV}|GoV3 z;9%v}@^^7_t7?C-ntl(j{F()E#&ivX)sNnKc@r3(zQ9uDGye@xD);pCn>1iAs*(-)TH!&TYA0?Sl2Oly85}Sb4q9e0B5gW3jhEB diff --git a/gfx/wr/wrench/reftests/boxshadow/scale.png b/gfx/wr/wrench/reftests/boxshadow/scale.png index 49aa8e8e053c0cb268ddfc9462413da76678b7e2..30d171a618ae0727291f87a8b0aff4763433d8d0 100644 GIT binary patch literal 13536 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 b&O}ADntM&~gvvwSiAAZe7Npoj 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 U4NcBZ1U?J$aND(`U>iE=ue+k|@Bjb+ diff --git a/gfx/wr/wrench/reftests/clip/clip-45-degree-rotation-ref.png b/gfx/wr/wrench/reftests/clip/clip-45-degree-rotation-ref.png index 5f2170f3e60ba23f0b14965fd0d8a90f5756e4ad..7f52f7acbaf190b8c48a40891bfe2342b30401f9 100644 GIT binary patch literal 4314 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 literal 4228 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 literal 763 zcmeAS@N?(olHy`uVBq!ia0vp^Yk+to2OE%#tPGpWz`%6K)5S5QV$R!38wC$D@Ekr+ z@qeML{{g98zrzAGQ#QiPwN o&T@`v!7QgWo1Tgc1L2>{2?mFFj!GTx114$)Pgg&ebxsLQ0Qw0&wg3PC diff --git a/gfx/wr/wrench/reftests/filters/backdrop-filter-perspective.png b/gfx/wr/wrench/reftests/filters/backdrop-filter-perspective.png index a555a1c5839a22294c6b7db3cbe878281e3458d1..ef24c5c4f3635a2b5d0e0b1ecceceb7b6676fe95 100644 GIT binary patch delta 56705 zcmb??WmHw)7p*AWA>EB4A>ExKpdgp-hD&!INTS|mWbLmF98!n-AhrlH+@$~oq z^gg~Z-u}GCKKtyw&YW}2y-xDNi~YG535>u&wX&S_C-3Z|9JFj^`G%(n)nq}m9u`k! z6Buk|f`8+jM~dk(5{Uda(vTPm z6y^SnHf($h@&7_MEQ6Hx{);5wdLbth|6iatIUS+ze}R1?&k`pY|BEz2{lDk@f0^>{ z^Z&oj31k#hRjub5)b^!T=va>Up@CIvtlBe3*h!WlsT}E+7go(}bG*7EB$%M8uMneh zAVX^;wG5O{+wdu(0%BByahnN|g!WohO3sxyRCjo|yE}*d_dXs3iIc`5-=({vY5Yb{ z{P#Zk*>GFSnwRQ9?c0c#MJlXx%bgY38?X~SW>z7IT2o)EU9t{Bj6p1gZH~HM!7nMK zcL#YhTF%M3B8o9@wJSs>?Qi+jmw?Ononu*b1rE@2D)uvH{Qpj7gP!nC<(W$An})*^ zJ(Fu~kvF`SCBz~FI#KcsgU#Qtj*{w>_Q03RcOy6=Zp`4N}kL?gmYv%=#58#;VZ(ZUP*F%RGqG|n%pN31KO z&+`*#)GE^#eu#*C;hgX?&mx!Tw_eY*0Y(;WeZuz!2K5gTX*E>rchB|VDY+?7qiY6H z_wps^e!ts)8x(ot^>^7KA$}*uCZv+pv#5gU_8ipa6@#hG=xu|wl(Ry`)^gIP3JSVs@x!a)oZd%Y?Z81lL7tRt=tD@__kHT95AL9W< zLEWj!@TM^fyo3tVsf3Iuw{;p|!S+@#2$~`(82@FDZ_XqmZaSnZxfG)d6#U0 ze#YVgx~oyyA)j6pWz)6m2TX4NvbWJALLzt>0ko11hi{saE4-nMhgR$#}UcKxWYwcKxb^kX3&@9hIN z97jIAn-@3tr{e1@Wx zPnFK}#dVU%Tt>J^Zi{oaykf4!o)unUe|y=Hvy}jGxCK8^z*?S6{SFHdgo-BrV4+VE zXUBYOkl+b-Z($_R?RL&{qNy3QM`a(HA|hvW?X{`**&c;c=2}bG%QRVKqS^pxwz

M_HD(q`Z?@!3E0?45 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 delta 57011 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
? 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

QPd&4+N88LyKC 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 diff --git a/gfx/wr/wrench/reftests/filters/filter-drop-shadow-clip.png b/gfx/wr/wrench/reftests/filters/filter-drop-shadow-clip.png index 543ffe227fc5cb9a6d592215e14d4763f9dad1f7..7e36607b04bcceffac9372814d976f1f9f969ba4 100644 GIT binary patch literal 11151 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 diff --git a/gfx/wr/wrench/reftests/performance/no-clip-mask.yaml b/gfx/wr/wrench/reftests/performance/no-clip-mask.yaml index 51d981e2a070..4cd41b177ea1 100644 --- a/gfx/wr/wrench/reftests/performance/no-clip-mask.yaml +++ b/gfx/wr/wrench/reftests/performance/no-clip-mask.yaml @@ -21,4 +21,3 @@ pipelines: bounds: [1075, -1, 12, 199] "clip-rect": [1075, -1, 12, 199] image: checkerboard(4, 8, 8) - stretch-size: 72 72 diff --git a/gfx/wr/wrench/reftests/transforms/near-plane-clip.yaml b/gfx/wr/wrench/reftests/transforms/near-plane-clip.yaml index 99cc121de713..bb12f35d1381 100644 --- a/gfx/wr/wrench/reftests/transforms/near-plane-clip.yaml +++ b/gfx/wr/wrench/reftests/transforms/near-plane-clip.yaml @@ -15,4 +15,3 @@ root: - bounds: [350, 200, 260, 300] image: checkerboard(2, 16, 16) - stretch-size: 260 260 diff --git a/gfx/wr/wrench/reftests/transforms/nested-preserve-3d.png b/gfx/wr/wrench/reftests/transforms/nested-preserve-3d.png index 3b74c198999e0d4f5f18af27655c9cfb5f8376bb..102ed077b6862077b415096aa92e79714acb2265 100644 GIT binary patch delta 604 zcmew+`%QL(1cw>JLKis;w|{s4J8Z50YCjXiahWISBA393kD7dkOIpzRXu8RBp~|#~ zv?to%0-rQ4ob1V|HQ9qxtp45I*U3+Rezp^He=;+1=EU_k+$Xa42~JFJOLg1Vbb|SK z#|h)+6U;gd#8TD|E-$wW(~EzXTnKd4G|8V`wIY=XD}MAmi%~kybGoPIs9l$hL5R%M zonS{#-o~X{FY2DEH!+=UB750^oyE0lYX06j{;0#oSjYI2=x>cr2Mm=yo!M~aM7TiZ z0|~*(G=a(nRsqte1on`c#B87)AYUcPyUIyu?VD;l{eKr1&963I2Fn)jcb>pW$mGa%n5P!T`e1aJxLLRL+qx$KL z!l%iBoJydG@sYEAmHhPMW6C3j;dswx9qw(+BAkwy>v^U;QD*=GPgg&ebxsLQ0Ipj0 A6951J delta 616 zcmew+`%QL(1V@UD^8a`B3vTWIHQz^xUq)H!JdYCp1_olOHx2InzalFC?C3u#SeX`) z_C)(z;FHFMkBny(ciI^17=IG|t?}u=#{Kj zsc|dTo0#5~>b5UQ-c?RQtM60{*i(~da41dg=Mb%baA&7o*uJ{A$%QWSB&SLK?5Y*1 zd>{e!MTbp6Plt_hhs^;d5~&T$TKhJbPKWqsW4{tVkLdkV^SqzTOq@A!{SEht>}_3( zjeydVk8w!>-JwwblCPX>R*j@hn#*Xs! z{Z|ER(jwA7to|POp>g4_;CWwJ=1X3a{PU_-q$Xj-qF#cR5hLFY2t6OtlZS!>p%Zjge=4bRr0Lz7ETa{XEpK5D1w!3 zFd~s^S@~~MxGlm+iBnC=1C-OQpoIgZ?7%5vDS>Ct&f1yD*}g(HFk!{NDd|YAVw9N7$t5>=28X;4wm4LF pfjC%=gw()rz`kX(GWS7dk#|RO*GzkL`56Ncc)I$ztaD0e0stofAYuRj delta 658 zcmew%`$KkvJV*Tj!B6l1v9J2O`v1@8!Zi;#1Z&a+Y8s{zODUYWySp~$&hG2SUvbzO zuQC2{^|!{40|9?E&sQ~_=XuRj_tlQe&LBj728i3l-?Gxq;48~~NfvpI;M#;&oOY8H zxL77n<&dv8&;PdZZE) zqe1@tZyO8W#h@7I{B^m_YfdD0g56-uVJ84|gXZKIPOkbnHaCwSTkc=GrVnEG-u@skJIEd(Ng{P9r2gjWc?ctUuHJvQP95P@=dX<`fn0^j%Q?g+|KXIY z|NJdiUi$gDuN$op;aJcD4PzF03ny?WCZrNeaTI?}lb7z7Lov`Gr2f=q6j!k?19F=m zFi-x?sTs2D*MTd-p!9$}mIaj{?k6hQFg%cV`oO5ruvwY=AhXDt4Y_Ong(QSA0D-5g KpUXO@geCynts_4G diff --git a/gfx/wr/wrench/reftests/transforms/perspective-clip-1.png b/gfx/wr/wrench/reftests/transforms/perspective-clip-1.png index bf8a9729b97e9e857f2db8551bc84c92b8f35951..4a8464b71634e2b18fb545cf49625387800ddd56 100644 GIT binary patch delta 1021 zcmXw&eN0nV7{;N9brM>18^%Flh|xblFhl`GX+|Ln3qhvb7RtI}K$t*_8x#-%mrPd1 zvf;EFA5MY#f#crNilt!Dwz`es0O_6VLMhOW0kgYWu8c2R`?1@Go#g!Wym`*^KKY$L zsV3^TdqG)p;(O^8SIsk=FBb*0p=Df&?Fo~U!%y>K!b3S14)tFDH{|43H+PcY@3GE3 z@coD=xguf!{u=B2$=vX8`wisaVe!e)4j?q=YzpI2&}c#NgQv#UlDyIxGRvX4W?7zF zd#A-hiIopsA-&s#c-6gGS$i&lD&OwO@f7)ySj44*ZQJZc6Ka~FJ0CDl z0fJd?VB?xD=v?B*j!CHBdA(q=4VrX_kH_vDQFx>X62+RiZlD>L4wy&FvM=}B2C!i* zQ?(o;sBr5##EC0`U?&?brz4cowcm@=tL-_w*zXqE9-T*XP52Qd#-Vd;3#JzCylr6? z0H>FV>u92B@*mg_0m_d z(J>WF?2%$3myY}Z8%jrVc%+uVR1^7-vlm(6XK;KT<|fcPM$~D7#WU_n`K2usPf^E~ zcF@#W0*$H93J!RP-mus5K@PgRUq+M`B@RZ08zFPprgN{e1{F01Eaa8R9Tj_dL* z>Key?wAy$79~R_qNXobdVhL7!=30ZS?{trU?Qatd=LS!%F9QQ~QCbU#R_|vXchb#w zG6*m5xmY$OiC`wHaD}Q9vGe z^*9DrziNf%gZTA~Oc!9ceeGB7pU9k<<(7Pi{yd~09}A6iypL9a>4JX%V86ML+BWvt z0gqF(PfhJFq^EYxY06*!#eUW}KE0PQVSXUTGA}Y!FS#x-Q&lhqfP78GJ~w&|h?ifo hXa|W&e5pwPnfV=YiioZ>81f)aa#CudG$H%*{{V8lBuoGR delta 1001 zcmaFC|A2pjO8s(A7srr_IdAXeuDDk!d;H^j*2sjs5T6-0l&T&u-&Ok5_U2-jm(d9> zqnwMpVFH;`T+O`{TFRUwmk5Rgad;c8;L%yL!uC{#+Qnu3H3Aof*t@$bnO`#hjeWkW z>`tM%-@pBD|NQt+#e3{~x$WNrvkzOg8&|K=WJuz)b+A~-&Y?b8lgW1Dg?7gJcQY@X zPkXyR`S$juudZpY&fCA})xqLh>~l6;mS10WSbmk=r@yOCzsr%I)A3Y?A=ozk#sANn zR=r-oe%H@ei<*n&SL}MYYgPH5MYetEmfQzIj`RMF&0qcN1OKXT`FZ@iZf)HBYPbCA zTOT~CWzH6fHLUED{55;s%3oj1Zyog9oa=v8zy5yQ*HiUZCQjST;8S|#LjBv#q4R%d zSzEk}`}%!V?CsUt-mKmVmUDUWe#f3yw)UCq%g?ZW4|}_BgKT^BIVOXvvo8GqEZUu~ zE_3I`y*WYQ_hY`k_22S%0?4&%IsZN_5BdA$?%TB3JH>@pU;n$(w-YSUR`=a?^R5@? z-_|GG-SgBuv^@S&-_D~t43pQk{j0T3-&*W$9T8r=Ej0J;?LMe*&+)XcH@a^h-1X~E z_^N$>TFZ3O7-!^|e%bu3|7-cZzoFIJwQ8|WpqFU+(4SG{g) zhH|V5(ylIJhRYc4WcPj_HIp^LX!1vv-IE`%oB?9pdRdFjS(h89Mlz@g|6-KA6S4K- zgHu4aasF+XXS4PdtN*$)Oa?PA@Tc9Lw`%|1U9#Okh0(l!+uYN?zL0#I5F1;ae3ke5 zR*KEOb?>a@*YA2Y zt*qeEo^ShBS?jN^s{gtF*5jMtSU+>&{NHb9L&NVyZO!+tzHqg@E~4~wXy|hLdvflZ zK?Xc-tIPXW9=`9((N*i~m)XvEV_Ls<*T-8&*9Xa62PL?9#$Vds0Mo=`{;;=q0=JfD zf3(T5iTJwgerWBN>d@(T?%G)ho{nT#X7%ubeBQs%e}~gU|7uhRUsaY~RrmkcH^tT4 z-mj{<_||;8nXZZ diff --git a/gfx/wr/wrench/reftests/transforms/perspective-shadow.png b/gfx/wr/wrench/reftests/transforms/perspective-shadow.png index b065ab9a0ebe2e133041f992bce7311459e431a1..dbf323e536c38cb4892184b68d784d7760529946 100644 GIT binary patch literal 10583 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 literal 10536 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 RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(64.0, 64.0), + size2(64.0, 64.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, img, @@ -190,6 +192,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(1024.0, 1024.0), + size2(1024.0, 1024.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, img, @@ -214,6 +218,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(1024.0, 1024.0), + size2(1024.0, 1024.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, img, @@ -249,7 +255,7 @@ impl<'a> RawtestHarness<'a> { let info = self.make_common_properties(rect(448.899994, 74.0, 151.000031, 56.)); // setup some malicious image size parameters - builder.push_repeating_image( + builder.push_image( &info, info.clip_rect, size2(151., 56.0), @@ -329,7 +335,7 @@ impl<'a> RawtestHarness<'a> { }; // setup some malicious image size parameters - builder.push_repeating_image( + builder.push_image( &info, info.clip_rect, image_size * 2., @@ -434,7 +440,7 @@ impl<'a> RawtestHarness<'a> { Some(100), ); - builder.push_repeating_image( + builder.push_image( &info, info.clip_rect, image_size, @@ -471,7 +477,7 @@ impl<'a> RawtestHarness<'a> { Some(100), ); - builder.push_repeating_image( + builder.push_image( &info, info.clip_rect, image_size, @@ -526,7 +532,7 @@ impl<'a> RawtestHarness<'a> { let image_size = size2(1510., 1510.); // setup some malicious image size parameters - builder.push_repeating_image( + builder.push_image( &info, info.clip_rect, image_size, @@ -552,7 +558,7 @@ impl<'a> RawtestHarness<'a> { let image_size = size2(1510., 1510.); // setup some malicious image size parameters - builder.push_repeating_image( + builder.push_image( &info, info.clip_rect, image_size, @@ -584,7 +590,7 @@ impl<'a> RawtestHarness<'a> { let image_size = size2(1510., 1510.); // setup some malicious image size parameters - builder.push_repeating_image( + builder.push_image( &info, info.clip_rect, image_size, @@ -650,6 +656,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(200.0, 200.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, blob_img.as_image(), @@ -672,6 +680,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(200.0, 200.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, blob_img.as_image(), @@ -757,6 +767,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(200.0, 200.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, blob_img.as_image(), @@ -765,6 +777,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info2, info2.clip_rect, + size2(200.0, 200.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, blob_img2.as_image(), @@ -856,6 +870,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(200.0, 200.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, blob_img.as_image(), @@ -883,6 +899,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(200.0, 200.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, blob_img.as_image(), @@ -908,6 +926,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(200.0, 200.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, blob_img.as_image(), @@ -1106,6 +1126,8 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, info.clip_rect, + size2(150.0, 50.0), + size2(0.0, 0.0), ImageRendering::Auto, AlphaType::PremultipliedAlpha, image, diff --git a/gfx/wr/wrench/src/yaml_frame_reader.rs b/gfx/wr/wrench/src/yaml_frame_reader.rs index 77d9aaba00b9..acab7fca4b08 100644 --- a/gfx/wr/wrench/src/yaml_frame_reader.rs +++ b/gfx/wr/wrench/src/yaml_frame_reader.rs @@ -1374,6 +1374,10 @@ impl YamlFrameReader { item["bounds"] ); }; + let stretch_size = item["stretch-size"].as_size().unwrap_or(image_dims); + let tile_spacing = item["tile-spacing"] + .as_size() + .unwrap_or(LayoutSize::new(0.0, 0.0)); let rendering = match item["rendering"].as_str() { Some("auto") | None => ImageRendering::Auto, Some("crisp-edges") => ImageRendering::CrispEdges, @@ -1391,29 +1395,16 @@ impl YamlFrameReader { item ), }; - let stretch_size = item["stretch-size"].as_size(); - let tile_spacing = item["tile-spacing"].as_size(); - if stretch_size.is_none() && tile_spacing.is_none() { - dl.push_image( - &info, - bounds, - rendering, - alpha_type, - image_key, - ColorF::WHITE, - ); - } else { - dl.push_repeating_image( - &info, - bounds, - stretch_size.unwrap_or(image_dims), - tile_spacing.unwrap_or(LayoutSize::zero()), - rendering, - alpha_type, - image_key, - ColorF::WHITE, - ); - } + dl.push_image( + &info, + bounds, + stretch_size, + tile_spacing, + rendering, + alpha_type, + image_key, + ColorF::WHITE, + ); } fn handle_text( diff --git a/gfx/wr/wrench/src/yaml_frame_writer.rs b/gfx/wr/wrench/src/yaml_frame_writer.rs index b3f37bea6de6..6c1c8939f579 100644 --- a/gfx/wr/wrench/src/yaml_frame_writer.rs +++ b/gfx/wr/wrench/src/yaml_frame_writer.rs @@ -1053,29 +1053,6 @@ impl YamlFrameWriter { } } DisplayItem::Image(item) => { - common_node(&mut v, clip_id_mapper, &item.common); - rect_node(&mut v, "bounds", &item.bounds); - if let Some(path) = self.path_for_image(item.image_key) { - path_node(&mut v, "image", &path); - } - if let Some(&CachedImage { - tiling: Some(tile_size), - .. - }) = self.images.get(&item.image_key) - { - u32_node(&mut v, "tile-size", tile_size as u32); - } - match item.image_rendering { - ImageRendering::Auto => (), - ImageRendering::CrispEdges => str_node(&mut v, "rendering", "crisp-edges"), - ImageRendering::Pixelated => str_node(&mut v, "rendering", "pixelated"), - }; - match item.alpha_type { - AlphaType::PremultipliedAlpha => str_node(&mut v, "alpha-type", "premultiplied-alpha"), - AlphaType::Alpha => str_node(&mut v, "alpha-type", "alpha"), - }; - } - DisplayItem::RepeatingImage(item) => { common_node(&mut v, clip_id_mapper, &item.common); rect_node(&mut v, "bounds", &item.bounds); if let Some(path) = self.path_for_image(item.image_key) { diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index e9ddf9fa4d6e..168fbacca085 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -6967,46 +6967,17 @@ IntSize nsLayoutUtils::ComputeImageContainerDrawingParameters( } } - // Attempt to snap pixels, the same as ComputeSnappedImageDrawingParameters. - // Any changes to the algorithm here will need to be reflected there. - bool snapped = false; - gfxSize gfxLayerSize; - const gfx::Matrix& itm = aSc.GetInheritedTransform(); - if (!itm.HasNonAxisAlignedTransform() && itm._11 > 0.0 && itm._22 > 0.0) { - gfxRect rect(gfxPoint(aDestRect.X(), aDestRect.Y()), - gfxSize(aDestRect.Width(), aDestRect.Height())); + // Compute our size in layer pixels. We may need to revisit this for Android + // because mobile websites are rarely displayed at a 1:1 + // LayoutPixel:ScreenPixel ratio and the snapping here may be insufficient. + const LayerIntSize layerSize = + RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width, + aDestRect.Height() * scaleFactors.height)); - gfxPoint p1 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopLeft()))); - gfxPoint p2 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopRight()))); - gfxPoint p3 = ThebesPoint(itm.TransformPoint(ToPoint(rect.BottomRight()))); - - if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) { - p1.Round(); - p3.Round(); - - rect.MoveTo(gfxPoint(std::min(p1.x, p3.x), std::min(p1.y, p3.y))); - rect.SizeTo(gfxSize(std::max(p1.x, p3.x) - rect.X(), - std::max(p1.y, p3.y) - rect.Y())); - - // An empty size is unacceptable so we ensure our suggested size is at - // least 1 pixel wide/tall. - gfxLayerSize = - gfxSize(std::max(rect.Width(), 1.0), std::max(rect.Height(), 1.0)); - snapped = true; - } - } - - if (!snapped) { - // Compute our size in layer pixels. - const LayerIntSize layerSize = - RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width, - aDestRect.Height() * scaleFactors.height)); - - // An empty size is unacceptable so we ensure our suggested size is at least - // 1 pixel wide/tall. - gfxLayerSize = - gfxSize(std::max(layerSize.width, 1), std::max(layerSize.height, 1)); - } + // An empty size is unacceptable so we ensure our suggested size is at least + // 1 pixel wide/tall. + gfxSize gfxLayerSize = + gfxSize(std::max(layerSize.width, 1), std::max(layerSize.height, 1)); return aImage->OptimalImageSizeForDest( gfxLayerSize, imgIContainer::FRAME_CURRENT, samplingFilter, aFlags); diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index a7f8d8ce024d..8fec7d6d8ac3 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -134,11 +134,11 @@ bool nsDisplayButtonBoxShadowOuter::CreateWebRenderCommands( nsRect shadowRect = nsRect(ToReferenceFrame(), mFrame->GetSize()); LayoutDeviceRect deviceBox = LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel); - wr::LayoutRect deviceBoxRect = wr::ToLayoutRect(deviceBox); + wr::LayoutRect deviceBoxRect = wr::ToRoundedLayoutRect(deviceBox); LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(GetPaintRect(), appUnitsPerDevPixel); - wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect); + wr::LayoutRect deviceClipRect = wr::ToRoundedLayoutRect(clipRect); bool hasBorderRadius; Unused << nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius); diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp index aba67e5aceb3..0edd1c0a5f8a 100644 --- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -185,12 +185,12 @@ bool nsDisplayFieldSetBorder::CreateWebRenderCommands( if (!legendRect.IsEmpty()) { // We need to clip out the part of the border where the legend would go auto appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel(); - auto layoutRect = wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits( + auto layoutRect = wr::ToRoundedLayoutRect(LayoutDeviceRect::FromAppUnits( frame->GetVisualOverflowRectRelativeToSelf() + offset, appUnitsPerDevPixel)); wr::ComplexClipRegion region; - region.rect = wr::ToLayoutRect( + region.rect = wr::ToRoundedLayoutRect( LayoutDeviceRect::FromAppUnits(legendRect, appUnitsPerDevPixel)); region.mode = wr::ClipMode::ClipOut; region.radii = wr::EmptyBorderRadius(); diff --git a/layout/generic/TextDrawTarget.h b/layout/generic/TextDrawTarget.h index b5743d245f6e..0125ab815ff7 100644 --- a/layout/generic/TextDrawTarget.h +++ b/layout/generic/TextDrawTarget.h @@ -84,7 +84,7 @@ class TextDrawTarget : public DrawTarget { LayoutDeviceRect layoutBoundsRect = LayoutDeviceRect::FromAppUnits(aBounds, appUnitsPerDevPixel); LayoutDeviceRect layoutClipRect = layoutBoundsRect; - mBoundsRect = wr::ToLayoutRect(layoutBoundsRect); + mBoundsRect = wr::ToRoundedLayoutRect(layoutBoundsRect); // Add 1 pixel of dirty area around clip rect to allow us to paint // antialiased pixels beyond the measured text extents. @@ -275,7 +275,7 @@ class TextDrawTarget : public DrawTarget { } wr::Line decoration; - decoration.bounds = wr::ToLayoutRect(LayoutDeviceRect(pos, size)); + decoration.bounds = wr::ToRoundedLayoutRect(LayoutDeviceRect(pos, size)); decoration.wavyLineThickness = 0; // dummy value, unused decoration.color = wr::ToColorF(aColor); decoration.orientation = aVertical ? wr::LineOrientation::Vertical @@ -310,7 +310,7 @@ class TextDrawTarget : public DrawTarget { wr::Line decoration; decoration.bounds = - wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aBounds)); + wr::ToRoundedLayoutRect(LayoutDeviceRect::FromUnknownRect(aBounds)); decoration.wavyLineThickness = aThickness; decoration.color = wr::ToColorF(aColor); decoration.orientation = aVertical ? wr::LineOrientation::Vertical @@ -347,7 +347,7 @@ class TextDrawTarget : public DrawTarget { private: wr::LayoutRect ClipRect() { - return wr::ToLayoutRect(mClipStack.LastElement()); + return wr::ToRoundedLayoutRect(mClipStack.LastElement()); } LayoutDeviceRect GeckoClipRect() { return mClipStack.LastElement(); } // Whether anything unsupported was encountered. This will result in this @@ -463,7 +463,8 @@ class TextDrawTarget : public DrawTarget { if (!aRect.Intersects(GeckoClipRect().ToUnknownRect())) { return; } - auto rect = wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect)); + auto rect = + wr::ToRoundedLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect)); auto color = wr::ToColorF(static_cast(aPattern).mColor); mBuilder.PushRect(rect, ClipRect(), mBackfaceVisible, color); @@ -490,7 +491,7 @@ class TextDrawTarget : public DrawTarget { if (!rect.Intersects(GeckoClipRect())) { return; } - wr::LayoutRect bounds = wr::ToLayoutRect(rect); + wr::LayoutRect bounds = wr::ToRoundedLayoutRect(rect); mBuilder.PushBorder(bounds, ClipRect(), true, widths, Range(sides, 4), radius); } diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index 1a88d0e5082e..6197e7a2ceb1 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -446,6 +446,7 @@ ImgDrawResult BulletRenderer::CreateWebRenderCommandsForImage( aItem->Frame()->PresContext()->AppUnitsPerDevPixel(); LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(mDest, appUnitsPerDevPixel); + destRect.Round(); Maybe svgContext; gfx::IntSize decodeSize = @@ -484,7 +485,7 @@ bool BulletRenderer::CreateWebRenderCommandsForPath( mozilla::layers::RenderRootStateManager* aManager, nsDisplayListBuilder* aDisplayListBuilder) { MOZ_ASSERT(IsPathType()); - wr::LayoutRect dest = wr::ToLayoutRect(mPathRect); + wr::LayoutRect dest = wr::ToRoundedLayoutRect(mPathRect); auto color = wr::ToColorF(ToDeviceColor(mColor)); bool isBackfaceVisible = !aItem->BackfaceIsHidden(); switch (mListStyleType) { diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index 311d9d627756..99233c1a8037 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -372,8 +372,8 @@ bool nsDisplayCanvasBackgroundColor::CreateWebRenderCommands( LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(bgClipRect, appUnitsPerDevPixel); - wr::LayoutRect r = wr::ToLayoutRect(rect); - aBuilder.PushRect(r, r, !BackfaceIsHidden(), + wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(rect); + aBuilder.PushRect(roundedRect, roundedRect, !BackfaceIsHidden(), wr::ToColorF(ToDeviceColor(mColor))); return true; } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index ff7c4dd317d7..ae17762df698 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2309,9 +2309,10 @@ bool nsDisplaySelectionOverlay::CreateWebRenderCommands( const StackingContextHelper& aSc, mozilla::layers::RenderRootStateManager* aManager, nsDisplayListBuilder* aDisplayListBuilder) { - wr::LayoutRect bounds = wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits( - nsRect(ToReferenceFrame(), Frame()->GetSize()), - mFrame->PresContext()->AppUnitsPerDevPixel())); + wr::LayoutRect bounds = + wr::ToRoundedLayoutRect(LayoutDeviceRect::FromAppUnits( + nsRect(ToReferenceFrame(), Frame()->GetSize()), + mFrame->PresContext()->AppUnitsPerDevPixel())); aBuilder.PushRect(bounds, bounds, !BackfaceIsHidden(), wr::ToColorF(ComputeColor())); return true; diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index ef51b762748f..928141a85e1d 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -163,7 +163,7 @@ class nsDisplayCanvas final : public nsPaintedDisplayItem { // parent side, where it will be done when we build the display list for // the iframe. That happens in WebRenderCompositableHolder. - wr::LayoutRect r = wr::ToLayoutRect(bounds); + wr::LayoutRect r = wr::ToRoundedLayoutRect(bounds); aBuilder.PushIFrame(r, !BackfaceIsHidden(), data->GetPipelineId().ref(), /*ignoreMissingPipelines*/ false); diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 7ee2ca04e7da..37bc04ded1cd 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1569,7 +1569,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer( // Clip to this rect so we don't render outside the inner rect LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits( inner, PresContext()->AppUnitsPerDevPixel()); - auto wrBounds = wr::ToLayoutRect(bounds); + auto wrBounds = wr::ToRoundedLayoutRect(bounds); // Draw image ImgDrawResult result = ImgDrawResult::NOT_READY; @@ -1609,6 +1609,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer( const int32_t factor = PresContext()->AppUnitsPerDevPixel(); LayoutDeviceRect destRect(LayoutDeviceRect::FromAppUnits(dest, factor)); + destRect.Round(); Maybe svgContext; IntSize decodeSize = @@ -1640,7 +1641,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer( nsRect rect(iconXPos, inner.y, size, size); auto devPxRect = LayoutDeviceRect::FromAppUnits( rect, PresContext()->AppUnitsPerDevPixel()); - auto dest = wr::ToLayoutRect(devPxRect); + auto dest = wr::ToRoundedLayoutRect(devPxRect); auto borderWidths = wr::ToBorderWidths(1.0, 1.0, 1.0, 1.0); wr::BorderSide side = {color, wr::BorderStyle::Solid}; @@ -1655,7 +1656,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer( size / 2 - twoPX); devPxRect = LayoutDeviceRect::FromAppUnits( rect, PresContext()->AppUnitsPerDevPixel()); - dest = wr::ToLayoutRect(devPxRect); + dest = wr::ToRoundedLayoutRect(devPxRect); aBuilder.PushRoundedRect(dest, wrBounds, isBackfaceVisible, color); } @@ -1890,6 +1891,7 @@ bool nsDisplayImage::CreateWebRenderCommands( const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel(); LayoutDeviceRect destRect( LayoutDeviceRect::FromAppUnits(GetDestRect(), factor)); + destRect.Round(); Maybe svgContext; IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters( diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 7f84958108ec..035fd0bb1d0c 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -1505,8 +1505,8 @@ bool nsDisplayRemote::CreateWebRenderCommands( mFrame->PresContext()->AppUnitsPerDevPixel()); rect += mOffset; - aBuilder.PushIFrame(mozilla::wr::ToLayoutRect(rect), !BackfaceIsHidden(), - mozilla::wr::AsPipelineId(mLayersId), + aBuilder.PushIFrame(mozilla::wr::ToRoundedLayoutRect(rect), + !BackfaceIsHidden(), mozilla::wr::AsPipelineId(mLayersId), /*ignoreMissingPipelines*/ true); return true; diff --git a/layout/painting/nsCSSRenderingBorders.cpp b/layout/painting/nsCSSRenderingBorders.cpp index 1babcdec80b3..44b51cd0218a 100644 --- a/layout/painting/nsCSSRenderingBorders.cpp +++ b/layout/painting/nsCSSRenderingBorders.cpp @@ -3328,7 +3328,7 @@ void nsCSSBorderRenderer::CreateWebRenderCommands( wr::IpcResourceUpdateQueue& aResources, const layers::StackingContextHelper& aSc) { LayoutDeviceRect outerRect = LayoutDeviceRect::FromUnknownRect(mOuterRect); - wr::LayoutRect roundedRect = wr::ToLayoutRect(outerRect); + wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(outerRect); wr::LayoutRect clipRect = roundedRect; wr::BorderSide side[4]; NS_FOR_CSS_SIDES(i) { @@ -3345,7 +3345,7 @@ void nsCSSBorderRenderer::CreateWebRenderCommands( if (mLocalClip) { LayoutDeviceRect localClip = LayoutDeviceRect::FromUnknownRect(mLocalClip.value()); - clipRect = wr::ToLayoutRect(localClip.Intersect(outerRect)); + clipRect = wr::ToRoundedLayoutRect(localClip.Intersect(outerRect)); } Range wrsides(side, 4); @@ -3593,7 +3593,7 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands( if (!mClip.IsEmpty()) { LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(mClip, appUnitsPerDevPixel); - clip = wr::ToLayoutRect(clipRect); + clip = wr::ToRoundedLayoutRect(clipRect); } ImgDrawResult drawResult = ImgDrawResult::SUCCESS; diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 9716a5e689c8..21bb9c15b107 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -3866,16 +3866,16 @@ bool nsDisplaySolidColor::CreateWebRenderCommands( LayoutDeviceRect renderRootRect = aDisplayListBuilder->GetRenderRootRect(renderRoot); wr::LayoutRect intersection = - wr::ToLayoutRect(bounds.Intersect(renderRootRect)); + wr::ToRoundedLayoutRect(bounds.Intersect(renderRootRect)); aBuilder.SubBuilder(renderRoot) .PushRect(intersection, intersection, !BackfaceIsHidden(), wr::ToColorF(ToDeviceColor(mColor))); } } } else { - wr::LayoutRect r = wr::ToLayoutRect(bounds); + wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(bounds); - aBuilder.PushRect(r, r, !BackfaceIsHidden(), + aBuilder.PushRect(roundedRect, roundedRect, !BackfaceIsHidden(), wr::ToColorF(ToDeviceColor(mColor))); } @@ -3915,8 +3915,8 @@ bool nsDisplaySolidColorRegion::CreateWebRenderCommands( nsRect rect = iter.Get(); LayoutDeviceRect layerRects = LayoutDeviceRect::FromAppUnits( rect, mFrame->PresContext()->AppUnitsPerDevPixel()); - wr::LayoutRect r = wr::ToLayoutRect(layerRects); - aBuilder.PushRect(r, r, !BackfaceIsHidden(), + wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(layerRects); + aBuilder.PushRect(roundedRect, roundedRect, !BackfaceIsHidden(), wr::ToColorF(ToDeviceColor(mColor))); } @@ -5181,9 +5181,9 @@ bool nsDisplayBackgroundColor::CreateWebRenderCommands( LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits( mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel()); - wr::LayoutRect r = wr::ToLayoutRect(bounds); + wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(bounds); - aBuilder.PushRect(r, r, !BackfaceIsHidden(), + aBuilder.PushRect(roundedRect, roundedRect, !BackfaceIsHidden(), wr::ToColorF(ToDeviceColor(mColor))); return true; @@ -5366,7 +5366,7 @@ bool nsDisplayClearBackground::CreateWebRenderCommands( nsRect(ToReferenceFrame(), mFrame->GetSize()), mFrame->PresContext()->AppUnitsPerDevPixel()); - aBuilder.PushClearRect(wr::ToLayoutRect(bounds)); + aBuilder.PushClearRect(wr::ToRoundedLayoutRect(bounds)); return true; } @@ -5539,7 +5539,7 @@ bool nsDisplayCompositorHitTestInfo::CreateWebRenderCommands( const LayoutDeviceRect devRect = LayoutDeviceRect::FromAppUnits(HitTestArea(), mAppUnitsPerDevPixel); - const wr::LayoutRect rect = wr::ToLayoutRect(devRect); + const wr::LayoutRect rect = wr::ToRoundedLayoutRect(devRect); aBuilder.PushHitTest(rect, rect, !BackfaceIsHidden()); aBuilder.ClearHitTestInfo(); @@ -5611,8 +5611,8 @@ bool nsDisplayCaret::CreateWebRenderCommands( LayoutDeviceRect devHookRect = LayoutDeviceRect::FromAppUnits( hookRect + ToReferenceFrame(), appUnitsPerDevPixel); - wr::LayoutRect caret = wr::ToLayoutRect(devCaretRect); - wr::LayoutRect hook = wr::ToLayoutRect(devHookRect); + wr::LayoutRect caret = wr::ToRoundedLayoutRect(devCaretRect); + wr::LayoutRect hook = wr::ToRoundedLayoutRect(devHookRect); // Note, WR will pixel snap anything that is layout aligned. aBuilder.PushRect(caret, caret, !BackfaceIsHidden(), wr::ToColorF(color)); @@ -5886,8 +5886,8 @@ bool nsDisplayBoxShadowOuter::CreateWebRenderCommands( LayoutDeviceRect deviceBox = LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel); - wr::LayoutRect deviceBoxRect = wr::ToLayoutRect(deviceBox); - wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect); + wr::LayoutRect deviceBoxRect = wr::ToRoundedLayoutRect(deviceBox); + wr::LayoutRect deviceClipRect = wr::ToRoundedLayoutRect(clipRect); LayoutDeviceSize zeroSize; wr::BorderRadius borderRadius = @@ -6015,7 +6015,7 @@ void nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands( // Now translate everything to device pixels. LayoutDeviceRect deviceBoxRect = LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel); - wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect); + wr::LayoutRect deviceClipRect = wr::ToRoundedLayoutRect(clipRect); Color shadowColor = nsCSSRendering::GetShadowColor(shadow.base, aFrame, 1.0); @@ -7736,7 +7736,7 @@ bool nsDisplayStickyPosition::CreateWebRenderCommands( NSAppUnitsToFloatPixels(appliedOffset.x, auPerDevPixel), NSAppUnitsToFloatPixels(appliedOffset.y, auPerDevPixel)}; wr::WrSpatialId spatialId = aBuilder.DefineStickyFrame( - wr::ToLayoutRect(bounds), topMargin.ptrOr(nullptr), + wr::ToRoundedLayoutRect(bounds), topMargin.ptrOr(nullptr), rightMargin.ptrOr(nullptr), bottomMargin.ptrOr(nullptr), leftMargin.ptrOr(nullptr), vBounds, hBounds, applied); @@ -10031,7 +10031,7 @@ static Maybe CreateSimpleClipRegion( wr::ToComplexClipRegion(insetRect, radii, appUnitsPerDevPixel)); } - rect = wr::ToLayoutRect( + rect = wr::ToRoundedLayoutRect( LayoutDeviceRect::FromAppUnits(insetRect, appUnitsPerDevPixel)); break; } @@ -10060,7 +10060,7 @@ static Maybe CreateSimpleClipRegion( clipRegions.AppendElement(wr::ToComplexClipRegion( ellipseRect, ellipseRadii, appUnitsPerDevPixel)); - rect = wr::ToLayoutRect( + rect = wr::ToRoundedLayoutRect( LayoutDeviceRect::FromAppUnits(ellipseRect, appUnitsPerDevPixel)); break; } @@ -10099,7 +10099,7 @@ static Maybe> CreateWRClipPathAndMasks( } wr::WrClipId clipId = aBuilder.DefineClip( - Nothing(), wr::ToLayoutRect(aBounds), nullptr, mask.ptr()); + Nothing(), wr::ToRoundedLayoutRect(aBounds), nullptr, mask.ptr()); return Some(MakePair(clipId, HandleOpacity::No)); } @@ -10512,7 +10512,7 @@ bool nsDisplayFilters::CreateWebRenderCommands( auto devPxRect = LayoutDeviceRect::FromAppUnits( filterClip.value() + ToReferenceFrame(), auPerDevPixel); wr::WrClipId clipId = - aBuilder.DefineClip(Nothing(), wr::ToLayoutRect(devPxRect)); + aBuilder.DefineClip(Nothing(), wr::ToRoundedLayoutRect(devPxRect)); clip = wr::WrStackingContextClip::ClipId(clipId); } else { clip = wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId()); diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp index 291a5cac03fa..469a4890a20b 100644 --- a/layout/painting/nsImageRenderer.cpp +++ b/layout/painting/nsImageRenderer.cpp @@ -603,6 +603,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(aDest, appUnitsPerDevPixel); auto stretchSize = wr::ToLayoutSize(destRect.Size()); + destRect.Round(); gfx::IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters( @@ -629,47 +630,47 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems( break; } - wr::LayoutRect dest = wr::ToLayoutRect(destRect); + nsPoint firstTilePos = nsLayoutUtils::GetBackgroundFirstTilePos( + aDest.TopLeft(), aFill.TopLeft(), aRepeatSize); + LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits( + nsRect(firstTilePos.x, firstTilePos.y, aFill.XMost() - firstTilePos.x, + aFill.YMost() - firstTilePos.y), + appUnitsPerDevPixel); + wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect); - wr::LayoutRect clip = wr::ToLayoutRect( + wr::LayoutRect roundedDest = wr::ToLayoutRect(destRect); + + // WebRender special cases situations where stretchSize == fillSize to + // infer that it shouldn't use repeat sampling. This makes sure + // we hit those special cases when not repeating. + + switch (mExtendMode) { + case ExtendMode::CLAMP: + fill = roundedDest; + stretchSize = roundedDest.size; + break; + case ExtendMode::REPEAT_Y: + fill.origin.x = roundedDest.origin.x; + fill.size.width = roundedDest.size.width; + stretchSize.width = roundedDest.size.width; + break; + case ExtendMode::REPEAT_X: + fill.origin.y = roundedDest.origin.y; + fill.size.height = roundedDest.size.height; + stretchSize.height = roundedDest.size.height; + break; + default: + break; + } + + wr::LayoutRect clip = wr::ToRoundedLayoutRect( LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel)); - if (mExtendMode == ExtendMode::CLAMP) { - // The image is not repeating. Just push as a regular image. - aBuilder.PushImage(dest, clip, !aItem->BackfaceIsHidden(), rendering, - key.value()); - } else { - nsPoint firstTilePos = nsLayoutUtils::GetBackgroundFirstTilePos( - aDest.TopLeft(), aFill.TopLeft(), aRepeatSize); - LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits( - nsRect(firstTilePos.x, firstTilePos.y, - aFill.XMost() - firstTilePos.x, - aFill.YMost() - firstTilePos.y), - appUnitsPerDevPixel); - wr::LayoutRect fill = wr::ToLayoutRect(fillRect); + LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits( + aRepeatSize - aDest.Size(), appUnitsPerDevPixel); - switch (mExtendMode) { - case ExtendMode::REPEAT_Y: - fill.origin.x = dest.origin.x; - fill.size.width = dest.size.width; - stretchSize.width = dest.size.width; - break; - case ExtendMode::REPEAT_X: - fill.origin.y = dest.origin.y; - fill.size.height = dest.size.height; - stretchSize.height = dest.size.height; - break; - default: - break; - } - - LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits( - aRepeatSize - aDest.Size(), appUnitsPerDevPixel); - - aBuilder.PushRepeatingImage(fill, clip, !aItem->BackfaceIsHidden(), - stretchSize, wr::ToLayoutSize(gapSize), - rendering, key.value()); - } + aBuilder.PushImage(fill, clip, !aItem->BackfaceIsHidden(), stretchSize, + wr::ToLayoutSize(gapSize), rendering, key.value()); break; } default: diff --git a/layout/reftests/async-scrolling/reftest.list b/layout/reftests/async-scrolling/reftest.list index 6369c20cfc66..ffda13b4c7b2 100644 --- a/layout/reftests/async-scrolling/reftest.list +++ b/layout/reftests/async-scrolling/reftest.list @@ -5,7 +5,7 @@ skip-if(!asyncPan) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html skip-if(!asyncPan) == bg-fixed-child.html bg-fixed-child-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-1.html bg-fixed-child-clip-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-2.html bg-fixed-child-clip-ref.html -fuzzy(0-1,0-246) fuzzy-if(skiaContent,0-2,0-170) fuzzy-if(browserIsRemote&&d2d,0-59,0-187) fuzzy-if(webrender,41-41,166-176) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html +fuzzy(0-1,0-246) fuzzy-if(skiaContent,0-2,0-170) fuzzy-if(browserIsRemote&&d2d,0-59,0-187) fuzzy-if(webrender,41-41,166-168) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html skip-if(!asyncPan) == bg-fixed-in-opacity.html bg-fixed-in-opacity-ref.html # Passing the test below without WebRender would require implementing CSS filters in the Gecko compositor. fails-if(!webrender) skip-if(!asyncPan) fuzzy-if(webrender&>kWidget,0-1,0-87) fuzzy-if(webrender&&!gtkWidget,0-1,0-3951) == bg-fixed-in-css-filter.html bg-fixed-in-css-filter-ref.html # bug 1454794 for webrender fuzziness @@ -24,7 +24,7 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-3120) skip-if(!asyncPa skip-if(!asyncPan) == position-fixed-cover-1.html position-fixed-cover-1-ref.html skip-if(!asyncPan) == position-fixed-cover-2.html position-fixed-cover-2-ref.html skip-if(!asyncPan) == position-fixed-cover-3.html position-fixed-cover-3-ref.html -fuzzy-if(Android,0-8,0-4) fuzzy-if(webrender&>kWidget,60-60,14-14) fuzzy-if(webrender&&cocoaWidget,22-22,44-44) skip-if(!asyncPan) == position-fixed-transformed-1.html position-fixed-transformed-1-ref.html +fuzzy-if(Android,0-5,0-4) skip-if(!asyncPan) == position-fixed-transformed-1.html position-fixed-transformed-1-ref.html skip-if(!asyncPan) == split-layers-1.html split-layers-1-ref.html skip-if(!asyncPan) == split-layers-multi-scrolling-1.html split-layers-multi-scrolling-1-ref.html fuzzy-if(skiaContent,0-2,0-240000) fuzzy-if(browserIsRemote&&!skiaContent&&(cocoaWidget||winWidget),0-1,0-240000) skip-if(!asyncPan) == split-opacity-layers-1.html split-opacity-layers-1-ref.html @@ -49,33 +49,33 @@ skip-if(!asyncPan) fails-if(!webrender) == sticky-inside-transform-1.html sticky fuzzy(0-1,0-60000) skip-if(!asyncPan) == group-opacity-surface-size-1.html group-opacity-surface-size-1-ref.html fuzzy-if(Android,0-1,0-197) fuzzy-if(webrender,0-1,0-1) skip-if(!asyncPan) == position-sticky-transformed.html position-sticky-transformed-ref.html skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html -fuzzy-if(Android,0-6,0-4) fuzzy-if(skiaContent&&!Android,0-1,0-34) fuzzy-if(webrender&>kWidget,64-64,24-24) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html -fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&>kWidget,64-64,14-14) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html +fuzzy-if(Android,0-6,0-4) fuzzy-if(skiaContent&&!Android,0-1,0-34) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html +fuzzy-if(Android,0-6,0-4) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html fuzzy-if(Android,0-6,0-4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item -fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&>kWidget,64-64,14-14) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html -fuzzy-if(Android,0-7,0-1406) fuzzy-if(webrender&>kWidget,1-1,20-20) fuzzy-if(webrender&&cocoaWidget,1-1,19-19) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html +fuzzy-if(Android,0-6,0-4) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html +fuzzy-if(Android,0-7,0-4) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html fuzzy-if(Android,0-7,0-4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html -fuzzy-if(Android,0-19,0-4) fuzzy-if(webrender&>kWidget,24-24,14-14) fuzzy-if(webrender&&cocoaWidget,13-13,39-39) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html -fuzzy-if(Android,0-7,0-4) fuzzy-if(webrender&>kWidget,54-54,14-14) fuzzy-if(webrender&&cocoaWidget,20-20,40-40) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html +fuzzy-if(Android,0-7,0-4) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html +fuzzy-if(Android,0-7,0-4) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html skip-if(!asyncPan) == perspective-scrolling-5.html perspective-scrolling-5-ref.html pref(apz.disable_for_scroll_linked_effects,true) skip-if(!asyncPan) == disable-apz-for-sle-pages.html disable-apz-for-sle-pages-ref.html fuzzy-if(browserIsRemote&&d2d,0-1,0-22) skip-if(!asyncPan) fuzzy-if(geckoview,2-2,242-242) skip-if(geckoview&&debug) == background-blend-mode-1.html background-blend-mode-1-ref.html # bug 1558286 for GV skip-if(Android||!asyncPan) != opaque-fractional-displayport-1.html about:blank skip-if(Android||!asyncPan) != opaque-fractional-displayport-2.html about:blank -fuzzy-if(Android,0-19,0-4) fuzzy-if(webrender&>kWidget,35-35,14-14) fuzzy-if(webrender&&cocoaWidget,22-22,44-44) skip-if(!asyncPan) == fixed-pos-scrolled-clip-1.html fixed-pos-scrolled-clip-1-ref.html -fuzzy-if(Android,0-44,0-10) fuzzy-if(webrender&>kWidget,48-48,28-28) fuzzy-if(webrender&&cocoaWidget,13-13,76-76) skip-if(!asyncPan) == fixed-pos-scrolled-clip-2.html fixed-pos-scrolled-clip-2-ref.html -fuzzy-if(Android,0-6,0-8) fuzzy-if(webrender&>kWidget,53-53,48-48) fuzzy-if(webrender&&cocoaWidget,19-19,72-72) skip-if(!asyncPan) == fixed-pos-scrolled-clip-3.html fixed-pos-scrolled-clip-3-ref.html -fuzzy-if(Android,0-6,0-8) fuzzy-if(webrender&>kWidget,53-53,48-48) fuzzy-if(webrender&&cocoaWidget,19-19,72-72) skip-if(!asyncPan) == fixed-pos-scrolled-clip-4.html fixed-pos-scrolled-clip-4-ref.html +fuzzy-if(Android,0-6,0-4) skip-if(!asyncPan) == fixed-pos-scrolled-clip-1.html fixed-pos-scrolled-clip-1-ref.html +fuzzy-if(Android,0-6,0-8) skip-if(!asyncPan) == fixed-pos-scrolled-clip-2.html fixed-pos-scrolled-clip-2-ref.html +fuzzy-if(Android,0-6,0-8) skip-if(!asyncPan) == fixed-pos-scrolled-clip-3.html fixed-pos-scrolled-clip-3-ref.html +fuzzy-if(Android,0-6,0-8) skip-if(!asyncPan) == fixed-pos-scrolled-clip-4.html fixed-pos-scrolled-clip-4-ref.html skip-if(!asyncPan) == fixed-pos-scrolled-clip-5.html fixed-pos-scrolled-clip-5-ref.html skip-if(!asyncPan) == position-sticky-bug1434250.html position-sticky-bug1434250-ref.html -fuzzy-if(Android,0-8,0-4) fuzzy-if(webrender&>kWidget,47-47,24-24) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) skip-if(!asyncPan) == position-sticky-scrolled-clip-1.html position-sticky-scrolled-clip-1-ref.html +fuzzy-if(Android,0-6,0-4) skip-if(!asyncPan) == position-sticky-scrolled-clip-1.html position-sticky-scrolled-clip-1-ref.html fuzzy-if(Android,0-6,0-4) skip == position-sticky-scrolled-clip-2.html position-sticky-scrolled-clip-2-ref.html # bug ?????? - incorrectly applying clip to sticky contents -fuzzy-if(Android,0-8,0-4) fuzzy-if(webrender&&cocoaWidget,11-11,39-39) skip-if(!asyncPan) == curtain-effect-1.html curtain-effect-1-ref.html -fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&>kWidget,27-27,24-24) fuzzy-if(webrender&&cocoaWidget,9-9,37-37) skip-if(!asyncPan) == transformed-1.html transformed-1-ref.html -fuzzy-if(Android&&!webrender,2-2,4-4) fuzzy-if(Android&&webrender,7-7,4-4) fuzzy-if(webrender&>kWidget,21-21,24-24) fuzzy-if(webrender&&cocoaWidget,6-6,37-37) skip-if(!asyncPan) == position-sticky-transformed-in-scrollframe-1.html position-sticky-transformed-in-scrollframe-1-ref.html -fuzzy-if(Android&&!webrender,3-3,4-4) fuzzy-if(Android&&webrender,10-10,4-4) fuzzy-if(webrender&>kWidget,37-37,24-24) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) skip-if(!asyncPan) == position-sticky-transformed-in-scrollframe-2.html position-sticky-transformed-in-scrollframe-2-ref.html -fuzzy-if(Android&&!webrender,3-3,4-4) fuzzy-if(Android&&webrender,13-13,4-4) fuzzy-if(webrender&>kWidget,9-9,14-14) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-1.html position-sticky-in-transformed-scrollframe-ref.html -fuzzy-if(Android&&!webrender,3-3,4-4) fuzzy-if(Android&&webrender,13-13,4-4) fuzzy-if(webrender&>kWidget,9-9,14-14) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-2.html position-sticky-in-transformed-scrollframe-ref.html +fuzzy-if(Android,0-2,0-4) skip-if(!asyncPan) == curtain-effect-1.html curtain-effect-1-ref.html +fuzzy-if(Android,0-1,0-4) skip-if(!asyncPan) == transformed-1.html transformed-1-ref.html +fuzzy-if(Android&&!webrender,2-2,4-4) skip-if(!asyncPan) == position-sticky-transformed-in-scrollframe-1.html position-sticky-transformed-in-scrollframe-1-ref.html +fuzzy-if(Android&&!webrender,3-3,4-4) skip-if(!asyncPan) == position-sticky-transformed-in-scrollframe-2.html position-sticky-transformed-in-scrollframe-2-ref.html +fuzzy-if(Android&&!webrender,3-3,4-4) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-1.html position-sticky-in-transformed-scrollframe-ref.html +fuzzy-if(Android&&!webrender,3-3,4-4) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-2.html position-sticky-in-transformed-scrollframe-ref.html # for the following tests, we want to disable the low-precision buffer # as it will expand the displayport beyond what the test specifies in diff --git a/layout/reftests/border-image/reftest.list b/layout/reftests/border-image/reftest.list index fb1400e8d7d2..f715bc405d7b 100644 --- a/layout/reftests/border-image/reftest.list +++ b/layout/reftests/border-image/reftest.list @@ -48,14 +48,14 @@ fuzzy(0-1,0-149) fuzzy-if(OSX,0-1,0-10595) fuzzy-if(webrender&&!geckoview,1-3,24 fuzzy(0-1,0-433) fuzzy-if(skiaContent,0-1,0-2500) fuzzy-if(webrender&&!geckoview,1-3,83975-85584) == border-image-linear-gradient-slice-fill-1.html border-image-linear-gradient-slice-fill-1-ref.html fuzzy(0-1,0-177) fuzzy-if(OSX,0-1,0-25771) fuzzy-if(skiaContent&&!Android,0-1,0-400) fuzzy-if(Android,0-1,0-6093) fuzzy-if(webrender&&!geckoview,1-3,57249-57480) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html fuzzy(0-1,0-48) fuzzy-if(OSX,0-5,0-1676) fuzzy-if(webrender&&!geckoview,1-1,4464-4537) == border-image-linear-gradient-width.html border-image-linear-gradient-width-ref.html -fuzzy(0-1,0-5000) fuzzy-if(OSX,0-1,0-15000) fuzzy-if(webrender&&!geckoview,1-2,60222-60545) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html -fuzzy(0-1,0-3000) fuzzy-if(OSX,0-1,0-6000) fuzzy-if(webrender&&!geckoview,1-3,25940-26688) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html +fuzzy(0-1,0-5000) fuzzy-if(OSX,0-1,0-15000) fuzzy-if(webrender&&!geckoview,2-2,58625-58987) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html +fuzzy(0-1,0-3000) fuzzy-if(OSX,0-1,0-6000) fuzzy-if(webrender&&!geckoview,1-3,25940-26413) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html fuzzy(0-1,0-12) fuzzy-if(skiaContent,0-1,0-400) fuzzy-if(webrender&&!geckoview,1-3,25966-26872) == border-image-linear-gradient-repeat-repeat-1.html border-image-linear-gradient-repeat-repeat-1-ref.html fuzzy(0-1,0-13) fuzzy-if(skiaContent,0-1,0-300) fuzzy-if(webrender&&!geckoview,1-3,26038-27131) == border-image-linear-gradient-repeat-round-1.html border-image-linear-gradient-repeat-round-1-ref.html fuzzy-if(webrender&&!geckoview,1-2,61283-67805) == border-image-linear-gradient-repeat-repeat-2.html border-image-linear-gradient-repeat-repeat-2-ref.html fuzzy(0-1,0-576) fuzzy-if(skiaContent,0-1,0-2000) fuzzy-if(webrender&&!geckoview,1-2,61764-68383) == border-image-linear-gradient-repeat-round-2.html border-image-linear-gradient-repeat-round-2-ref.html fuzzy(0-1,0-8533) fuzzy-if(webrender&&!geckoview,1-3,64622-85925) == border-image-linear-gradient-repeat-repeat-3.html border-image-linear-gradient-repeat-repeat-3-ref.html -fuzzy(0-1,0-7161) fuzzy-if(webrender&&!geckoview,1-3,107185-107548) == border-image-linear-gradient-repeat-round-3.html border-image-linear-gradient-repeat-round-3-ref.html +fuzzy(0-1,0-7161) fuzzy-if(webrender&&!geckoview,1-3,85018-86037) == border-image-linear-gradient-repeat-round-3.html border-image-linear-gradient-repeat-round-3-ref.html fuzzy-if(webrender,0-1,0-2096) == border-image-radial-gradient.html border-image-radial-gradient-ref.html fuzzy(0-1,0-42) fuzzy-if(skiaContent,0-2,0-20) fuzzy-if(webrender,0-1,0-37818) == border-image-radial-gradient-slice-1.html border-image-radial-gradient-slice-1-ref.html diff --git a/layout/reftests/box-shadow/reftest.list b/layout/reftests/box-shadow/reftest.list index 935ceb4952f4..a7f16cb06afa 100644 --- a/layout/reftests/box-shadow/reftest.list +++ b/layout/reftests/box-shadow/reftest.list @@ -11,7 +11,7 @@ random != boxshadow-blur-2.html boxshadow-blur-2-notref.html # fixedpoint divisi == boxshadow-rounding.html boxshadow-rounding-ref.html # One uses old path, one uses WR box shadow. fails-if(Android) == boxshadow-button.html boxshadow-button-ref.html -fuzzy-if(OSX==1010,0-1,0-24) fuzzy-if(d2d,0-16,0-999) fuzzy-if(skiaContent,0-14,0-179) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649 +fuzzy-if(OSX==1010,0-1,0-24) fuzzy-if(d2d,0-16,0-999) fuzzy-if(skiaContent,0-14,0-179) fuzzy-if(webrender,5-9,700-1080) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649 fails-if(Android) == boxshadow-fileupload.html boxshadow-fileupload-ref.html fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-98,0-152) fuzzy-if(skiaContent,0-13,0-28) fuzzy-if(webrender,19-19,47-47) == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg @@ -29,7 +29,7 @@ fuzzy(0-2,0-440) == boxshadow-skiprect.html boxshadow-skiprect-ref.html fuzzy(0-3,0-500) fuzzy-if(d2d,0-2,0-1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html == boxshadow-inset-neg-spread.html about:blank == boxshadow-inset-neg-spread2.html boxshadow-inset-neg-spread2-ref.html -fuzzy(0-26,0-3610) fuzzy-if(d2d,0-26,0-5910) fuzzy-if(webrender,18-19,4184-4341) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264 +fuzzy(0-26,0-3610) fuzzy-if(d2d,0-26,0-5910) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264 == boxshadow-inset-large-border-radius.html boxshadow-inset-large-border-radius-ref.html # fuzzy due to blur going inside, but as long as it's essentially black instead of a light gray its ok. diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 79992f75549c..97e9c27679b9 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1603,8 +1603,7 @@ random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 600974-2.html 600974-1-r random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 600974-3.html 600974-1-ref.html # Bug 1392106 == 602200-1.html 602200-1-ref.html == 602200-2.html 602200-2-ref.html -# Canvas with a fractional margin does not snap properly; see bug 1580534 -fuzzy-if(Android,0-8,0-20) fails-if(webrender) == 602200-3.html 602200-3-ref.html +fuzzy-if(Android,0-8,0-20) == 602200-3.html 602200-3-ref.html == 602200-4.html 602200-4-ref.html == 603423-1.html 603423-1-ref.html == 604737.html 604737-ref.html @@ -2096,12 +2095,12 @@ skip-if(!asyncPan) == 1544895.html 1544895-ref.html == 1547759-1.html 1547759-1-ref.html == 1548809.html 1548809-ref.html != 1552789-1.html 1552789-ref-1.html -pref(image.downscale-during-decode.enabled,true) == 1553571-1.html 1553571-1-ref.html +pref(image.downscale-during-decode.enabled,true) fuzzy-if(webrender,3-4,17665-18088) == 1553571-1.html 1553571-1-ref.html == 1558937-1.html 1558937-1-ref.html != 1563484.html 1563484-notref.html == 1563484.html 1563484-ref.html fuzzy-if(!webrender||!winWidget,254-255,464-1613) fuzzy-if(geckoview&&webrender,253-253,1392-1397) == 1562733-rotated-nastaliq-1.html 1562733-rotated-nastaliq-1-ref.html -fuzzy-if(winWidget&&webrender,0-31,0-3) fuzzy-if(geckoview&&webrender,0-93,0-26) == 1562733-rotated-nastaliq-2.html 1562733-rotated-nastaliq-2-ref.html +fuzzy-if(winWidget&&webrender,0-31,0-3) fuzzy-if(geckoview&&webrender,0-93,0-16) == 1562733-rotated-nastaliq-2.html 1562733-rotated-nastaliq-2-ref.html test-pref(plain_text.wrap_long_lines,false) != 1565129.txt 1565129.txt fuzzy(0-32,0-8) fuzzy-if(Android&&webrender,0-32,0-1458) == 1576553-1.html 1576553-1-ref.html == 1579953-2.html 1579953-2-ref.html diff --git a/layout/reftests/css-blending/reftest.list b/layout/reftests/css-blending/reftest.list index 9105ffe85081..83e23e538ec9 100644 --- a/layout/reftests/css-blending/reftest.list +++ b/layout/reftests/css-blending/reftest.list @@ -38,7 +38,7 @@ fuzzy-if(d2d||azureSkia||gtkWidget,0-10,0-4800) == background-blending-soft-ligh fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-40000) == background-blending-image-color-959674.html background-blending-image-color-959674-ref.html #fuzzy due to inconsistencies in rounded rect cliping between parent and child; may be related to antialiasing. Between platforms, the max difference is the same, and the number of different pixels is either 36 or 37. (Win, Mac and Lin) -fuzzy(0-65,0-53) fuzzy-if(geckoview&&webrender,63-64,163-328) == mix-blend-mode-952051.html mix-blend-mode-952051-ref.html +fuzzy(0-65,0-53) fuzzy-if(geckoview&&webrender,64-64,163-163) == mix-blend-mode-952051.html mix-blend-mode-952051-ref.html fuzzy-if(d3d11,0-49,0-200) == mix-blend-mode-and-filter.html mix-blend-mode-and-filter-ref.html fuzzy-if(d3d11,0-1,0-5) == mix-blend-mode-and-filter.svg mix-blend-mode-and-filter-ref.svg diff --git a/layout/reftests/css-break/reftest.list b/layout/reftests/css-break/reftest.list index 6f1c5ee528b1..32a8aa612ec9 100644 --- a/layout/reftests/css-break/reftest.list +++ b/layout/reftests/css-break/reftest.list @@ -1,5 +1,5 @@ == box-decoration-break-1.html box-decoration-break-1-ref.html -fuzzy(0-1,0-20) fuzzy-if(skiaContent,0-1,0-700) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html +fuzzy(0-1,0-20) fuzzy-if(skiaContent,0-1,0-700) fuzzy-if(webrender,20-26,8891-12681) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html skip-if(verify) fuzzy(0-45,0-460) fuzzy-if(skiaContent,0-57,0-439) fuzzy-if(Android,0-57,0-1330) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html # Bug 1386543, bug 1392106 random-if(!gtkWidget||webrender) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index 3ca53541b746..a864fbc0e2ab 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -23,7 +23,7 @@ fuzzy-if(cocoaWidget,0-135,0-56) == dir-6a.html dir-6a-ref.html == css-spacing-1.html css-spacing-1-ref.html pref(mathml.disabled,true) == disabled-scriptlevel-1.html disabled-scriptlevel-1-ref.html pref(mathml.disabled,true) == disabled-scriptlevel-1.xhtml disabled-scriptlevel-1-ref.xhtml -random-if(smallScreen&&Android) fuzzy(0-255,0-200) fuzzy-if(geckoview&&webrender,216-216,312-314) fuzzy-if(webrender&&winWidget,114-255,265-361) fuzzy-if(webrender&&OSX,79-79,314-314) == mirror-op-1.html mirror-op-1-ref.html +random-if(smallScreen&&Android) fuzzy(0-255,0-200) fuzzy-if(webrender&&winWidget,114-255,265-304) fuzzy-if(webrender&&OSX,87-87,242-242) == mirror-op-1.html mirror-op-1-ref.html != mirror-op-2.html mirror-op-2-ref.html != mirror-op-3.html mirror-op-3-ref.html != mirror-op-4.html mirror-op-4-ref.html diff --git a/layout/reftests/position-sticky/reftest.list b/layout/reftests/position-sticky/reftest.list index ab20ffc05371..7cf0edaa8f1d 100644 --- a/layout/reftests/position-sticky/reftest.list +++ b/layout/reftests/position-sticky/reftest.list @@ -50,6 +50,6 @@ fuzzy-if(Android,0-8,0-630) fuzzy-if(OSX,0-1,0-11) fuzzy-if(skiaContent,0-1,0-22 == block-in-inline-continuations.html block-in-inline-continuations-ref.html == iframe-1.html iframe-1-ref.html == transformed-1.html transformed-1-ref.html -fuzzy-if(Android,0-4,0-4) fuzzy-if(webrender&>kWidget,31-31,24-24) fuzzy-if(webrender&&cocoaWidget,8-8,37-37) skip-if(!asyncPan) == transformed-2.html transformed-2-ref.html -skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(webrender&>kWidget,57-57,24-24) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) == nested-sticky-1.html nested-sticky-1-ref.html -skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),0-4,0-104) fuzzy-if(webrender&>kWidget,57-57,24-24) fuzzy-if(webrender,cocoaWidget,16-16,40-40) == nested-sticky-2.html nested-sticky-2-ref.html +fuzzy-if(Android,0-2,0-4) skip-if(!asyncPan) == transformed-2.html transformed-2-ref.html +skip-if(!asyncPan) fuzzy-if(Android,0-3,0-4) == nested-sticky-1.html nested-sticky-1-ref.html +skip-if(!asyncPan) fuzzy-if(Android,0-3,0-4) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),0-4,0-104) == nested-sticky-2.html nested-sticky-2-ref.html diff --git a/layout/reftests/writing-mode/reftest.list b/layout/reftests/writing-mode/reftest.list index a77d5ffba79b..b76836b91d0c 100644 --- a/layout/reftests/writing-mode/reftest.list +++ b/layout/reftests/writing-mode/reftest.list @@ -148,9 +148,9 @@ random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1188061-2-nsChangeHint_U # tests involving sideways-lr mode == 1193519-sideways-lr-1.html 1193519-sideways-lr-1-ref.html == 1193519-sideways-lr-2.html 1193519-sideways-lr-2-ref.html -fuzzy-if(winWidget,0-3,0-84) fails-if(webrender&&winWidget) == 1193519-sideways-lr-3.html 1193519-sideways-lr-3-ref.html -fuzzy-if(winWidget,0-3,0-112) fails-if(webrender&&!cocoaWidget) fails-if(Android) == 1193519-sideways-lr-4.html 1193519-sideways-lr-4-ref.html # see bug 1366692. Rounding error with WR enabled, and on Android. -fuzzy-if(gtkWidget,0-255,0-6) fuzzy-if(cocoaWidget,0-65,0-69) fuzzy-if(geckoview&&webrender,0-255,0-7) == 1193519-sideways-lr-decoration-1.html 1193519-sideways-lr-decoration-1-ref.html +fuzzy-if(winWidget,0-3,0-84) fails-if(webrender&&!gtkWidget) == 1193519-sideways-lr-3.html 1193519-sideways-lr-3-ref.html +fuzzy-if(winWidget,0-3,0-112) fails-if(webrender||Android) == 1193519-sideways-lr-4.html 1193519-sideways-lr-4-ref.html # see bug 1366692. Rounding error with WR enabled, and on Android. +fuzzy-if(gtkWidget,0-255,0-6) fuzzy-if(cocoaWidget,0-65,0-69) fuzzy-if(geckoview&&webrender,0-255,0-4) == 1193519-sideways-lr-decoration-1.html 1193519-sideways-lr-decoration-1-ref.html == 1196887-1-computed-display-inline-block.html 1196887-1-computed-display-inline-block-ref.html == 1205787-legacy-svg-values-1.html 1205787-legacy-svg-values-1-ref.html diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index feb9a275054b..e3665a415a25 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -6925,19 +6925,20 @@ static void CreateWRCommandsForBeveledBorder( for (const auto& segment : segments) { auto rect = LayoutDeviceRect::FromUnknownRect(NSRectToRect( segment.mRect + aOffset, aBorderParams.mAppUnitsPerDevPixel)); - auto r = wr::ToLayoutRect(rect); + auto roundedRect = wr::ToRoundedLayoutRect(rect); auto color = wr::ToColorF(ToDeviceColor(segment.mColor)); // Adjust for the start bevel if needed. - AdjustAndPushBevel(aBuilder, r, segment.mColor, segment.mStartBevel, - aBorderParams.mAppUnitsPerDevPixel, + AdjustAndPushBevel(aBuilder, roundedRect, segment.mColor, + segment.mStartBevel, aBorderParams.mAppUnitsPerDevPixel, aBorderParams.mBackfaceIsVisible, true); - AdjustAndPushBevel(aBuilder, r, segment.mColor, segment.mEndBevel, + AdjustAndPushBevel(aBuilder, roundedRect, segment.mColor, segment.mEndBevel, aBorderParams.mAppUnitsPerDevPixel, aBorderParams.mBackfaceIsVisible, false); - aBuilder.PushRect(r, r, aBorderParams.mBackfaceIsVisible, color); + aBuilder.PushRect(roundedRect, roundedRect, + aBorderParams.mBackfaceIsVisible, color); } } @@ -6952,7 +6953,7 @@ static void CreateWRCommandsForBorderSegment( auto borderRect = LayoutDeviceRect::FromUnknownRect(NSRectToRect( aBorderParams.mBorderRect + aOffset, aBorderParams.mAppUnitsPerDevPixel)); - wr::LayoutRect r = wr::ToLayoutRect(borderRect); + wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(borderRect); wr::BorderSide wrSide[4]; NS_FOR_CSS_SIDES(i) { wrSide[i] = wr::ToBorderSide(ToDeviceColor(aBorderParams.mBorderColor), @@ -6960,7 +6961,8 @@ static void CreateWRCommandsForBorderSegment( } const bool horizontal = aBorderParams.mStartBevelSide == eSideTop || aBorderParams.mStartBevelSide == eSideBottom; - auto borderWidth = horizontal ? r.size.height : r.size.width; + auto borderWidth = + horizontal ? roundedRect.size.height : roundedRect.size.width; // All border style is set to none except left side. So setting the widths of // each side to width of rect is fine. @@ -6976,8 +6978,9 @@ static void CreateWRCommandsForBorderSegment( } Range wrsides(wrSide, 4); - aBuilder.PushBorder(r, r, aBorderParams.mBackfaceIsVisible, borderWidths, - wrsides, wr::EmptyBorderRadius()); + aBuilder.PushBorder(roundedRect, roundedRect, + aBorderParams.mBackfaceIsVisible, borderWidths, wrsides, + wr::EmptyBorderRadius()); } void BCBlockDirSeg::CreateWebRenderCommands( diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp index b35a33b21109..da347e8fd3ad 100644 --- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -418,6 +418,7 @@ ImgDrawResult nsImageBoxFrame::CreateWebRenderCommands( const int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel(); LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(dest, appUnitsPerDevPixel); + fillRect.Round(); Maybe svgContext; gfx::IntSize decodeSize = @@ -441,9 +442,12 @@ ImgDrawResult nsImageBoxFrame::CreateWebRenderCommands( if (key.isNothing()) { return result; } - wr::LayoutRect fill = wr::ToLayoutRect(fillRect); - aBuilder.PushImage(fill, fill, !BackfaceIsHidden(), rendering, key.value()); + + LayoutDeviceSize gapSize(0, 0); + aBuilder.PushImage(fill, fill, !BackfaceIsHidden(), + wr::ToLayoutSize(fillRect.Size()), + wr::ToLayoutSize(gapSize), rendering, key.value()); return result; } diff --git a/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini b/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini index 163d3bd65264..556f93e2ad86 100644 --- a/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini +++ b/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini @@ -2,5 +2,3 @@ expected: if (os == "android") and not e10s: FAIL if (os == "android") and e10s: PASS - fuzzy: - if webrender: maxDifference=65;totalPixels=340 diff --git a/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini b/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini deleted file mode 100644 index 7386c953e815..000000000000 --- a/testing/web-platform/meta/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mix-blend-mode-parent-with-3D-transform.html] - fuzzy: - if webrender: maxDifference=56;totalPixels=340 diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm index 7770257c19b2..cb2dae0dccc8 100644 --- a/widget/cocoa/nsNativeThemeCocoa.mm +++ b/widget/cocoa/nsNativeThemeCocoa.mm @@ -3436,8 +3436,8 @@ bool nsNativeThemeCocoa::CreateWebRenderCommandsForWidget( mozilla::layers::RenderRootStateManager* aManager, nsIFrame* aFrame, StyleAppearance aAppearance, const nsRect& aRect) { nsPresContext* presContext = aFrame->PresContext(); - wr::LayoutRect bounds = - wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(aRect, presContext->AppUnitsPerDevPixel())); + wr::LayoutRect bounds = wr::ToRoundedLayoutRect( + LayoutDeviceRect::FromAppUnits(aRect, presContext->AppUnitsPerDevPixel())); EventStates eventState = GetContentState(aFrame, aAppearance); diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp index 583844d1d34b..b45f93b5b244 100644 --- a/widget/gtk/nsNativeThemeGTK.cpp +++ b/widget/gtk/nsNativeThemeGTK.cpp @@ -1243,8 +1243,9 @@ bool nsNativeThemeGTK::CreateWebRenderCommandsForWidget( mozilla::layers::RenderRootStateManager* aManager, nsIFrame* aFrame, StyleAppearance aAppearance, const nsRect& aRect) { nsPresContext* presContext = aFrame->PresContext(); - wr::LayoutRect bounds = wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits( - aRect, presContext->AppUnitsPerDevPixel())); + wr::LayoutRect bounds = + wr::ToRoundedLayoutRect(LayoutDeviceRect::FromAppUnits( + aRect, presContext->AppUnitsPerDevPixel())); switch (aAppearance) { case StyleAppearance::Window: