Bug 605618 Part 2: Infrastructure for building shadow display list r=tn sr=roc
authorBenjamin Stover <bstover@mozilla.com>
Thu, 13 Jan 2011 09:45:14 -0800
changeset 60444 85d06279c8358a8e1c883aa670a20212b1039a90
parent 60443 a4c1b880bd52b62b98f705986a7f41dc93227f26
child 60445 e41a3720b995db3b695f47e0ced9efd9ec27ea36
push idunknown
push userunknown
push dateunknown
reviewerstn, roc
bugs605618
milestone2.0b10pre
Bug 605618 Part 2: Infrastructure for building shadow display list r=tn sr=roc
layout/base/nsDisplayItemTypes.h
layout/base/nsDisplayList.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsSubDocumentFrame.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
--- a/layout/base/nsDisplayItemTypes.h
+++ b/layout/base/nsDisplayItemTypes.h
@@ -76,16 +76,17 @@ enum Type {
   TYPE_OUTLINE,
   TYPE_OWN_LAYER,
   TYPE_PAGE_CONTENT,
   TYPE_PAGE_SEQUENCE,
   TYPE_PLUGIN,
   TYPE_PRINT_PREVIEW_BACKGROUND,
   TYPE_PRINT_PLUGIN,
   TYPE_REMOTE,
+  TYPE_REMOTE_SHADOW,
   TYPE_SELECTION_OVERLAY,
   TYPE_SOLID_COLOR,
   TYPE_TABLE_CELL_BACKGROUND,
   TYPE_TABLE_CELL_SELECTION,
   TYPE_TABLE_ROW_BACKGROUND,
   TYPE_TABLE_ROW_GROUP_BACKGROUND,
   TYPE_TABLE_BORDER_BACKGROUND,
   TYPE_TEXT,
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -519,16 +519,17 @@ protected:
  * subclass would just have a frame pointer, so its object would be just three
  * pointers (vtable, next-item, frame).
  * 
  * Display items belong to a list at all times (except temporarily as they
  * move from one list to another).
  */
 class nsDisplayItem : public nsDisplayItemLink {
 public:
+  typedef mozilla::layers::FrameMetrics::ViewID ViewID;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::LayerState LayerState;
 
   // This is never instantiated directly (it has pure virtual methods), so no
   // need to count constructors and destructors.
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
     mFrame(aFrame) {
@@ -542,21 +543,33 @@ public:
                      nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
     return aBuilder->Allocate(aSize);
   }
 
 // Contains all the type integers for each display list item type
 #include "nsDisplayItemTypes.h"
 
   struct HitTestState {
+    typedef nsTArray<ViewID> ShadowArray;
+
+    HitTestState(ShadowArray* aShadows = NULL)
+      : mShadows(aShadows) {
+    }
+
     ~HitTestState() {
       NS_ASSERTION(mItemBuffer.Length() == 0,
                    "mItemBuffer should have been cleared");
     }
+
     nsAutoTArray<nsDisplayItem*, 100> mItemBuffer;
+
+    // It is sometimes useful to hit test for frames that are not in this
+    // process. Display items may append IDs into this array if it is
+    // non-null.
+    ShadowArray* mShadows;
   };
 
   /**
    * Some consecutive items should be rendered together as a unit, e.g.,
    * outlines for the same element. For this, we need a way for items to
    * identify their type. We use the type for other purposes too.
    */
   virtual Type GetType() = 0;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -114,16 +114,17 @@ using namespace mozilla::dom;
 namespace css = mozilla::css;
 
 #ifdef DEBUG
 // TODO: remove, see bug 598468.
 bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
 #endif // DEBUG
 
 typedef gfxPattern::GraphicsFilter GraphicsFilter;
+typedef FrameMetrics::ViewID ViewID;
 
 /**
  * A namespace class for static layout utilities.
  */
 
 nsIFrame*
 nsLayoutUtils::GetLastContinuationWithChild(nsIFrame* aFrame)
 {
@@ -1089,16 +1090,50 @@ nsLayoutUtils::CombineBreakType(PRUint8 
 
 #ifdef DEBUG
 #include <stdio.h>
 
 static PRBool gDumpPaintList = getenv("MOZ_DUMP_PAINT_LIST") != 0;
 static PRBool gDumpEventList = PR_FALSE;
 #endif
 
+nsresult
+nsLayoutUtils::GetRemoteContentIds(nsIFrame* aFrame,
+                                   const nsRect& aTarget,
+                                   nsTArray<ViewID> &aOutIDs,
+                                   PRBool aIgnoreRootScrollFrame)
+{
+  nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::EVENT_DELIVERY,
+                               PR_FALSE);
+  nsDisplayList list;
+
+  if (aIgnoreRootScrollFrame) {
+    nsIFrame* rootScrollFrame =
+      aFrame->PresContext()->PresShell()->GetRootScrollFrame();
+    if (rootScrollFrame) {
+      builder.SetIgnoreScrollFrame(rootScrollFrame);
+    }
+  }
+
+  builder.EnterPresShell(aFrame, aTarget);
+
+  nsresult rv =
+    aFrame->BuildDisplayListForStackingContext(&builder, aTarget, &list);
+
+  builder.LeavePresShell(aFrame, aTarget);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsTArray<nsIFrame*> outFrames;
+  nsDisplayItem::HitTestState hitTestState(&aOutIDs);
+  list.HitTest(&builder, aTarget, &hitTestState, &outFrames);
+  list.DeleteAll();
+
+  return NS_OK;
+}
+
 nsIFrame*
 nsLayoutUtils::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
                                 PRBool aShouldIgnoreSuppression,
                                 PRBool aIgnoreRootScrollFrame)
 {
   nsresult rv;
   nsTArray<nsIFrame*> outFrames;
   rv = GetFramesForArea(aFrame, nsRect(aPt, nsSize(1, 1)), outFrames,
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -60,30 +60,33 @@ class nsClientRectList;
 #include "nsIFrame.h"
 #include "nsThreadUtils.h"
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
 #include "gfxPattern.h"
 #include "imgIContainer.h"
 #include "nsCSSPseudoElements.h"
 #include "nsHTMLReflowState.h"
+#include "nsIFrameLoader.h"
+#include "Layers.h"
 
 class nsBlockFrame;
 class gfxDrawable;
 
 /**
  * nsLayoutUtils is a namespace class used for various helper
  * functions that are useful in multiple places in layout.  The goal
  * is not to define multiple copies of the same static helper.
  */
 class nsLayoutUtils
 {
   typedef gfxPattern::GraphicsFilter GraphicsFilter;
 
 public:
+  typedef mozilla::layers::FrameMetrics::ViewID ViewID;
 
   /**
    * Use heuristics to figure out the name of the child list that
    * aChildFrame is currently in.
    */
   static nsIAtom* GetChildListNameFor(nsIFrame* aChildFrame);
 
   /**
@@ -431,16 +434,33 @@ public:
    * @param aOrigin The origin to translate to.
    * @param aMatrix The matrix to change the basis of.
    * @return A matrix equivalent to aMatrix, but operating in the coordinate system with
    *         origin aOrigin.
    */
   static gfxMatrix ChangeMatrixBasis(const gfxPoint &aOrigin, const gfxMatrix &aMatrix);
 
   /**
+   * Find IDs corresponding to a scrollable content element in the child process.
+   * In correspondence with the shadow layer tree, you can use this to perform a
+   * hit test that corresponds to a specific shadow layer that you can then perform
+   * transformations on to do parent-side scrolling.
+   *
+   * @param aFrame The root frame of a stack context
+   * @param aTarget The rect to hit test relative to the frame origin
+   * @param aOutIDs All found IDs are added here
+   * @param aIgnoreRootScrollFrame a boolean to control if the display list
+   *        builder should ignore the root scroll frame
+   */
+  static nsresult GetRemoteContentIds(nsIFrame* aFrame,
+                                     const nsRect& aTarget,
+                                     nsTArray<ViewID> &aOutIDs,
+                                     PRBool aIgnoreRootScrollFrame);
+
+  /**
    * Given aFrame, the root frame of a stacking context, find its descendant
    * frame under the point aPt that receives a mouse event at that location,
    * or nsnull if there is no such frame.
    * @param aPt the point, relative to the frame origin
    * @param aShouldIgnoreSuppression a boolean to control if the display
    * list builder should ignore paint suppression or not
    * @param aIgnoreRootScrollFrame whether or not the display list builder
    * should ignore the root scroll frame.
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -277,29 +277,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
   if (!mInnerView)
     return NS_OK;
 
 #ifdef MOZ_IPC
   nsFrameLoader* frameLoader = FrameLoader();
   if (frameLoader) {
     RenderFrameParent* rfp = frameLoader->GetCurrentRemoteFrame();
     if (rfp) {
-      // We're the subdoc for <browser remote="true"> and it has
-      // painted content.  Display its shadow layer tree.
-      nsDisplayList shadowTree;
-      shadowTree.AppendToTop(
-        new (aBuilder) nsDisplayRemote(aBuilder, this, rfp));
-
-      // Clip the shadow layers to subdoc bounds
-      nsPoint offset = GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
-      nsRect bounds = mInnerView->GetBounds() + offset;
-
-      return aLists.Content()->AppendNewToTop(
-        new (aBuilder) nsDisplayClip(aBuilder, this, &shadowTree,
-                                     bounds));
+      return rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists);
     }
   }
 #endif
 
   nsIView* subdocView = mInnerView->GetFirstChild();
   if (!subdocView)
     return NS_OK;
 
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -42,16 +42,17 @@
 
 #include "BasicLayers.h"
 #include "LayerManagerOGL.h"
 #include "RenderFrameParent.h"
 
 #include "gfx3DMatrix.h"
 #include "nsFrameLoader.h"
 #include "nsViewportFrame.h"
+#include "nsSubDocumentFrame.h"
 
 typedef nsFrameLoader::ViewportConfig ViewportConfig;
 using namespace mozilla::layers;
 
 namespace mozilla {
 namespace layout {
 
 static void
@@ -359,20 +360,56 @@ RenderFrameParent::GetShadowLayers() con
 
 ContainerLayer*
 RenderFrameParent::GetRootLayer() const
 {
   ShadowLayersParent* shadowLayers = GetShadowLayers();
   return shadowLayers ? shadowLayers->GetRoot() : nsnull;
 }
 
+NS_IMETHODIMP
+RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder,
+                                    nsSubDocumentFrame* aFrame,
+                                    const nsRect& aDirtyRect,
+                                    const nsDisplayListSet& aLists)
+{
+  // We're the subdoc for <browser remote="true"> and it has
+  // painted content.  Display its shadow layer tree.
+  nsDisplayList shadowTree;
+  shadowTree.AppendToTop(
+    new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this));
+
+  // Clip the shadow layers to subdoc bounds
+  nsPoint offset = aFrame->GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
+  nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset;
+
+  return aLists.Content()->AppendNewToTop(
+    new (aBuilder) nsDisplayClip(aBuilder, aFrame, &shadowTree,
+                                 bounds));
+}
+
 }  // namespace layout
 }  // namespace mozilla
 
 already_AddRefed<Layer>
 nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
                             LayerManager* aManager)
 {
   PRInt32 appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel);
   nsRefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect);
   return layer.forget();
 }
+
+
+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
+  //     cover that case here.
+  //
+  if (aState->mShadows) {
+    aState->mShadows->AppendElement(mId);
+  }
+}
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -39,44 +39,50 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_layout_RenderFrameParent_h
 #define mozilla_layout_RenderFrameParent_h
 
 #include "mozilla/layout/PRenderFrameParent.h"
 
 #include "nsDisplayList.h"
+#include "Layers.h"
 
 class nsFrameLoader;
+class nsSubDocumentFrame;
 
 namespace mozilla {
+
 namespace layers {
-class ContainerLayer;
-class Layer;
-class LayerManager;
 class ShadowLayersParent;
 }
 
 namespace layout {
 
 class RenderFrameParent : public PRenderFrameParent
 {
+  typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ContainerLayer ContainerLayer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ShadowLayersParent ShadowLayersParent;
 
 public:
   RenderFrameParent(nsFrameLoader* aFrameLoader);
   virtual ~RenderFrameParent();
 
   void Destroy();
 
   void ShadowLayersUpdated();
 
+  NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
+                              nsSubDocumentFrame* aFrame,
+                              const nsRect& aDirtyRect,
+                              const nsDisplayListSet& aLists);
+
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame,
                                      LayerManager* aManager,
                                      const nsIntRect& aVisibleRect);
 
 protected:
   NS_OVERRIDE void ActorDestroy(ActorDestroyReason why);
 
@@ -121,9 +127,52 @@ public:
   BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager);
 
   NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE)
 
 private:
   RenderFrameParent* mRemoteFrame;
 };
 
+/**
+ * nsDisplayRemoteShadow is a way of adding display items for frames in a
+ * separate process, for hit testing only. After being processed, the hit
+ * test state will contain IDs for any remote frames that were hit.
+ *
+ * The frame should be its respective render frame parent.
+ */
+class nsDisplayRemoteShadow : public nsDisplayItem
+{
+  typedef mozilla::layout::RenderFrameParent RenderFrameParent;
+  typedef mozilla::layers::FrameMetrics::ViewID ViewID;
+
+public:
+  nsDisplayRemoteShadow(nsDisplayListBuilder* aBuilder,
+                        nsIFrame* aFrame,
+                        nsRect aRect,
+                        ViewID aId)
+    : nsDisplayItem(aBuilder, aFrame)
+    , mRect(aRect)
+    , mId(aId)
+  {}
+
+  NS_OVERRIDE nsRect GetBounds(nsDisplayListBuilder* aBuilder)
+  {
+    return mRect;
+  }
+
+  virtual PRUint32 GetPerFrameKey()
+  {
+    NS_ABORT();
+    return 0;
+  }
+
+  NS_OVERRIDE void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+                           HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
+
+  NS_DISPLAY_DECL_NAME("Remote-Shadow", TYPE_REMOTE_SHADOW)
+
+private:
+  nsRect mRect;
+  ViewID mId;
+};
+
 #endif  // mozilla_layout_RenderFrameParent_h