Bug 945203. Part 8: Add FrameLayerBuilder support for capturing nsDisplayEventRegions data into ThebesLayers. r=mattwoodrow
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 17 Dec 2013 01:16:24 +1300
changeset 161856 722d9c9944c165125097a16178d2aaf0356cdea5
parent 161855 265f3a2040b413ee8507946b2cdadb0fb03f6637
child 161857 370686e09ca4f8fb1ad87c828b44d8b27f256d9c
push idunknown
push userunknown
push dateunknown
reviewersmattwoodrow
bugs945203
milestone29.0a1
Bug 945203. Part 8: Add FrameLayerBuilder support for capturing nsDisplayEventRegions data into ThebesLayers. r=mattwoodrow
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -258,16 +258,29 @@ public:
   void Accumulate(ContainerState* aState,
                   nsDisplayItem* aItem,
                   const nsIntRect& aVisibleRect,
                   const nsIntRect& aDrawRect,
                   const DisplayItemClip& aClip);
   const nsIFrame* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
 
   /**
+   * Add aHitRegion and aDispatchToContentHitRegion to the hit regions for
+   * this ThebesLayer.
+   */
+  void AccumulateEventRegions(const nsIntRegion& aHitRegion,
+                              const nsIntRegion& aMaybeHitRegion,
+                              const nsIntRegion& aDispatchToContentHitRegion)
+  {
+    mHitRegion.Or(mHitRegion, aHitRegion);
+    mMaybeHitRegion.Or(mMaybeHitRegion, aMaybeHitRegion);
+    mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aDispatchToContentHitRegion);
+  }
+
+  /**
    * If this represents only a nsDisplayImage, and the image type
    * supports being optimized to an ImageLayer (TYPE_RASTER only) returns
    * an ImageContainer for the image.
    */
   already_AddRefed<ImageContainer> CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder);
 
   void AddDrawAboveRegion(const nsIntRegion& aAbove)
   {
@@ -338,16 +351,28 @@ public:
    */
   nsIntRegion  mDrawRegion;
   /**
    * The region of visible content in the layer that is opaque.
    * Same coordinate system as mVisibleRegion.
    */
   nsIntRegion  mOpaqueRegion;
   /**
+   * The definitely-hit region for this ThebesLayer.
+   */
+  nsIntRegion  mHitRegion;
+  /**
+   * The maybe-hit region for this ThebesLayer.
+   */
+  nsIntRegion  mMaybeHitRegion;
+  /**
+   * The dispatch-to-content hit region for this ThebesLayer.
+   */
+  nsIntRegion  mDispatchToContentHitRegion;
+  /**
    * The "active scrolled root" for all content in the layer. Must
    * be non-null; all content in a ThebesLayer must have the same
    * active scrolled root.
    */
   const nsIFrame* mAnimatedGeometryRoot;
   const nsIFrame* mReferenceFrame;
   ThebesLayer* mLayer;
   /**
@@ -612,18 +637,16 @@ protected:
    * @param aAnimatedGeometryRoot the active scrolled root for the next
    * display item
    * @param aOpaqueRect if non-null, a region of the display item that is opaque
    * @param aSolidColor if non-null, indicates that every pixel in aVisibleRect
    * will be painted with aSolidColor by the item
    */
   ThebesLayerData* FindThebesLayerFor(nsDisplayItem* aItem,
                                       const nsIntRect& aVisibleRect,
-                                      const nsIntRect& aDrawRect,
-                                      const DisplayItemClip& aClip,
                                       const nsIFrame* aAnimatedGeometryRoot,
                                       const nsPoint& aTopLeft);
   ThebesLayerData* GetTopThebesLayerData()
   {
     return mThebesLayerDataStack.IsEmpty() ? nullptr
         : mThebesLayerDataStack[mThebesLayerDataStack.Length() - 1].get();
   }
 
@@ -820,23 +843,25 @@ FrameLayerBuilder::Shutdown()
 {
   if (gMaskLayerImageCache) {
     delete gMaskLayerImageCache;
     gMaskLayerImageCache = nullptr;
   }
 }
 
 void
-FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager)
+FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+                        ThebesLayerData* aLayerData)
 {
   mDisplayListBuilder = aBuilder;
   mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext();
   if (mRootPresContext) {
     mInitialDOMGeneration = mRootPresContext->GetDOMGeneration();
   }
+  mContainingThebesLayer = aLayerData;
   aManager->SetUserData(&gLayerManagerLayerBuilder, this);
 }
 
 void
 FrameLayerBuilder::FlashPaint(gfxContext *aContext)
 {
   float r = float(rand()) / RAND_MAX;
   float g = float(rand()) / RAND_MAX;
@@ -1681,16 +1706,44 @@ ContainerState::SetFixedPositionLayerDat
     viewportSize = presContext->PresShell()->
       GetScrollPositionClampingScrollPortSize();
   }
 
   nsLayoutUtils::SetFixedPositionLayerData(aLayer,
       viewportFrame, viewportSize, aFixedPosFrame, presContext, mParameters);
 }
 
+static gfx3DMatrix
+GetTransformToRoot(Layer* aLayer)
+{
+  gfx3DMatrix transform = aLayer->GetTransform();
+  for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
+    transform = transform * l->GetTransform();
+  }
+  return transform;
+}
+
+static void
+AddTransformedBoundsToRegion(const nsIntRegion& aRegion,
+                             const gfx3DMatrix& aTransform,
+                             nsIntRegion* aDest)
+{
+  nsIntRect bounds = aRegion.GetBounds();
+  gfxRect transformed =
+    aTransform.TransformBounds(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
+  transformed.RoundOut();
+  nsIntRect intRect;
+  if (!gfxUtils::GfxRectToIntRect(transformed, &intRect)) {
+    // This should only fail if coordinates are too big to fit in an int32
+    *aDest = nsIntRect(-INT32_MAX/2, -INT32_MAX/2, INT32_MAX, INT32_MAX);
+    return;
+  }
+  aDest->Or(*aDest, intRect);
+}
+
 void
 ContainerState::PopThebesLayerData()
 {
   NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
 
   int32_t lastIndex = mThebesLayerDataStack.Length() - 1;
   ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
 
@@ -1742,16 +1795,17 @@ ContainerState::PopThebesLayerData()
     NS_ASSERTION(index != AutoLayersArray::NoIndex, "Thebes layer not found?");
     mNewChildLayers.InsertElementAt(index + 1, layer);
 
     // Hide the ThebesLayer. We leave it in the layer tree so that we
     // can find and recycle it later.
     nsIntRect emptyRect;
     data->mLayer->SetClipRect(&emptyRect);
     data->mLayer->SetVisibleRegion(nsIntRegion());
+    data->mLayer->SetEventRegions(EventRegions());
   } else {
     layer = data->mLayer;
     imageContainer = nullptr;
     layer->SetClipRect(nullptr);
   }
 
   gfxMatrix transform;
   if (!layer->GetTransform().Is2D(&transform)) {
@@ -1790,19 +1844,20 @@ ContainerState::PopThebesLayerData()
     NS_ASSERTION(userData, "where did our user data go?");
     if (userData->mForcedBackgroundColor != backgroundColor) {
       // Invalidate the entire target ThebesLayer since we're changing
       // the background color
       data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion());
     }
     userData->mForcedBackgroundColor = backgroundColor;
 
-    // use a mask layer for rounded rect clipping
-    int32_t commonClipCount = data->mCommonClipCount;
-    NS_ASSERTION(commonClipCount >= 0, "Inconsistent clip count.");
+    // use a mask layer for rounded rect clipping.
+    // data->mCommonClipCount may be -1 if we haven't put any actual
+    // drawable items in this layer (i.e. it's only catching events).
+    int32_t commonClipCount = std::max(0, data->mCommonClipCount);
     SetupMaskLayer(layer, data->mItemClip, commonClipCount);
     // copy commonClipCount to the entry
     FrameLayerBuilder::ThebesLayerItemsEntry* entry = mLayerBuilder->
       GetThebesLayerItemsEntry(static_cast<ThebesLayer*>(layer.get()));
     entry->mCommonClipCount = commonClipCount;
   } else {
     // mask layer for image and color layers
     SetupMaskLayer(layer, data->mItemClip);
@@ -1819,16 +1874,44 @@ ContainerState::PopThebesLayerData()
     flags |= Layer::CONTENT_OPAQUE;
   } else if (data->mNeedComponentAlpha && !hidpi) {
     flags |= Layer::CONTENT_COMPONENT_ALPHA;
   }
   layer->SetContentFlags(flags);
 
   SetFixedPositionLayerData(layer, fixedPosFrameForLayerData);
 
+  ThebesLayerData* containingThebesLayerData =
+     mLayerBuilder->GetContainingThebesLayerData();
+  if (containingThebesLayerData) {
+    gfx3DMatrix matrix = GetTransformToRoot(layer);
+    nsIntPoint translatedDest = GetTranslationForThebesLayer(containingThebesLayerData->mLayer);
+    matrix.TranslatePost(-gfxPoint3D(translatedDest.x, translatedDest.y, 0));
+    AddTransformedBoundsToRegion(data->mDispatchToContentHitRegion, matrix,
+                                 &containingThebesLayerData->mDispatchToContentHitRegion);
+    AddTransformedBoundsToRegion(data->mMaybeHitRegion, matrix,
+                                 &containingThebesLayerData->mMaybeHitRegion);
+    // Our definitely-hit region must go to the maybe-hit-region since
+    // this function is an approximation.
+    gfxMatrix matrix2D;
+    bool isPrecise = matrix.Is2D(&matrix2D) && !matrix2D.HasNonAxisAlignedTransform();
+    AddTransformedBoundsToRegion(data->mHitRegion, matrix,
+      isPrecise ? &containingThebesLayerData->mHitRegion
+                : &containingThebesLayerData->mMaybeHitRegion);
+  } else {
+    EventRegions regions;
+    regions.mHitRegion.Swap(&data->mHitRegion);
+    // Points whose hit-region status we're not sure about need to be dispatched
+    // to the content thread.
+    regions.mDispatchToContentHitRegion.Sub(data->mMaybeHitRegion, regions.mHitRegion);
+    regions.mDispatchToContentHitRegion.Or(regions.mDispatchToContentHitRegion,
+                                           data->mDispatchToContentHitRegion);
+    layer->SetEventRegions(regions);
+  }
+
   if (lastIndex > 0) {
     // Since we're going to pop off the last ThebesLayerData, the
     // mVisibleAboveRegion of the second-to-last item will need to include
     // the regions of the last item.
     ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1];
     nextData->CopyAboveRegion(data);
   }
 
@@ -1992,18 +2075,16 @@ ThebesLayerData::Accumulate(ContainerSta
       }
     }
   }
 }
 
 ThebesLayerData*
 ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
                                    const nsIntRect& aVisibleRect,
-                                   const nsIntRect& aDrawRect,
-                                   const DisplayItemClip& aClip,
                                    const nsIFrame* aActiveScrolledRoot,
                                    const nsPoint& aTopLeft)
 {
   int32_t i;
   int32_t lowestUsableLayerWithScrolledRoot = -1;
   int32_t topmostLayerWithScrolledRoot = -1;
   for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) {
     ThebesLayerData* data = mThebesLayerDataStack[i];
@@ -2032,40 +2113,33 @@ ContainerState::FindThebesLayerFor(nsDis
   }
 
   if (topmostLayerWithScrolledRoot >= 0) {
     while (uint32_t(topmostLayerWithScrolledRoot + 1) < mThebesLayerDataStack.Length()) {
       PopThebesLayerData();
     }
   }
 
-  nsRefPtr<ThebesLayer> layer;
   ThebesLayerData* thebesLayerData = nullptr;
   if (lowestUsableLayerWithScrolledRoot < 0) {
-    layer = CreateOrRecycleThebesLayer(aActiveScrolledRoot, aItem->ReferenceFrame(), aTopLeft);
-
-    NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
-    mNewChildLayers.AppendElement(layer);
+    nsRefPtr<ThebesLayer> layer =
+      CreateOrRecycleThebesLayer(aActiveScrolledRoot, aItem->ReferenceFrame(), aTopLeft);
 
     thebesLayerData = new ThebesLayerData();
     mThebesLayerDataStack.AppendElement(thebesLayerData);
     thebesLayerData->mLayer = layer;
     thebesLayerData->mAnimatedGeometryRoot = aActiveScrolledRoot;
     thebesLayerData->mReferenceFrame = aItem->ReferenceFrame();
+
+    NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
+    *mNewChildLayers.AppendElement() = layer.forget();
   } else {
     thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot];
-    layer = thebesLayerData->mLayer;
   }
 
-  // check to see if the new item has rounded rect clips in common with
-  // other items in the layer
-  thebesLayerData->UpdateCommonClipCount(aClip);
-
-  thebesLayerData->Accumulate(this, aItem, aVisibleRect, aDrawRect, aClip);
-
   return thebesLayerData;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 static void
 DumpPaintedImage(nsDisplayItem* aItem, gfxASurface* aSurf)
 {
   nsCString string(aItem->Name());
@@ -2198,16 +2272,17 @@ ContainerState::ProcessDisplayItems(cons
     NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
       "items in a container layer should all have the same app units per dev pixel");
 
     nsIntRect itemVisibleRect =
       ScaleToOutsidePixels(item->GetVisibleRect(), false);
     bool snap;
     nsRect itemContent = item->GetBounds(mBuilder, &snap);
     nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
+    nsDisplayItem::Type itemType = item->GetType();
     nsIntRect clipRect;
     const DisplayItemClip& itemClip = item->GetClip();
     if (itemClip.HasClip()) {
       itemContent.IntersectRect(itemContent, itemClip.GetClipRect());
       clipRect = ScaleToNearestPixels(itemClip.GetClipRect());
       itemDrawRect.IntersectRect(itemDrawRect, clipRect);
       clipRect.MoveBy(mParameters.mOffset);
     }
@@ -2263,21 +2338,19 @@ ContainerState::ProcessDisplayItems(cons
       // Note that items without their own layers can't be skipped this
       // way, since their ThebesLayer may decide it wants to draw them
       // into its buffer even if they're currently covered.
       if (itemVisibleRect.IsEmpty() &&
           !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
         continue;
       }
 
-
-      nsDisplayItem::Type type = item->GetType();
-      bool setVisibleRegion = (type != nsDisplayItem::TYPE_TRANSFORM) &&
-        (type != nsDisplayItem::TYPE_SCROLL_LAYER);
-      if (type == nsDisplayItem::TYPE_TRANSFORM) {
+      bool setVisibleRegion = (itemType != nsDisplayItem::TYPE_TRANSFORM) &&
+        (itemType != nsDisplayItem::TYPE_SCROLL_LAYER);
+      if (itemType == nsDisplayItem::TYPE_TRANSFORM) {
         mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr;
       } else {
         mParameters.mAncestorClipRect = nullptr;
       }
 
       // Just use its layer.
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
       if (!ownLayer) {
@@ -2367,31 +2440,38 @@ ContainerState::ProcessDisplayItems(cons
        */
       nsAutoPtr<nsDisplayItemGeometry> dummy;
       mLayerBuilder->AddLayerDisplayItem(ownLayer, item, 
                                          itemClip, layerState,
                                          topLeft, nullptr,
                                          dummy);
     } else {
       ThebesLayerData* data =
-        FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, itemClip,
-                           animatedGeometryRoot, topLeft);
-
-      nsAutoPtr<nsDisplayItemGeometry> geometry(item->AllocateGeometry(mBuilder));
-
-      InvalidateForLayerChange(item, data->mLayer, itemClip, topLeft, geometry);
-
-      mLayerBuilder->AddThebesDisplayItem(data->mLayer, item, itemClip,
-                                          mContainerFrame,
-                                          layerState, topLeft,
-                                          geometry);
-
-      // check to see if the new item has rounded rect clips in common with
-      // other items in the layer
-      data->UpdateCommonClipCount(itemClip);
+        FindThebesLayerFor(item, itemVisibleRect, animatedGeometryRoot, topLeft);
+
+      if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
+        nsDisplayLayerEventRegions* eventRegions =
+            static_cast<nsDisplayLayerEventRegions*>(item);
+        data->AccumulateEventRegions(ScaleRegionToOutsidePixels(eventRegions->HitRegion()),
+                                     ScaleRegionToOutsidePixels(eventRegions->MaybeHitRegion()),
+                                     ScaleRegionToOutsidePixels(eventRegions->DispatchToContentHitRegion()));
+      } else {
+        // check to see if the new item has rounded rect clips in common with
+        // other items in the layer
+        data->UpdateCommonClipCount(itemClip);
+        data->Accumulate(this, item, itemVisibleRect, itemDrawRect, itemClip);
+
+        nsAutoPtr<nsDisplayItemGeometry> geometry(item->AllocateGeometry(mBuilder));
+        InvalidateForLayerChange(item, data->mLayer, itemClip, topLeft, geometry);
+
+        mLayerBuilder->AddThebesDisplayItem(data, item, itemClip,
+                                            mContainerFrame,
+                                            layerState, topLeft,
+                                            geometry);
+      }
     }
   }
 }
 
 void
 ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, 
                                          Layer* aNewLayer,
                                          const DisplayItemClip& aClip,
@@ -2504,31 +2584,33 @@ ContainerState::InvalidateForLayerChange
     aItem->NotifyRenderingChanged();
     InvalidatePostTransformRegion(newThebesLayer,
         combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
         GetTranslationForThebesLayer(newThebesLayer));
   }
 }
 
 void
-FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
+FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData,
                                         nsDisplayItem* aItem,
                                         const DisplayItemClip& aClip,
                                         nsIFrame* aContainerLayerFrame,
                                         LayerState aLayerState,
                                         const nsPoint& aTopLeft,
                                         nsAutoPtr<nsDisplayItemGeometry> aGeometry)
 {
+  ThebesLayer* layer = aLayerData->mLayer;
   ThebesDisplayItemLayerUserData* thebesData =
-    static_cast<ThebesDisplayItemLayerUserData*>(aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
+    static_cast<ThebesDisplayItemLayerUserData*>
+      (layer->GetUserData(&gThebesDisplayItemLayerUserData));
   nsRefPtr<BasicLayerManager> tempManager;
   nsIntRect intClip;
   bool hasClip = false;
   if (aLayerState != LAYER_NONE) {
-    DisplayItemData *data = GetDisplayItemDataForManager(aItem, aLayer->Manager());
+    DisplayItemData *data = GetDisplayItemDataForManager(aItem, layer->Manager());
     if (data) {
       tempManager = data->mInactiveManager;
     }
     if (!tempManager) {
       tempManager = new BasicLayerManager();
     }
 
     // We need to grab these before calling AddLayerDisplayItem because it will overwrite them.
@@ -2541,82 +2623,82 @@ FrameLayerBuilder::AddThebesDisplayItem(
 
     if (hasClip) {
       intClip = clip.GetBounds().ScaleToOutsidePixels(thebesData->mXScale, 
                                                       thebesData->mYScale, 
                                                       thebesData->mAppUnitsPerDevPixel);
     }
   }
 
-  AddLayerDisplayItem(aLayer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
-
-  ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
+  AddLayerDisplayItem(layer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
+
+  ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(layer);
   if (entry) {
     entry->mContainerLayerFrame = aContainerLayerFrame;
     if (entry->mContainerLayerGeneration == 0) {
       entry->mContainerLayerGeneration = mContainerLayerGeneration;
     }
     if (tempManager) {
       FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
-      layerBuilder->Init(mDisplayListBuilder, tempManager);
+      layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData);
 
       tempManager->BeginTransaction();
       if (mRetainingManager) {
         layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
       }
   
       nsAutoPtr<LayerProperties> props(LayerProperties::CloneFrom(tempManager->GetRoot()));
-      nsRefPtr<Layer> layer =
+      nsRefPtr<Layer> tmpLayer =
         aItem->BuildLayer(mDisplayListBuilder, tempManager, ContainerLayerParameters());
       // We have no easy way of detecting if this transaction will ever actually get finished.
       // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp
-      if (!layer) {
+      if (!tmpLayer) {
         tempManager->EndTransaction(nullptr, nullptr);
         tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
         return;
       }
 
       // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
       // stored in layerBuilder. Manually add it now.
       if (mRetainingManager) {
 #ifdef DEBUG_DISPLAY_ITEM_DATA
         LayerManagerData* parentLmd = static_cast<LayerManagerData*>
-          (aLayer->Manager()->GetUserData(&gLayerManagerUserData));
+          (layer->Manager()->GetUserData(&gLayerManagerUserData));
         LayerManagerData* lmd = static_cast<LayerManagerData*>
           (tempManager->GetUserData(&gLayerManagerUserData));
         lmd->mParent = parentLmd;
 #endif
-        layerBuilder->StoreDataForFrame(aItem, layer, LAYER_ACTIVE);
+        layerBuilder->StoreDataForFrame(aItem, tmpLayer, LAYER_ACTIVE);
       }
 
-      tempManager->SetRoot(layer);
+      tempManager->SetRoot(tmpLayer);
       layerBuilder->WillEndTransaction();
       tempManager->AbortTransaction();
 
-      nsIntPoint offset = GetLastPaintOffset(aLayer) - GetTranslationForThebesLayer(aLayer);
+      nsIntPoint offset = GetLastPaintOffset(layer) - GetTranslationForThebesLayer(layer);
       props->MoveBy(-offset);
-      nsIntRegion invalid = props->ComputeDifferences(layer, nullptr);
+      nsIntRegion invalid = props->ComputeDifferences(tmpLayer, nullptr);
       if (aLayerState == LAYER_SVG_EFFECTS) {
         invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(aItem->Frame(),
                                                                         aItem->ToReferenceFrame(),
                                                                         invalid.GetBounds());
       }
       if (!invalid.IsEmpty()) {
 #ifdef MOZ_DUMP_PAINTING
         if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
-          printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->Frame(), aLayer);
+          printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->Frame(), layer);
         }
 #endif
         if (hasClip) {
           invalid.And(invalid, intClip);
         }
 
         invalid.ScaleRoundOut(thebesData->mXScale, thebesData->mYScale);
-        InvalidatePostTransformRegion(aLayer, invalid,
-                                      GetTranslationForThebesLayer(aLayer));
+        InvalidatePostTransformRegion(layer, invalid,
+                                      GetTranslationForThebesLayer(layer));
       }
     }
     ClippedDisplayItem* cdi =
       entry->mItems.AppendElement(ClippedDisplayItem(aItem,
                                                      mContainerLayerGeneration));
     cdi->mInactiveLayerManager = tempManager;
   }
 }
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -8,16 +8,17 @@
 
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "nsRegion.h"
 #include "nsIFrame.h"
 #include "ImageLayers.h"
 #include "DisplayItemClip.h"
+#include "mozilla/layers/LayersTypes.h"
 
 class nsDisplayListBuilder;
 class nsDisplayList;
 class nsDisplayItem;
 class gfxContext;
 class nsDisplayItemGeometry;
 
 namespace mozilla {
@@ -25,16 +26,17 @@ namespace layers {
 class ContainerLayer;
 class LayerManager;
 class BasicLayerManager;
 class ThebesLayer;
 }
 
 class FrameLayerBuilder;
 class LayerManagerData;
+class ThebesLayerData;
 
 enum LayerState {
   LAYER_NONE,
   LAYER_INACTIVE,
   LAYER_ACTIVE,
   // Force an active layer even if it causes incorrect rendering, e.g.
   // when the layer has rounded rect clips.
   LAYER_ACTIVE_FORCE,
@@ -139,16 +141,17 @@ struct ContainerLayerParameters {
 class FrameLayerBuilder : public layers::LayerUserData {
 public:
   typedef layers::ContainerLayer ContainerLayer;
   typedef layers::Layer Layer;
   typedef layers::ThebesLayer ThebesLayer;
   typedef layers::ImageLayer ImageLayer;
   typedef layers::LayerManager LayerManager;
   typedef layers::BasicLayerManager BasicLayerManager;
+  typedef layers::EventRegions EventRegions;
 
   FrameLayerBuilder() :
     mRetainingManager(nullptr),
     mDetectedDOMModification(false),
     mInvalidateAllLayers(false),
     mContainerLayerGeneration(0),
     mMaxContainerLayerGeneration(0)
   {
@@ -156,17 +159,18 @@ public:
   }
   ~FrameLayerBuilder()
   {
     MOZ_COUNT_DTOR(FrameLayerBuilder);
   }
 
   static void Shutdown();
 
-  void Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager);
+  void Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
+            ThebesLayerData* aLayerData = nullptr);
 
   /**
    * Call this to notify that we have just started a transaction on the
    * retained layer manager aManager.
    */
   void DidBeginRetainedLayerTransaction(LayerManager* aManager);
 
   /**
@@ -282,17 +286,17 @@ public:
 
   /**
    * Record aItem as a display item that is rendered by the ThebesLayer
    * aLayer, with aClipRect, where aContainerLayerFrame is the frame
    * for the container layer this ThebesItem belongs to.
    * aItem must have an underlying frame.
    * @param aTopLeft offset from active scrolled root to reference frame
    */
-  void AddThebesDisplayItem(ThebesLayer* aLayer,
+  void AddThebesDisplayItem(ThebesLayerData* aLayer,
                             nsDisplayItem* aItem,
                             const DisplayItemClip& aClip,
                             nsIFrame* aContainerLayerFrame,
                             LayerState aLayerState,
                             const nsPoint& aTopLeft,
                             nsAutoPtr<nsDisplayItemGeometry> aGeometry);
 
   /**
@@ -577,16 +581,21 @@ public:
    * Get the ThebesLayerItemsEntry object associated with aLayer in this
    * FrameLayerBuilder
    */
   ThebesLayerItemsEntry* GetThebesLayerItemsEntry(ThebesLayer* aLayer)
   {
     return mThebesLayerItems.GetEntry(aLayer);
   }
 
+  ThebesLayerData* GetContainingThebesLayerData()
+  {
+    return mContainingThebesLayer;
+  }
+
 protected:
   void RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer,
                                                     bool aRemoveThebesItems,
                                                     bool aRemoveOwnerData);
 
   static PLDHashOperator ProcessRemovedDisplayItems(nsRefPtrHashKey<DisplayItemData>* aEntry,
                                                     void* aUserArg);
   static PLDHashOperator RestoreDisplayItemData(nsRefPtrHashKey<DisplayItemData>* aEntry,
@@ -616,16 +625,23 @@ protected:
    * The display list builder being used.
    */
   nsDisplayListBuilder*               mDisplayListBuilder;
   /**
    * A map from ThebesLayers to the list of display items (plus
    * clipping data) to be rendered in the layer.
    */
   nsTHashtable<ThebesLayerItemsEntry> mThebesLayerItems;
+
+  /**
+   * When building layers for an inactive layer, this is where the
+   * inactive layer will be placed.
+   */
+  ThebesLayerData*                    mContainingThebesLayer;
+
   /**
    * Saved generation counter so we can detect DOM changes.
    */
   uint32_t                            mInitialDOMGeneration;
   /**
    * Set to true if we have detected and reported DOM modification during
    * the current paint.
    */