--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -273,16 +273,17 @@ AsyncImagePipelineManager::ApplyAsyncIma
MOZ_ASSERT(pipeline->mCurrentTexture.get());
float opacity = 1.0f;
builder.PushStackingContext(wr::ToLayoutRect(pipeline->mScBounds),
0,
&opacity,
pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
wr::TransformStyle::Flat,
+ nullptr,
pipeline->mMixBlendMode,
nsTArray<wr::WrFilterOp>());
LayerRect rect(0, 0, pipeline->mCurrentTexture->GetSize().width, pipeline->mCurrentTexture->GetSize().height);
if (pipeline->mScaleToSize.isSome()) {
rect = LayerRect(0, 0, pipeline->mScaleToSize.value().width, pipeline->mScaleToSize.value().height);
}
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -28,16 +28,17 @@ StackingContextHelper::StackingContextHe
wr::LayoutRect scBounds = aParentSC.ToRelativeLayoutRect(aLayer->BoundsForStackingContext());
Layer* layer = aLayer->GetLayer();
mTransform = aTransform.valueOr(layer->GetTransform());
float opacity = 1.0f;
mBuilder->PushStackingContext(scBounds, 0, &opacity,
mTransform.IsIdentity() ? nullptr : &mTransform,
wr::TransformStyle::Flat,
+ nullptr,
wr::ToMixBlendMode(layer->GetMixBlendMode()),
aFilters);
mOrigin = aLayer->Bounds().TopLeft();
}
StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC,
wr::DisplayListBuilder& aBuilder,
WebRenderLayer* aLayer,
@@ -52,56 +53,67 @@ StackingContextHelper::StackingContextHe
mTransform = *aTransformPtr;
}
mBuilder->PushStackingContext(scBounds,
aAnimationsId,
aOpacityPtr,
aTransformPtr,
wr::TransformStyle::Flat,
+ nullptr,
wr::ToMixBlendMode(aLayer->GetLayer()->GetMixBlendMode()),
aFilters);
mOrigin = aLayer->Bounds().TopLeft();
}
StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC,
wr::DisplayListBuilder& aBuilder,
nsDisplayListBuilder* aDisplayListBuilder,
nsDisplayItem* aItem,
nsDisplayList* aDisplayList,
gfx::Matrix4x4Typed<LayerPixel, LayerPixel>* aBoundTransform,
uint64_t aAnimationsId,
float* aOpacityPtr,
gfx::Matrix4x4* aTransformPtr,
+ gfx::Matrix4x4* aPerspectivePtr,
const nsTArray<wr::WrFilterOp>& aFilters,
const gfx::CompositionOp& aMixBlendMode)
: mBuilder(&aBuilder)
{
- nsRect itemBounds = aDisplayList->GetClippedBoundsWithRespectToASR(aDisplayListBuilder, aItem->GetActiveScrolledRoot());
- nsRect childrenVisible = aItem->GetVisibleRectForChildren();
- nsRect visibleRect = itemBounds.Intersect(childrenVisible);
+ nsRect visibleRect;
+ bool is2d = aTransformPtr && aTransformPtr->Is2D() && !aPerspectivePtr;
+ if (is2d) {
+ nsRect itemBounds = aDisplayList->GetClippedBoundsWithRespectToASR(aDisplayListBuilder, aItem->GetActiveScrolledRoot());
+ nsRect childrenVisible = aItem->GetVisibleRectForChildren();
+ visibleRect = itemBounds.Intersect(childrenVisible);
+ } else {
+ visibleRect = aDisplayList->GetBounds(aDisplayListBuilder);
+ // The position of bounds are calculated by transform and perspective matrix in 3d case. reset it to (0, 0)
+ visibleRect.MoveTo(0, 0);
+ }
float appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
LayerRect bounds = ViewAs<LayerPixel>(LayoutDeviceRect::FromAppUnits(visibleRect, appUnitsPerDevPixel),
PixelCastJustification::WebRenderHasUnitResolution);
// WR will only apply the 'translate' of the transform, so we need to do the scale/rotation manually.
- if (aBoundTransform && !aBoundTransform->IsIdentity()) {
+ if (aBoundTransform && !aBoundTransform->IsIdentity() && is2d) {
bounds.MoveTo(aBoundTransform->TransformPoint(bounds.TopLeft()));
}
wr::LayoutRect scBounds = aParentSC.ToRelativeLayoutRect(bounds);
if (aTransformPtr) {
mTransform = *aTransformPtr;
}
mBuilder->PushStackingContext(scBounds,
aAnimationsId,
aOpacityPtr,
aTransformPtr,
- wr::TransformStyle::Flat,
+ is2d ? wr::TransformStyle::Flat : wr::TransformStyle::Preserve3D,
+ aPerspectivePtr,
wr::ToMixBlendMode(aMixBlendMode),
aFilters);
mOrigin = bounds.TopLeft();
}
StackingContextHelper::~StackingContextHelper()
{
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -51,16 +51,17 @@ public:
wr::DisplayListBuilder& aBuilder,
nsDisplayListBuilder* aDisplayListBuilder,
nsDisplayItem* aItem,
nsDisplayList* aDisplayList,
gfx::Matrix4x4Typed<LayerPixel, LayerPixel>* aBoundTransform,
uint64_t aAnimationsId,
float* aOpacityPtr,
gfx::Matrix4x4* aTransformPtr,
+ gfx::Matrix4x4* aPerspectivePtr = nullptr,
const nsTArray<wr::WrFilterOp>& aFilters = nsTArray<wr::WrFilterOp>(),
const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER);
// This version of the constructor should only be used at the root level
// of the tree, so that we have a StackingContextHelper to pass down into
// the RenderLayer traversal, but don't actually want it to push a stacking
// context on the display list builder.
StackingContextHelper();
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -637,29 +637,35 @@ DisplayListBuilder::Finalize(wr::LayoutS
}
void
DisplayListBuilder::PushStackingContext(const wr::LayoutRect& aBounds,
const uint64_t& aAnimationId,
const float* aOpacity,
const gfx::Matrix4x4* aTransform,
wr::TransformStyle aTransformStyle,
+ const gfx::Matrix4x4* aPerspective,
const wr::MixBlendMode& aMixBlendMode,
const nsTArray<wr::WrFilterOp>& aFilters)
{
wr::LayoutTransform matrix;
if (aTransform) {
matrix = ToLayoutTransform(*aTransform);
}
const wr::LayoutTransform* maybeTransform = aTransform ? &matrix : nullptr;
+ wr::LayoutTransform perspective;
+ if (aPerspective) {
+ perspective = ToLayoutTransform(*aPerspective);
+ }
+ const wr::LayoutTransform* maybePerspective = aPerspective ? &perspective : nullptr;
WRDL_LOG("PushStackingContext b=%s t=%s\n", Stringify(aBounds).c_str(),
aTransform ? Stringify(*aTransform).c_str() : "none");
wr_dp_push_stacking_context(mWrState, aBounds, aAnimationId, aOpacity,
- maybeTransform, aTransformStyle, aMixBlendMode,
- aFilters.Elements(), aFilters.Length());
+ maybeTransform, aTransformStyle, maybePerspective,
+ aMixBlendMode, aFilters.Elements(), aFilters.Length());
}
void
DisplayListBuilder::PopStackingContext()
{
WRDL_LOG("PopStackingContext\n");
wr_dp_pop_stacking_context(mWrState);
}
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -168,16 +168,17 @@ public:
void Finalize(wr::LayoutSize& aOutContentSize,
wr::BuiltDisplayList& aOutDisplayList);
void PushStackingContext(const wr::LayoutRect& aBounds, // TODO: We should work with strongly typed rects
const uint64_t& aAnimationId,
const float* aOpacity,
const gfx::Matrix4x4* aTransform,
wr::TransformStyle aTransformStyle,
+ const gfx::Matrix4x4* aPerspective,
const wr::MixBlendMode& aMixBlendMode,
const nsTArray<wr::WrFilterOp>& aFilters);
void PopStackingContext();
wr::WrClipId DefineClip(const wr::LayoutRect& aClipRect,
const nsTArray<wr::WrComplexClipRegion>* aComplex = nullptr,
const wr::WrImageMask* aMask = nullptr);
void PushClip(const wr::WrClipId& aClipId);
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -990,16 +990,17 @@ pub extern "C" fn wr_dp_end(state: &mut
#[no_mangle]
pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
bounds: LayoutRect,
animation_id: u64,
opacity: *const f32,
transform: *const LayoutTransform,
transform_style: TransformStyle,
+ perspective: *const LayoutTransform,
mix_blend_mode: MixBlendMode,
filters: *const WrFilterOp,
filter_count: usize) {
assert!(unsafe { !is_in_render_thread() });
let bounds = bounds.into();
let c_filters = make_slice(filters, filter_count);
@@ -1030,23 +1031,28 @@ pub extern "C" fn wr_dp_push_stacking_co
let transform_binding = match animation_id {
0 => match transform {
Some(transform) => Some(PropertyBinding::Value(transform.clone())),
None => None,
},
_ => Some(PropertyBinding::Binding(PropertyBindingKey::new(animation_id))),
};
+ let perspective_ref = unsafe { perspective.as_ref() };
+ let perspective = match perspective_ref {
+ Some(perspective) => Some(perspective.clone()),
+ None => None,
+ };
state.frame_builder
.dl_builder
.push_stacking_context(webrender_api::ScrollPolicy::Scrollable,
bounds,
transform_binding,
transform_style,
- None,
+ perspective,
mix_blend_mode,
filters);
}
#[no_mangle]
pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
assert!(unsafe { !is_in_render_thread() });
state.frame_builder.dl_builder.pop_stacking_context();
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -938,16 +938,17 @@ WR_FUNC;
WR_INLINE
void wr_dp_push_stacking_context(WrState *aState,
LayoutRect aBounds,
uint64_t aAnimationId,
const float *aOpacity,
const LayoutTransform *aTransform,
TransformStyle aTransformStyle,
+ const LayoutTransform *aPerspective,
MixBlendMode aMixBlendMode,
const WrFilterOp *aFilters,
size_t aFilterCount)
WR_FUNC;
WR_INLINE
void wr_dp_push_text(WrState *aState,
LayoutRect aBounds,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6151,16 +6151,17 @@ nsDisplayOpacity::CreateWebRenderCommand
aBuilder,
aDisplayListBuilder,
this,
&mList,
nullptr,
animationsId,
opacityForSC,
nullptr,
+ nullptr,
filters);
aManager->CreateWebRenderCommandsFromDisplayList(&mList,
aDisplayListBuilder,
sc,
aBuilder);
return true;
}
@@ -6202,17 +6203,17 @@ bool
nsDisplayBlendMode::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc,
nsTArray<WebRenderParentCommand>& aParentCommands,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder)
{
nsTArray<mozilla::wr::WrFilterOp> filters;
StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this,
- &mList, nullptr, 0, nullptr, nullptr,
+ &mList, nullptr, 0, nullptr, nullptr, nullptr,
filters, nsCSSRendering::GetGFXBlendMode(mBlendMode));
return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, sc, aParentCommands,
aManager, aDisplayListBuilder);
}
// nsDisplayBlendMode uses layers for rendering
already_AddRefed<Layer>
@@ -7847,16 +7848,17 @@ nsDisplayTransform::CreateWebRenderComma
aBuilder,
aDisplayListBuilder,
this,
mStoredList.GetChildren(),
&boundTransform,
animationsId,
nullptr,
transformForSC,
+ nullptr,
filters);
return mStoredList.CreateWebRenderCommands(aBuilder, sc, aParentCommands,
aManager, aDisplayListBuilder);
}
already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
LayerManager *aManager,
@@ -8429,16 +8431,71 @@ nsDisplayPerspective::BuildLayer(nsDispl
LayerState
nsDisplayPerspective::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters)
{
return LAYER_ACTIVE_FORCE;
}
+bool
+nsDisplayPerspective::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ nsTArray<WebRenderParentCommand>& aParentCommands,
+ WebRenderLayerManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder)
+{
+ float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+ Matrix4x4 perspectiveMatrix;
+ DebugOnly<bool> hasPerspective =
+ nsDisplayTransform::ComputePerspectiveMatrix(mTransformFrame, appUnitsPerPixel,
+ perspectiveMatrix);
+ MOZ_ASSERT(hasPerspective, "Why did we create nsDisplayPerspective?");
+
+ /*
+ * ClipListToRange can remove our child after we were created.
+ */
+ if (!mList.GetChildren()->GetTop()) {
+ return false;
+ }
+
+ /*
+ * The resulting matrix is still in the coordinate space of the transformed
+ * frame. Append a translation to the reference frame coordinates.
+ */
+ nsDisplayTransform* transform =
+ static_cast<nsDisplayTransform*>(mList.GetChildren()->GetTop());
+
+ Point3D newOrigin =
+ Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x, appUnitsPerPixel),
+ NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y, appUnitsPerPixel),
+ 0.0f);
+ Point3D roundedOrigin(NS_round(newOrigin.x),
+ NS_round(newOrigin.y),
+ 0);
+
+ gfx::Matrix4x4 transformForSC = gfx::Matrix4x4::Translation(roundedOrigin);
+
+ nsTArray<mozilla::wr::WrFilterOp> filters;
+ StackingContextHelper sc(aSc,
+ aBuilder,
+ aDisplayListBuilder,
+ this,
+ mList.GetChildren(),
+ nullptr,
+ 0,
+ nullptr,
+ &transformForSC,
+ &perspectiveMatrix,
+ filters);
+
+ return mList.CreateWebRenderCommands(aBuilder, sc, aParentCommands,
+ aManager, aDisplayListBuilder);
+}
+
int32_t
nsDisplayPerspective::ZIndex() const
{
return ZIndexForFrame(mTransformFrame);
}
nsDisplayItemGeometry*
nsCharClipDisplayItem::AllocateGeometry(nsDisplayListBuilder* aBuilder)
@@ -9193,16 +9250,17 @@ nsDisplayFilter::CreateWebRenderCommands
aBuilder,
aDisplayListBuilder,
this,
&mList,
nullptr,
0,
nullptr,
nullptr,
+ nullptr,
wrFilters);
nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, sc, aParentCommands, aManager, aDisplayListBuilder);
return true;
}
#ifdef MOZ_DUMP_PAINTING
void
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -5041,16 +5041,21 @@ public:
virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override
{
return mList.IsUniform(aBuilder);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) override;
+ bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ nsTArray<WebRenderParentCommand>& aParentCommands,
+ mozilla::layers::WebRenderLayerManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) override
{
if (!mList.GetChildren()->GetTop()) {
return false;
}
return mList.GetChildren()->GetTop()->ShouldBuildLayerEvenIfInvisible(aBuilder);
}