Bug 605618 Part 4: Map for storing views r=cjones

This commit is contained in:
Benjamin Stover 2011-01-13 09:45:14 -08:00
parent 1b69189147
commit 871b660fda
4 changed files with 178 additions and 10 deletions

View File

@ -115,12 +115,14 @@
#ifdef MOZ_IPC
#include "ContentParent.h"
#include "TabParent.h"
#include "mozilla/layout/RenderFrameParent.h"
using namespace mozilla;
using namespace mozilla::dom;
#endif
using namespace mozilla::layers;
typedef FrameMetrics::ViewID ViewID;
#include "jsapi.h"
@ -302,7 +304,6 @@ nsFrameLoader::nsFrameLoader(nsIContent *aOwner, PRBool aNetworkCreated)
, mCurrentRemoteFrame(nsnull)
, mRemoteBrowser(nsnull)
#endif
, mContentView(new nsContentView(aOwner, FrameMetrics::ROOT_SCROLL_ID))
{
}
@ -1284,6 +1285,9 @@ void
nsFrameLoader::SetOwnerContent(nsIContent* aContent)
{
mOwnerContent = aContent;
if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
rfp->OwnerContentChanged(aContent);
}
}
#ifdef MOZ_IPC
@ -1975,16 +1979,51 @@ nsFrameLoader::GetContentViewsIn(float aXPx, float aYPx,
PRUint32* aLength,
nsIContentView*** aResult)
{
*aResult = nsnull;
*aLength = 0;
nscoord x = nsPresContext::CSSPixelsToAppUnits(aXPx - aLeftSize);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aYPx - aTopSize);
nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
nsRect target(x, y, w, h);
nsIFrame* frame = GetPrimaryFrameOfOwningContent();
nsTArray<ViewID> ids;
nsLayoutUtils::GetRemoteContentIds(frame, target, ids, true);
if (ids.Length() == 0 || !GetCurrentRemoteFrame()) {
*aResult = nsnull;
*aLength = 0;
return NS_OK;
}
nsIContentView** result = reinterpret_cast<nsIContentView**>(
NS_Alloc(ids.Length() * sizeof(nsIContentView*)));
for (PRUint32 i = 0; i < ids.Length(); i++) {
nsIContentView* view = GetCurrentRemoteFrame()->GetContentView(ids[i]);
NS_ABORT_IF_FALSE(view, "Retrieved ID from RenderFrameParent, it should be valid!");
nsRefPtr<nsIContentView>(view).forget(&result[i]);
}
*aResult = result;
*aLength = ids.Length();
return NS_OK;
}
NS_IMETHODIMP
nsFrameLoader::GetRootContentView(nsIContentView** aContentView)
{
nsRefPtr<nsIContentView>(GetContentView()).forget(aContentView);
return NS_OK;
RenderFrameParent* rfp = GetCurrentRemoteFrame();
if (!rfp) {
*aContentView = nsnull;
return NS_OK;
}
nsContentView* view = rfp->GetContentView();
NS_ABORT_IF_FALSE(view, "Should always be able to create root scrollable!");
nsRefPtr<nsIContentView>(view).forget(aContentView);
return NS_OK;
}
nsresult

View File

@ -272,8 +272,7 @@ public:
#endif
nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; }
nsContentView* GetContentView() { return mContentView; }
nsIContent* GetOwnerContent() { return mOwnerContent; }
void SetOwnerContent(nsIContent* aContent);
private:
@ -338,8 +337,6 @@ private:
TabParent* mRemoteBrowser;
#endif
nsRefPtr<nsContentView> mContentView;
// See nsIFrameLoader.idl. Short story, if !(mRenderMode &
// RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in
// favor of what content tells.

View File

@ -55,6 +55,9 @@ using namespace mozilla::layers;
namespace mozilla {
namespace layout {
typedef FrameMetrics::ViewID ViewID;
typedef RenderFrameParent::ViewMap ViewMap;
static void
AssertInTopLevelChromeDoc(ContainerLayer* aContainer,
nsIFrame* aContainedFrame)
@ -66,6 +69,14 @@ AssertInTopLevelChromeDoc(ContainerLayer* aContainer,
"Expected frame to be in top-level chrome document");
}
// Return view for given ID in aArray, NULL if not found.
static nsContentView*
FindViewForId(const ViewMap& aMap, ViewID aId)
{
ViewMap::const_iterator iter = aMap.find(aId);
return iter != aMap.end() ? iter->second : NULL;
}
static void
AssertValidContainerOfShadowTree(ContainerLayer* aContainer,
Layer* aShadowRoot)
@ -179,10 +190,65 @@ IsTempLayerManager(LayerManager* aManager)
!static_cast<BasicLayerManager*>(aManager)->IsRetained());
}
// Recursively create a new array of scrollables, preserving any scrollables
// that are still in the layer tree.
//
// aXScale and aYScale are used to calculate any values that need to be in
// chrome-document CSS pixels and aren't part of the rendering loop, such as
// the initial scroll offset for a new view.
static void
BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
nsFrameLoader* aFrameLoader, Layer* aLayer,
float aXScale = 1, float aYScale = 1)
{
if (!aLayer->GetFirstChild())
return;
ContainerLayer* container = static_cast<ContainerLayer*>(aLayer);
const FrameMetrics& metrics = container->GetFrameMetrics();
const ViewID scrollId = metrics.mScrollId;
nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent()
->PresContext()->AppUnitsPerDevPixel();
nsContentView* view = FindViewForId(oldContentViews, scrollId);
if (view) {
// View already exists. Be sure to propagate scales for any values
// that need to be calculated something in chrome-doc CSS pixels.
ViewConfig config = view->GetViewConfig();
aXScale *= config.mXScale;
aYScale *= config.mYScale;
view->mOwnerContent = aFrameLoader->GetOwnerContent();
} else {
// View doesn't exist, so generate one. We start the view scroll offset at
// the same position as the framemetric's scroll offset from the layer.
// The default scale is 1, so no need to propagate scale down.
ViewConfig config;
config.mScrollOffset = nsPoint(
NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.x, auPerDevPixel) * aXScale,
NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.y, auPerDevPixel) * aYScale);
view = new nsContentView(aFrameLoader->GetOwnerContent(), scrollId, config);
}
newContentViews.insert(ViewMap::value_type(scrollId, view));
for (Layer* child = aLayer->GetFirstChild();
child; child = child->GetNextSibling()) {
const gfx3DMatrix transform = aLayer->GetTransform();
aXScale *= transform._11;
aYScale *= transform._22;
BuildViewMap(oldContentViews, newContentViews, aFrameLoader, child,
aXScale, aYScale);
}
}
RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader)
: mFrameLoader(aFrameLoader)
{
NS_ABORT_IF_FALSE(aFrameLoader, "Need a frameloader here");
mContentViews.insert(ViewMap::value_type(
FrameMetrics::ROOT_SCROLL_ID,
new nsContentView(aFrameLoader->GetOwnerContent(), FrameMetrics::ROOT_SCROLL_ID)
));
}
RenderFrameParent::~RenderFrameParent()
@ -202,11 +268,22 @@ RenderFrameParent::Destroy()
}
}
nsContentView*
RenderFrameParent::GetContentView(ViewID aId)
{
return FindViewForId(mContentViews, aId);
}
void
RenderFrameParent::ShadowLayersUpdated()
{
mFrameLoader->SetCurrentRemoteFrame(this);
// View map must only contain views that are associated with the current
// shadow layer tree. We must always update the map when shadow layers
// are updated.
BuildViewMap();
nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent();
if (!docFrame) {
// Bad, but nothing we can do about it (XXX/cjones: or is there?
@ -286,7 +363,7 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
float shadowXScale, shadowYScale;
ComputeShadowTreeTransform(aFrame,
shadowRoot->GetFrameMetrics(),
mFrameLoader->GetContentView()->GetViewConfig(),
GetContentView()->GetViewConfig(),
aBuilder,
&shadowTranslation,
&shadowXScale, &shadowYScale);
@ -299,6 +376,14 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
return nsRefPtr<Layer>(mContainer).forget();
}
void
RenderFrameParent::OwnerContentChanged(nsIContent* aContent)
{
NS_ABORT_IF_FALSE(mFrameLoader->GetOwnerContent() == aContent,
"Don't build new map if owner is same!");
BuildViewMap();
}
void
RenderFrameParent::ActorDestroy(ActorDestroyReason why)
{
@ -341,6 +426,34 @@ RenderFrameParent::DeallocPLayers(PLayersParent* aLayers)
return true;
}
void
RenderFrameParent::BuildViewMap()
{
ViewMap newContentViews;
if (GetRootLayer()) {
// Some of the content views in our hash map may no longer be active. To
// tag them as inactive and to remove any chance of them using a dangling
// pointer, we set mContentView to NULL.
//
// BuildViewMap will restore mOwnerContent if the content view is still
// in our hash table.
for (ViewMap::const_iterator iter = mContentViews.begin();
iter != mContentViews.end();
++iter) {
iter->second->mOwnerContent = NULL;
}
mozilla::layout::BuildViewMap(mContentViews, newContentViews, mFrameLoader, GetRootLayer());
}
// Root scrollable layer might not be around yet. Don't accidentally delete
// our view for it.
if (!newContentViews.empty()) {
mContentViews = newContentViews;
}
}
LayerManager*
RenderFrameParent::GetLayerManager() const
{

View File

@ -43,9 +43,11 @@
#include "mozilla/layout/PRenderFrameParent.h"
#include <map>
#include "nsDisplayList.h"
#include "Layers.h"
class nsContentView;
class nsFrameLoader;
class nsSubDocumentFrame;
@ -64,13 +66,22 @@ class RenderFrameParent : public PRenderFrameParent
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::ShadowLayersParent ShadowLayersParent;
typedef FrameMetrics::ViewID ViewID;
public:
typedef std::map<ViewID, nsRefPtr<nsContentView> > ViewMap;
RenderFrameParent(nsFrameLoader* aFrameLoader);
virtual ~RenderFrameParent();
void Destroy();
/**
* Helper function for getting a non-owning reference to a scrollable.
* @param aId The ID of the frame.
*/
nsContentView* GetContentView(ViewID aId = FrameMetrics::ROOT_SCROLL_ID);
void ShadowLayersUpdated();
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
@ -83,6 +94,8 @@ public:
LayerManager* aManager,
const nsIntRect& aVisibleRect);
void OwnerContentChanged(nsIContent* aContent);
protected:
NS_OVERRIDE void ActorDestroy(ActorDestroyReason why);
@ -90,12 +103,18 @@ protected:
NS_OVERRIDE virtual bool DeallocPLayers(PLayersParent* aLayers);
private:
void BuildViewMap();
LayerManager* GetLayerManager() const;
ShadowLayersParent* GetShadowLayers() const;
ContainerLayer* GetRootLayer() const;
nsRefPtr<nsFrameLoader> mFrameLoader;
nsRefPtr<ContainerLayer> mContainer;
// This contains the views for all the scrollable frames currently in the
// painted region of our remote content.
ViewMap mContentViews;
};
} // namespace layout