Bug 1248913 - Build nsDisplayBlendMode items for background-blend-mode. r?mattwoodrow draft
authorMarkus Stange <mstange@themasta.com>
Tue, 08 Mar 2016 14:22:36 -0500
changeset 338211 27451f1e4e593428721e50e4d46560b038346ec4
parent 338210 db35763f2c33d830197ceb2d9a0e45d065846e11
child 338212 6c4eaddc442bba642cbda41426a848be490cf8dc
push id12468
push usermstange@themasta.com
push dateTue, 08 Mar 2016 19:59:01 +0000
reviewersmattwoodrow
bugs1248913
milestone47.0a1
Bug 1248913 - Build nsDisplayBlendMode items for background-blend-mode. r?mattwoodrow MozReview-Commit-ID: 72IzlcgHFtd
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsCanvasFrame.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2478,16 +2478,19 @@ nsDisplayBackgroundImage::AppendBackgrou
     aList->AppendToTop(&bgItemList);
     return true;
   }
 
   if (!bg) {
     aList->AppendToTop(&bgItemList);
     return false;
   }
+
+  const DisplayItemScrollClip* scrollClip =
+    aBuilder->ClipState().GetCurrentInnermostScrollClip();
  
   bool needBlendContainer = false;
 
   // Passing bg == nullptr in this macro will result in one iteration with
   // i = 0.
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
     if (bg->mImage.mLayers[i].mImage.IsEmpty()) {
       continue;
@@ -2499,30 +2502,39 @@ nsDisplayBackgroundImage::AppendBackgrou
 
     DisplayListClipState::AutoSaveRestore clipState(aBuilder);
     if (!aBuilder->IsForEventDelivery()) {
       const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i];
       SetBackgroundClipRegion(clipState, aFrame, toRef,
                               layer, willPaintBorder);
     }
 
+    nsDisplayList thisItemList;
     nsDisplayBackgroundImage* bgItem =
       new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bg);
 
     if (bgItem->ShouldFixToViewport(aBuilder)) {
-      bgItemList.AppendNewToTop(
+      thisItemList.AppendNewToTop(
         nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, aFrame, bgItem, i));
     } else {
-      bgItemList.AppendNewToTop(bgItem);
+      thisItemList.AppendNewToTop(bgItem);
     }
+
+    if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
+      thisItemList.AppendNewToTop(
+        new (aBuilder) nsDisplayBlendMode(aBuilder, aFrame, &thisItemList,
+                                          bg->mImage.mLayers[i].mBlendMode,
+                                          scrollClip, i + 1));
+    }
+    bgItemList.AppendToTop(&thisItemList);
   }
 
   if (needBlendContainer) {
     bgItemList.AppendNewToTop(
-      new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, &bgItemList));
+      new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, &bgItemList, scrollClip));
   }
 
   aList->AppendToTop(&bgItemList);
   return false;
 }
 
 // Check that the rounded border of aFrame, added to aToReferenceFrame,
 // intersects aRect.  Assumes that the unrounded border has already
@@ -2970,23 +2982,22 @@ nsDisplayBackgroundImage::Paint(nsDispla
 void
 nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
                                         nsRenderingContext* aCtx, const nsRect& aBounds,
                                         nsRect* aClipRect) {
   nsPoint offset = ToReferenceFrame();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   CheckForBorderItem(this, flags);
 
-  const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
   image::DrawResult result =
     nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
                                     aBounds,
                                     nsRect(offset, mFrame->GetSize()),
                                     flags, aClipRect, mLayer,
-                                    nsCSSRendering::GetGFXBlendMode(layer.mBlendMode));
+                                    CompositionOp::OP_OVER);
 
   nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
 }
 
 void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                          const nsDisplayItemGeometry* aGeometry,
                                                          nsRegion* aInvalidRegion)
 {
@@ -4320,19 +4331,21 @@ void
 nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream)
 {
   aStream << " (opacity " << mOpacity << ")";
 }
 
 nsDisplayBlendMode::nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
                                              nsIFrame* aFrame, nsDisplayList* aList,
                                              uint8_t aBlendMode,
-                                             const DisplayItemScrollClip* aScrollClip)
+                                             const DisplayItemScrollClip* aScrollClip,
+                                             uint32_t aIndex)
   : nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
   , mBlendMode(aBlendMode)
+  , mIndex(aIndex)
 {
   MOZ_COUNT_CTOR(nsDisplayBlendMode);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayBlendMode::~nsDisplayBlendMode() {
   MOZ_COUNT_DTOR(nsDisplayBlendMode);
 }
@@ -4384,26 +4397,28 @@ bool nsDisplayBlendMode::ComputeVisibili
   nsRegion visibleUnderChildren;
   visibleUnderChildren.And(*aVisibleRegion, bounds);
   return nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
 }
 
 bool nsDisplayBlendMode::TryMerge(nsDisplayItem* aItem) {
   if (aItem->GetType() != TYPE_BLEND_MODE)
     return false;
+  nsDisplayBlendMode* item = static_cast<nsDisplayBlendMode*>(aItem);
   // items for the same content element should be merged into a single
   // compositing group
-  // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
-  if (aItem->Frame()->GetContent() != mFrame->GetContent())
+  if (item->Frame()->GetContent() != mFrame->GetContent())
     return false;
-  if (aItem->GetClip() != GetClip())
+  if (item->mIndex != 0 || mIndex != 0)
+    return false; // don't merge background-blend-mode items
+  if (item->GetClip() != GetClip())
     return false;
-  if (aItem->ScrollClip() != ScrollClip())
+  if (item->ScrollClip() != ScrollClip())
     return false;
-  MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendMode*>(aItem));
+  MergeFromTrackingMergedFrames(item);
   return true;
 }
 
 nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
                                                  nsIFrame* aFrame, nsDisplayList* aList,
                                                  const DisplayItemScrollClip* aScrollClip)
     : nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
     , mIndex(0)
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -3387,46 +3387,52 @@ private:
   float mOpacity;
   bool mForEventsOnly;
 };
 
 class nsDisplayBlendMode : public nsDisplayWrapList {
 public:
   nsDisplayBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                         nsDisplayList* aList, uint8_t aBlendMode,
-                        const DisplayItemScrollClip* aScrollClip);
+                        const DisplayItemScrollClip* aScrollClip,
+                        uint32_t aIndex = 0);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayBlendMode();
 #endif
 
   nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) override;
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) override
   {
     // We don't need to compute an invalidation region since we have LayerTreeInvalidation
   }
+  virtual uint32_t GetPerFrameKey() override {
+    return (mIndex << nsDisplayItem::TYPE_BITS) |
+      nsDisplayItem::GetPerFrameKey();
+  }
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion) override;
   virtual bool TryMerge(nsDisplayItem* aItem) override;
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
   NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE)
 
 private:
   uint8_t mBlendMode;
+  uint32_t mIndex;
 };
 
 class nsDisplayBlendContainer : public nsDisplayWrapList {
 public:
     // Use this constructor for blend containers that can have active child layers.
     nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                             nsDisplayList* aList,
                             const DisplayItemScrollClip* aScrollClip);
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -402,40 +402,54 @@ nsCanvasFrame::BuildDisplayList(nsDispla
         new (aBuilder) nsDisplayCanvasThemedBackground(aBuilder, this));
       return;
     }
 
     if (!bg) {
       return;
     }
 
+    const DisplayItemScrollClip* scrollClip =
+      aBuilder->ClipState().GetCurrentInnermostScrollClip();
+
     bool needBlendContainer = false;
 
     // Create separate items for each background layer.
     const nsStyleImageLayers& layers = bg->mImage;
     NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) {
       if (layers.mLayers[i].mImage.IsEmpty()) {
         continue;
       }
       if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
         needBlendContainer = true;
       }
+
+      nsDisplayList thisItemList;
       nsDisplayCanvasBackgroundImage* bgItem =
         new (aBuilder) nsDisplayCanvasBackgroundImage(aBuilder, this, i, bg);
       if (bgItem->ShouldFixToViewport(aBuilder)) {
-        aLists.BorderBackground()->AppendNewToTop(
+        thisItemList.AppendNewToTop(
           nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, this, bgItem, i));
       } else {
-        aLists.BorderBackground()->AppendNewToTop(bgItem);
+        thisItemList.AppendNewToTop(bgItem);
       }
+
+      if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
+        thisItemList.AppendNewToTop(
+          new (aBuilder) nsDisplayBlendMode(aBuilder, this, &thisItemList,
+                                            layers.mLayers[i].mBlendMode,
+                                            scrollClip, i + 1));
+      }
+      aLists.BorderBackground()->AppendToTop(&thisItemList);
     }
 
     if (needBlendContainer) {
       aLists.BorderBackground()->AppendNewToTop(
-        new (aBuilder) nsDisplayBlendContainer(aBuilder, this, aLists.BorderBackground()));
+        new (aBuilder) nsDisplayBlendContainer(aBuilder, this, aLists.BorderBackground(),
+                                               scrollClip));
     }
   }
 
   for (nsIFrame* kid : PrincipalChildList()) {
     // Put our child into its own pseudo-stack.
     BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   }