Bug 902525 - Part 1: Layers changes r=roc
authorRik Cabanier <cabanier@adobe.com>
Sat, 14 Sep 2013 20:23:46 -0700
changeset 156055 b9121c28d2d3c35d5e494a1e050405e4b94aeeb4
parent 156054 104e23b7018783aabca4f2d1fd5364fedeb0ab0b
child 156056 3fc6876a6b9b42b4c21b06311b13356414f5cc87
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs902525
milestone26.0a1
Bug 902525 - Part 1: Layers changes r=roc
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicContainerLayer.cpp
gfx/layers/basic/BasicThebesLayer.cpp
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -176,16 +176,17 @@ Layer::Layer(LayerManager* aManager, voi
   mParent(nullptr),
   mNextSibling(nullptr),
   mPrevSibling(nullptr),
   mImplData(aImplData),
   mMaskLayer(nullptr),
   mPostXScale(1.0f),
   mPostYScale(1.0f),
   mOpacity(1.0),
+  mMixBlendMode(gfxContext::OPERATOR_OVER),
   mContentFlags(0),
   mUseClipRect(false),
   mUseTileSourceRect(false),
   mIsFixedPosition(false),
   mMargins(0, 0, 0, 0),
   mStickyPositionData(nullptr),
   mDebugColorIndex(0),
   mAnimationGeneration(0)
@@ -675,16 +676,30 @@ Layer::GetEffectiveOpacity()
 {
   float opacity = GetLocalOpacity();
   for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
        c = c->GetParent()) {
     opacity *= c->GetLocalOpacity();
   }
   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)
 {
   if (mMaskLayer) {
     mMaskLayer->mEffectiveTransform = aTransformToSurface;
 
 #ifdef DEBUG
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -7,16 +7,17 @@
 #define GFX_LAYERS_H
 
 #include <stdint.h>                     // for uint32_t, uint64_t, uint8_t
 #include <stdio.h>                      // for FILE
 #include <sys/types.h>                  // for int32_t, int64_t
 #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
 #include "gfxPattern.h"                 // for gfxPattern, etc
 #include "gfxPoint.h"                   // for gfxPoint, gfxIntSize
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2, etc
 #include "mozilla/DebugOnly.h"          // for DebugOnly
@@ -727,16 +728,25 @@ public:
   {
     if (mOpacity != aOpacity) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Opacity", this));
       mOpacity = aOpacity;
       Mutated();
     }
   }
 
+  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
    * composited to the destination. The coordinates are relative to
    * the parent layer (i.e. the contents of this layer
    * are transformed before this clip rect is applied).
    * For the root layer, the coordinates are relative to the widget,
    * in device pixels.
@@ -932,16 +942,17 @@ public:
       mStickyPositionData->mOuter = aOuter;
       mStickyPositionData->mInner = aInner;
       Mutated();
     }
   }
 
   // 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; }
   ContainerLayer* GetParent() { return mParent; }
   Layer* GetNextSibling() { return mNextSibling; }
   const Layer* GetNextSibling() const { return mNextSibling; }
   Layer* GetPrevSibling() { return mPrevSibling; }
   const Layer* GetPrevSibling() const { return mPrevSibling; }
@@ -1097,21 +1108,28 @@ public:
    */
   virtual ShadowableLayer* AsShadowableLayer() { return nullptr; }
 
   // These getters can be used anytime.  They return the effective
   // values that should be used when drawing this layer to screen,
   // 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
    * this layer all the way to some intermediate surface or destination
    * surface. For non-BasicLayers this will be a transform to the nearest
    * ancestor with UseIntermediateSurface() (or to the root, if there is no
    * such ancestor), but for BasicLayers it's different.
    */
@@ -1299,16 +1317,17 @@ protected:
   // meantime).
   nsAutoPtr<gfx3DMatrix> mPendingTransform;
   float mPostXScale;
   float mPostYScale;
   gfx3DMatrix mEffectiveTransform;
   AnimationArray mAnimations;
   InfallibleTArray<AnimData> mAnimationData;
   float mOpacity;
+  gfxContext::GraphicsOperator mMixBlendMode;
   nsIntRect mClipRect;
   nsIntRect mTileSourceRect;
   nsIntRegion mInvalidRegion;
   uint32_t mContentFlags;
   bool mUseClipRect;
   bool mUseTileSourceRect;
   bool mIsFixedPosition;
   LayerPoint mAnchor;
--- a/gfx/layers/basic/BasicContainerLayer.cpp
+++ b/gfx/layers/basic/BasicContainerLayer.cpp
@@ -52,26 +52,34 @@ BasicContainerLayer::ComputeEffectiveTra
   }
 
   mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
   // We always pass the ideal matrix down to our children, so there is no
   // need to apply any compensation using the residual from SnapTransformTranslation.
   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
 BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect)
 {
   gfxMatrix transform;
   if (!GetEffectiveTransform().CanDraw2D(&transform) ||
       transform.HasNonIntegerTranslation())
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -104,17 +104,18 @@ BasicThebesLayer::PaintThebes(gfxContext
   // this duplication.
   mContentClient->SyncFrontBufferToBackBuffer();
 
   bool canUseOpaqueSurface = CanUseOpaqueSurface();
   ContentType contentType =
     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");
 
     mValidRegion.SetEmpty();
     mContentClient->Clear();
 
     nsIntRegion toDraw = IntersectWithClip(GetEffectiveVisibleRegion(), aContext);
 
@@ -125,36 +126,36 @@ BasicThebesLayer::PaintThebes(gfxContext
         BasicManager()->SetTransactionIncomplete();
         return;
       }
 
       aContext->Save();
 
       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<gfxContext> 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 {
         groupContext = aContext;
       }
       SetAntialiasingFlags(this, groupContext);
       aCallback(this, groupContext, toDraw, nsIntRegion(), aCallbackData);
       if (needsGroup) {
         BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext);
         if (needsClipToVisibleRegion) {
           gfxUtils::ClipToRegion(aContext, toDraw);
         }
-        AutoSetOperator setOperator(aContext, GetOperator());
+        AutoSetOperator setOptimizedOperator(aContext, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : GetOperator());
         PaintWithMask(aContext, opacity, aMaskLayer);
       }
 
       aContext->Restore();
     }
 
     RenderTraceInvalidateEnd(this, "FFFF00");
     return;