Bug 845169 - Update touch region from remote frame. r=roc
authorKan-Ru Chen (陳侃如) <kanru@kanru.info>
Tue, 13 Aug 2013 15:56:57 +0800
changeset 156255 ce94c5f1ad3f6de9206e89192a6b4faa064969e0
parent 156254 95da71532621656886d1adf99a0649b48ae185b8
child 156256 7bb10d5dfca26e13f32013c0269eb21ba4ea1523
push id407
push userlsblakk@mozilla.com
push dateTue, 03 Dec 2013 03:32:50 +0000
treeherdermozilla-release@babf8c9ebc52 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs845169
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 845169 - Update touch region from remote frame. r=roc
content/base/src/nsFrameLoader.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
ipc/glue/IPCMessageUtils.h
layout/base/nsDisplayList.cpp
layout/base/nsPresShell.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsSubDocumentFrame.h
layout/ipc/PRenderFrame.ipdl
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -2067,16 +2067,23 @@ nsFrameLoader::TryRemoteBrowser()
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
 
     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
     mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
 
     mContentParent = mRemoteBrowser->Manager();
+
+    if (mOwnerContent->AttrValueIs(kNameSpaceID_None,
+                                   nsGkAtoms::mozpasspointerevents,
+                                   nsGkAtoms::_true,
+                                   eCaseMatters)) {
+      unused << mRemoteBrowser->SendSetUpdateHitRegion(true);
+    }
   }
   return true;
 }
 
 mozilla::dom::PBrowserParent*
 nsFrameLoader::GetRemoteBrowser()
 {
   return mRemoteBrowser;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -400,16 +400,23 @@ child:
     /**
      * Sent by the chrome process when it no longer wants this remote
      * <browser>.  The child side cleans up in response, then
      * finalizing its death by sending back __delete__() to the
      * parent.
      */
     Destroy();
 
+
+    /**
+     * Tell the child side if it has to update it's touchable region
+     * to the parent.
+     */
+    SetUpdateHitRegion(bool aEnabled);
+
 /*
  * FIXME: write protocol!
 
 state LIVE:
     send LoadURL goto LIVE;
 //etc.
     send Destroy goto DYING;
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -289,16 +289,17 @@ TabChild::TabChild(ContentChild* aManage
   , mAppPackageFileDescriptorRecved(false)
   , mOldViewportWidth(0.0f)
   , mLastBackgroundColor(NS_RGB(255, 255, 255))
   , mDidFakeShow(false)
   , mNotified(false)
   , mContentDocumentIsDisplayed(false)
   , mTriedBrowserInit(false)
   , mOrientation(eScreenOrientation_PortraitPrimary)
+  , mUpdateHitRegion(false)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
 NS_IMETHODIMP
 TabChild::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
@@ -2137,16 +2138,23 @@ TabChild::RecvDestroy()
   }
 
   // XXX what other code in ~TabChild() should we be running here?
   DestroyWindow();
 
   return Send__delete__(this);
 }
 
+bool
+TabChild::RecvSetUpdateHitRegion(const bool& aEnabled)
+{
+    mUpdateHitRegion = aEnabled;
+    return true;
+}
+
 PRenderFrameChild*
 TabChild::AllocPRenderFrameChild(ScrollingBehavior* aScrolling,
                             TextureFactoryIdentifier* aTextureFactoryIdentifier,
                             uint64_t* aLayersId)
 {
     return new RenderFrameChild();
 }
 
@@ -2348,16 +2356,22 @@ TabChild::MakeVisible()
 void
 TabChild::MakeHidden()
 {
     if (mWidget) {
         mWidget->Show(false);
     }
 }
 
+void
+TabChild::UpdateHitRegion(const nsRegion& aRegion)
+{
+    mRemoteFrame->SendUpdateHitRegion(aRegion);
+}
+
 NS_IMETHODIMP
 TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
 {
   if (mTabChildGlobal) {
     NS_ADDREF(*aResult = mTabChildGlobal);
     return NS_OK;
   }
   *aResult = nullptr;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -335,22 +335,27 @@ public:
                                  nsICachedFileDescriptorListener* aCallback);
 
     void CancelCachedFileDescriptorCallback(
                                     const nsAString& aPath,
                                     nsICachedFileDescriptorListener* aCallback);
 
     ContentChild* Manager() { return mManager; }
 
+    bool GetUpdateHitRegion() { return mUpdateHitRegion; }
+
+    void UpdateHitRegion(const nsRegion& aRegion);
+
 protected:
     virtual PRenderFrameChild* AllocPRenderFrameChild(ScrollingBehavior* aScrolling,
                                                       TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                                       uint64_t* aLayersId) MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) MOZ_OVERRIDE;
     virtual bool RecvDestroy() MOZ_OVERRIDE;
+    virtual bool RecvSetUpdateHitRegion(const bool& aEnabled) MOZ_OVERRIDE;
 
     nsEventStatus DispatchWidgetEvent(nsGUIEvent& event);
 
     virtual PIndexedDBChild* AllocPIndexedDBChild(const nsCString& aASCIIOrigin,
                                                   bool* /* aAllowed */);
 
     virtual bool DeallocPIndexedDBChild(PIndexedDBChild* aActor);
 
@@ -466,16 +471,17 @@ private:
     float mOldViewportWidth;
     nscolor mLastBackgroundColor;
     ScrollingBehavior mScrolling;
     bool mDidFakeShow;
     bool mNotified;
     bool mContentDocumentIsDisplayed;
     bool mTriedBrowserInit;
     ScreenOrientation mOrientation;
+    bool mUpdateHitRegion;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
 GetTabChildFrom(nsIDocShell* aDocShell)
 {
     nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -758,44 +758,49 @@ struct ParamTraits<nsIntRect>
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y) &&
             ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
-template<>
-struct ParamTraits<nsIntRegion>
+template<typename Region, typename Rect, typename Iter>
+struct RegionParamTraits
 {
-  typedef nsIntRegion paramType;
+  typedef Region paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
-    nsIntRegionRectIterator it(param);
-    while (const nsIntRect* r = it.Next())
+    Iter it(param);
+    while (const Rect* r = it.Next())
       WriteParam(msg, *r);
     // empty rects are sentinel values because nsRegions will never
     // contain them
-    WriteParam(msg, nsIntRect());
+    WriteParam(msg, Rect());
   }
 
   static bool Read(const Message* msg, void** iter, paramType* result)
   {
-    nsIntRect rect;
+    Rect rect;
     while (ReadParam(msg, iter, &rect)) {
       if (rect.IsEmpty())
         return true;
       result->Or(*result, rect);
     }
     return false;
   }
 };
 
 template<>
+struct ParamTraits<nsIntRegion>
+  : RegionParamTraits<nsIntRegion, nsIntRect, nsIntRegionRectIterator>
+{};
+
+template<>
 struct ParamTraits<nsIntSize>
 {
   typedef nsIntSize paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
@@ -984,16 +989,21 @@ struct ParamTraits<nsRect>
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y) &&
             ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
 template<>
+struct ParamTraits<nsRegion>
+  : RegionParamTraits<nsRegion, nsRect, nsRegionRectIterator>
+{};
+
+template<>
 struct ParamTraits<nsID>
 {
   typedef nsID paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.m0);
     WriteParam(aMsg, aParam.m1);
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -35,16 +35,17 @@
 #include "nsThemeConstants.h"
 #include "LayerTreeInvalidation.h"
 
 #include "imgIContainer.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "BasicLayers.h"
 #include "nsBoxFrame.h"
 #include "nsViewportFrame.h"
+#include "nsSubDocumentFrame.h"
 #include "nsSVGEffects.h"
 #include "nsSVGElement.h"
 #include "nsSVGClipPathFrame.h"
 #include "GeckoProfiler.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
 #include "nsViewManager.h"
 #include "ImageLayers.h"
@@ -1265,16 +1266,27 @@ GetMouseThrough(const nsIFrame* aFrame)
     } else if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER) {
       return false;
     }
     frame = frame->GetParentBox();
   }
   return false;
 }
 
+static bool
+IsFrameReceivingPointerEvents(nsIFrame* aFrame)
+{
+  nsSubDocumentFrame* frame = do_QueryFrame(aFrame);
+  if (frame && frame->PassPointerEventsToChildren()) {
+    return true;
+  }
+  return NS_STYLE_POINTER_EVENTS_NONE !=
+    aFrame->StyleVisibility()->GetEffectivePointerEvents(aFrame);
+}
+
 // A list of frames, and their z depth. Used for sorting
 // the results of hit testing.
 struct FramesWithDepth
 {
   FramesWithDepth(float aDepth) :
     mDepth(aDepth)
   {}
 
@@ -1347,18 +1359,17 @@ void nsDisplayList::HitTest(nsDisplayLis
         // We may have just finished a run of consecutive preserve-3d transforms,
         // so flush these into the destination array before processing our frame list.
         FlushFramesArray(temp, aOutFrames);
       }
 
       for (uint32_t j = 0; j < outFrames.Length(); j++) {
         nsIFrame *f = outFrames.ElementAt(j);
         // Handle the XUL 'mousethrough' feature and 'pointer-events'.
-        if (!GetMouseThrough(f) &&
-            f->StyleVisibility()->GetEffectivePointerEvents(f) != NS_STYLE_POINTER_EVENTS_NONE) {
+        if (!GetMouseThrough(f) && IsFrameReceivingPointerEvents(f)) {
           writeFrames->AppendElement(f);
         }
       }
     }
   }
   // Clear any remaining preserve-3d transforms.
   FlushFramesArray(temp, aOutFrames);
   NS_ASSERTION(aState->mItemBuffer.Length() == uint32_t(itemBufferStart),
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5484,16 +5484,57 @@ public:
     mShell->GetPresContext()->NotifyDidPaintForSubtree(mFlags);
   }
 
 private:
   PresShell* mShell;
   uint32_t mFlags;
 };
 
+class AutoUpdateHitRegion
+{
+public:
+  AutoUpdateHitRegion(PresShell* aShell, nsIFrame* aFrame)
+    : mShell(aShell), mFrame(aFrame)
+  {
+  }
+  ~AutoUpdateHitRegion()
+  {
+    if (XRE_GetProcessType() != GeckoProcessType_Content ||
+        !mFrame || !mShell) {
+      return;
+    }
+    TabChild* tabChild = GetTabChildFrom(mShell);
+    if (!tabChild || !tabChild->GetUpdateHitRegion()) {
+      return;
+    }
+    nsRegion region;
+    nsDisplayListBuilder builder(mFrame,
+                                 nsDisplayListBuilder::EVENT_DELIVERY,
+                                 /* aBuildCert= */ false);
+    nsDisplayList list;
+    nsAutoTArray<nsIFrame*, 100> outFrames;
+    nsDisplayItem::HitTestState hitTestState;
+    nsRect bounds = mShell->GetPresContext()->GetVisibleArea();
+    builder.EnterPresShell(mFrame, bounds);
+    mFrame->BuildDisplayListForStackingContext(&builder, bounds, &list);
+    builder.LeavePresShell(mFrame, bounds);
+    list.HitTest(&builder, bounds, &hitTestState, &outFrames);
+    list.DeleteAll();
+    for (int32_t i = outFrames.Length() - 1; i >= 0; --i) {
+      region.Or(region, nsLayoutUtils::TransformFrameRectToAncestor(
+                  outFrames[i], nsRect(nsPoint(0, 0), outFrames[i]->GetSize()), mFrame));
+    }
+    tabChild->UpdateHitRegion(region);
+  }
+private:
+  PresShell* mShell;
+  nsIFrame* mFrame;
+};
+
 void
 PresShell::Paint(nsView*        aViewToPaint,
                  const nsRegion& aDirtyRegion,
                  uint32_t        aFlags)
 {
   PROFILER_LABEL("Paint", "PresShell::Paint");
   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
   NS_ASSERTION(aViewToPaint, "null view");
@@ -5515,16 +5556,17 @@ PresShell::Paint(nsView*        aViewToP
   NS_ASSERTION(layerManager, "Must be in paint event");
   bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
 
   uint32_t didPaintFlags = aFlags;
   if (!shouldInvalidate) {
     didPaintFlags |= PAINT_COMPOSITE;
   }
   nsAutoNotifyDidPaint notifyDidPaint(this, didPaintFlags);
+  AutoUpdateHitRegion updateHitRegion(this, frame);
 
   // Whether or not we should set first paint when painting is
   // suppressed is debatable. For now we'll do it because
   // B2G relies on first paint to configure the viewport and
   // we only want to do that when we have real content to paint.
   // See Bug 798245
   if (mIsFirstPaint && !mPaintingSuppressed) {
     layerManager->SetIsFirstPaint();
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -298,17 +298,21 @@ nsSubDocumentFrame::BuildDisplayList(nsD
   if (!IsVisibleForPainting(aBuilder))
     return;
 
   // If mozpasspointerevents is set, then we should allow subdocument content
   // to handle events even if we're pointer-events:none.
   if (aBuilder->IsForEventDelivery() && !PassPointerEventsToChildren())
     return;
 
-  DisplayBorderBackgroundOutline(aBuilder, aLists);
+  // If we are pointer-events:none then we don't need to HitTest background
+  if (!aBuilder->IsForEventDelivery() ||
+      StyleVisibility()->mPointerEvents != NS_STYLE_POINTER_EVENTS_NONE) {
+    DisplayBorderBackgroundOutline(aBuilder, aLists);
+  }
 
   if (!mInnerView)
     return;
 
   nsFrameLoader* frameLoader = FrameLoader();
   if (frameLoader) {
     RenderFrameParent* rfp = frameLoader->GetCurrentRemoteFrame();
     if (rfp) {
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -102,16 +102,22 @@ public:
   }
 
   bool ShouldClampScrollPosition()
   {
     nsFrameLoader* frameLoader = FrameLoader();
     return !frameLoader || frameLoader->ShouldClampScrollPosition();
   }
 
+  /**
+   * Return true if pointer event hit-testing should be allowed to target
+   * content in the subdocument.
+   */
+  bool PassPointerEventsToChildren();
+
 protected:
   friend class AsyncFrameInit;
 
   // Helper method to look up the HTML marginwidth & marginheight attributes
   nsIntSize GetMarginAttributes();
 
   nsFrameLoader* FrameLoader();
 
@@ -130,22 +136,16 @@ protected:
    * and our sub-document has an intrinsic size. The frame returned is the
    * frame for the document element of the document we're embedding.
    *
    * Called "Obtain*" and not "Get*" because of comment on GetDocShell that
    * says it should be called ObtainDocShell because of it's side effects.
    */
   nsIFrame* ObtainIntrinsicSizeFrame();
 
-  /**
-   * Return true if pointer event hit-testing should be allowed to target
-   * content in the subdocument.
-   */
-  bool PassPointerEventsToChildren();
-
   nsRefPtr<nsFrameLoader> mFrameLoader;
   nsView* mInnerView;
   bool mIsInline;
   bool mPostedReflowCallback;
   bool mDidCreateDoc;
   bool mCallingShow;
 };
 
--- a/layout/ipc/PRenderFrame.ipdl
+++ b/layout/ipc/PRenderFrame.ipdl
@@ -3,16 +3,20 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBrowser;
 include protocol PLayerTransaction;
 
+include "nsRegion.h";
+
+using nsRegion;
+
 namespace mozilla {
 namespace layout {
 
 /**
  * PRenderFrame (in the layout sense of "frame") represents one web
  * "page".  It's used to graft content processes' layer trees into
  * chrome's rendering path.  The lifetime of a PRenderFrame is tied to
  * its PresShell in the child process.
@@ -39,22 +43,26 @@ parent:
      */
     async PLayerTransaction();
 
     async NotifyCompositorTransaction();
 
     async CancelDefaultPanZoom();
     async DetectScrollableSubframe();
 
+    async UpdateHitRegion(nsRegion aRegion);
+
     async __delete__();
 
 state EMPTY_OR_DIRECT_COMPOSITOR:
     recv PLayerTransaction goto HAVE_CONTENT;
     recv NotifyCompositorTransaction goto EMPTY_OR_DIRECT_COMPOSITOR;
+    recv UpdateHitRegion goto EMPTY_OR_DIRECT_COMPOSITOR;
     recv __delete__;
 
 state HAVE_CONTENT:
     recv NotifyCompositorTransaction goto HAVE_CONTENT;
+    recv UpdateHitRegion goto HAVE_CONTENT;
     recv __delete__;
 };
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -857,16 +857,23 @@ bool
 RenderFrameParent::RecvDetectScrollableSubframe()
 {
   if (GetApzcTreeManager()) {
     GetApzcTreeManager()->DetectScrollableSubframe(ScrollableLayerGuid(mLayersId));
   }
   return true;
 }
 
+bool
+RenderFrameParent::RecvUpdateHitRegion(const nsRegion& aRegion)
+{
+  mTouchRegion = aRegion;
+  return true;
+}
+
 PLayerTransactionParent*
 RenderFrameParent::AllocPLayerTransactionParent()
 {
   if (!mFrameLoader || mFrameLoaderDestroyed) {
     return nullptr;
   }
   nsRefPtr<LayerManager> lm = GetFrom(mFrameLoader);
   return new LayerTransactionParent(lm->AsLayerManagerComposite(), this, 0);
@@ -1002,31 +1009,45 @@ void
 RenderFrameParent::UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom)
 {
   if (GetApzcTreeManager()) {
     GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId),
                                                 aAllowZoom, aMinZoom, aMaxZoom);
   }
 }
 
+bool
+RenderFrameParent::HitTest(const nsRect& aRect)
+{
+  return mTouchRegion.Contains(aRect);
+}
+
 }  // namespace layout
 }  // namespace mozilla
 
 already_AddRefed<Layer>
 nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
                             LayerManager* aManager,
                             const ContainerParameters& aContainerParameters)
 {
   int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel);
   visibleRect += aContainerParameters.mOffset;
   nsRefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect, this, aContainerParameters);
   return layer.forget();
 }
 
+void
+nsDisplayRemote::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+                         HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
+{
+  if (mRemoteFrame->HitTest(aRect)) {
+    aOutFrames->AppendElement(mFrame);
+  }
+}
 
 void
 nsDisplayRemoteShadow::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                          HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
 {
   // If we are here, then rects have intersected.
   //
   // XXX I think iframes and divs can be rounded like anything else but we don't
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -99,24 +99,28 @@ public:
   void NotifyDimensionsChanged(ScreenIntSize size);
 
   void ZoomToRect(const CSSRect& aRect);
 
   void ContentReceivedTouch(bool aPreventDefault);
 
   void UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
 
+  bool HitTest(const nsRect& aRect);
+
 protected:
   void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   virtual bool RecvNotifyCompositorTransaction() MOZ_OVERRIDE;
 
   virtual bool RecvCancelDefaultPanZoom() MOZ_OVERRIDE;
   virtual bool RecvDetectScrollableSubframe() MOZ_OVERRIDE;
 
+  virtual bool RecvUpdateHitRegion(const nsRegion& aRegion) MOZ_OVERRIDE;
+
   virtual PLayerTransactionParent* AllocPLayerTransactionParent() MOZ_OVERRIDE;
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
 
 private:
   void BuildViewMap();
   void TriggerRepaint();
   void DispatchEventForPanZoomController(const InputEvent& aEvent);
 
@@ -155,16 +159,18 @@ private:
   // Destroy() so that less code needs to be special-cased for after
   // Destroy().
   // 
   // It's possible for mFrameLoader==null and
   // mFrameLoaderDestroyed==false.
   bool mFrameLoaderDestroyed;
   // this is gfxRGBA because that's what ColorLayer wants.
   gfxRGBA mBackgroundColor;
+
+  nsRegion mTouchRegion;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 /**
  * A DisplayRemote exists solely to graft a child process's shadow
  * layer tree (for a given RenderFrameParent) into its parent
@@ -185,16 +191,19 @@ public:
                                    LayerManager* aManager,
                                    const ContainerParameters& aParameters) MOZ_OVERRIDE
   { return mozilla::LAYER_ACTIVE_FORCE; }
 
   virtual already_AddRefed<Layer>
   BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
              const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
 
+  void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+               HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
+
   NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE)
 
 private:
   RenderFrameParent* mRemoteFrame;
 };
 
 /**
  * nsDisplayRemoteShadow is a way of adding display items for frames in a