From 492ade5e962c8779eafb43719e970667be1f2687 Mon Sep 17 00:00:00 2001 From: Rik Cabanier Date: Sun, 15 Sep 2013 16:23:52 -0400 Subject: [PATCH] Bug 902525 - Part 1: Layers changes. r=roc --- gfx/layers/Layers.cpp | 15 +++++++++++++++ gfx/layers/Layers.h | 19 +++++++++++++++++++ gfx/layers/basic/BasicContainerLayer.cpp | 14 +++++++++++--- gfx/layers/basic/BasicThebesLayer.cpp | 9 +++++---- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 39ca3b95eccf..e98d30d07548 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -181,6 +181,7 @@ Layer::Layer(LayerManager* aManager, void* aImplData) : mPostXScale(1.0f), mPostYScale(1.0f), mOpacity(1.0), + mMixBlendMode(gfxContext::OPERATOR_OVER), mContentFlags(0), mUseClipRect(false), mUseTileSourceRect(false), @@ -680,6 +681,20 @@ Layer::GetEffectiveOpacity() } return opacity; } + +gfxContext::GraphicsOperator +Layer::GetEffectiveMixBlendMode() +{ + if(mMixBlendMode != gfxContext::OPERATOR_OVER) + return mMixBlendMode; + for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface(); + c = c->GetParent()) { + if(c->mMixBlendMode != gfxContext::OPERATOR_OVER) + return c->mMixBlendMode; + } + + return mMixBlendMode; +} void Layer::ComputeEffectiveTransformForMaskLayer(const gfx3DMatrix& aTransformToSurface) diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index a55c13fc92b9..52818f9ba4c0 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -12,6 +12,7 @@ #include "FrameMetrics.h" // for FrameMetrics #include "Units.h" // for LayerMargin, LayerPoint #include "gfx3DMatrix.h" // for gfx3DMatrix +#include "gfxContext.h" // for GraphicsOperator #include "gfxASurface.h" // for gfxASurface, etc #include "gfxColor.h" // for gfxRGBA #include "gfxMatrix.h" // for gfxMatrix @@ -732,6 +733,15 @@ public: } } + void SetMixBlendMode(gfxContext::GraphicsOperator aMixBlendMode) + { + if (mMixBlendMode != aMixBlendMode) { + MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) MixBlendMode", this)); + mMixBlendMode = aMixBlendMode; + Mutated(); + } + } + /** * CONSTRUCTION PHASE ONLY * Set a clip rect which will be applied to this layer as it is @@ -937,6 +947,7 @@ public: // These getters can be used anytime. float GetOpacity() { return mOpacity; } + gfxContext::GraphicsOperator GetMixBlendMode() const { return mMixBlendMode; } const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nullptr; } uint32_t GetContentFlags() { return mContentFlags; } const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; } @@ -1102,11 +1113,18 @@ public: // accounting for this layer possibly being a shadow. const nsIntRect* GetEffectiveClipRect(); const nsIntRegion& GetEffectiveVisibleRegion(); + /** * Returns the product of the opacities of this layer and all ancestors up * to and excluding the nearest ancestor that has UseIntermediateSurface() set. */ float GetEffectiveOpacity(); + + /** + * Returns the blendmode of this layer. + */ + gfxContext::GraphicsOperator GetEffectiveMixBlendMode(); + /** * This returns the effective transform computed by * ComputeEffectiveTransforms. Typically this is a transform that transforms @@ -1304,6 +1322,7 @@ protected: AnimationArray mAnimations; InfallibleTArray mAnimationData; float mOpacity; + gfxContext::GraphicsOperator mMixBlendMode; nsIntRect mClipRect; nsIntRect mTileSourceRect; nsIntRegion mInvalidRegion; diff --git a/gfx/layers/basic/BasicContainerLayer.cpp b/gfx/layers/basic/BasicContainerLayer.cpp index 6973aad37f03..0d371f27e315 100644 --- a/gfx/layers/basic/BasicContainerLayer.cpp +++ b/gfx/layers/basic/BasicContainerLayer.cpp @@ -57,16 +57,24 @@ BasicContainerLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToS ComputeEffectiveTransformsForChildren(idealTransform); ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + + Layer* child = GetFirstChild(); + bool hasSingleBlendingChild = false; + if (!HasMultipleChildren() && child) { + hasSingleBlendingChild = child->GetMixBlendMode() != gfxContext::OPERATOR_OVER; + } - /* If we have a single child, it can just inherit our opacity, + /* If we have a single childand it is not blending,, it can just inherit our opacity, * otherwise we need a PushGroup and we need to mark ourselves as using * an intermediate surface so our children don't inherit our opacity * via GetEffectiveOpacity. * Having a mask layer always forces our own push group + * Having a blend mode also always forces our own push group */ mUseIntermediateSurface = - GetMaskLayer() || (GetEffectiveOpacity() != 1.0 && - HasMultipleChildren()); + GetMaskLayer() || + (GetMixBlendMode() != gfxContext::OPERATOR_OVER && HasMultipleChildren()) || + (GetEffectiveOpacity() != 1.0 && (HasMultipleChildren() || hasSingleBlendingChild)); } bool diff --git a/gfx/layers/basic/BasicThebesLayer.cpp b/gfx/layers/basic/BasicThebesLayer.cpp index 7b0010e93051..775fe418ece9 100644 --- a/gfx/layers/basic/BasicThebesLayer.cpp +++ b/gfx/layers/basic/BasicThebesLayer.cpp @@ -109,7 +109,8 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, canUseOpaqueSurface ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA; float opacity = GetEffectiveOpacity(); - + gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode(); + if (!BasicManager()->IsRetained()) { NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer"); @@ -130,13 +131,13 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, bool needsClipToVisibleRegion = GetClipToVisibleRegion(); bool needsGroup = - opacity != 1.0 || GetOperator() != gfxContext::OPERATOR_OVER || aMaskLayer; + opacity != 1.0 || GetOperator() != gfxContext::OPERATOR_OVER || mixBlendMode != gfxContext::OPERATOR_OVER || aMaskLayer; nsRefPtr groupContext; if (needsGroup) { groupContext = BasicManager()->PushGroupForLayer(aContext, this, toDraw, &needsClipToVisibleRegion); - if (GetOperator() != gfxContext::OPERATOR_OVER) { + if (GetOperator() != gfxContext::OPERATOR_OVER || mixBlendMode != gfxContext::OPERATOR_OVER) { needsClipToVisibleRegion = true; } } else { @@ -149,7 +150,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, if (needsClipToVisibleRegion) { gfxUtils::ClipToRegion(aContext, toDraw); } - AutoSetOperator setOperator(aContext, GetOperator()); + AutoSetOperator setOptimizedOperator(aContext, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : GetOperator()); PaintWithMask(aContext, opacity, aMaskLayer); }