Bug 787131. Move management of primary content state stuff from the nsSubDocumentFrame into the nsFrameLoader, so it works on display:none elements. r=jlebar

This commit is contained in:
Boris Zbarsky 2012-09-04 23:00:26 -04:00
parent d7c07b26b1
commit 25a4faafba
3 changed files with 123 additions and 97 deletions

View File

@ -91,6 +91,10 @@
#include "mozilla/dom/StructuredCloneUtils.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
@ -306,6 +310,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
, mClipSubdocument(true)
, mClampScrollPosition(true)
, mRemoteBrowserInitialized(false)
, mObservingOwnerContent(false)
, mCurrentRemoteFrame(nullptr)
, mRemoteBrowser(nullptr)
, mRenderMode(RENDER_MODE_DEFAULT)
@ -657,29 +662,24 @@ SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
/**
* Set the type of the treeitem and hook it up to the treeowner.
* @param aItem the treeitem we're working with
* @param aOwningContent the content node that owns aItem
* @param aTreeOwner the relevant treeowner; might be null
* @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
* @param aParentNode if non-null, the docshell we should be added as a child to
*
* @return whether aItem is top-level content
*/
static bool
AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, nsIContent* aOwningContent,
nsIDocShellTreeOwner* aOwner, int32_t aParentType,
nsIDocShellTreeNode* aParentNode)
bool
nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
nsIDocShellTreeOwner* aOwner,
int32_t aParentType,
nsIDocShellTreeNode* aParentNode)
{
NS_PRECONDITION(aItem, "Must have docshell treeitem");
NS_PRECONDITION(aOwningContent, "Must have owning content");
NS_PRECONDITION(mOwnerContent, "Must have owning content");
nsAutoString value;
bool isContent = false;
if (aOwningContent->IsXUL()) {
aOwningContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
} else {
aOwningContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozframetype, value);
}
mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
// we accept "content" and "content-xxx" values.
// at time of writing, we expect "xxx" to be "primary" or "targetable", but
@ -692,7 +692,7 @@ AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, nsIContent* aOwningContent,
// Force mozbrowser frames to always be typeContent, even if the
// mozbrowser interfaces are disabled.
nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
do_QueryInterface(aOwningContent);
do_QueryInterface(mOwnerContent);
if (mozbrowser) {
bool isMozbrowser = false;
mozbrowser->GetMozbrowser(&isMozbrowser);
@ -725,6 +725,8 @@ AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, nsIContent* aOwningContent,
if (aOwner) {
bool is_targetable = is_primary ||
value.LowerCaseEqualsLiteral("content-targetable");
mOwnerContent->AddMutationObserver(this);
mObservingOwnerContent = true;
aOwner->ContentShellAdded(aItem, is_primary, is_targetable, value);
}
}
@ -1205,10 +1207,15 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherTreeItem, ourOwner,
ourChromeEventHandler);
AddTreeItemToTreeOwner(ourTreeItem, otherContent, otherOwner,
otherParentType, nullptr);
AddTreeItemToTreeOwner(otherTreeItem, ourContent, ourOwner, ourParentType,
nullptr);
// Switch the owner content before we start calling AddTreeItemToTreeOwner.
// Note that we rely on this to deal with setting mObservingOwnerContent to
// false and calling RemoveMutationObserver as needed.
SetOwnerContent(otherContent);
aOther->SetOwnerContent(ourContent);
AddTreeItemToTreeOwner(ourTreeItem, otherOwner, otherParentType, nullptr);
aOther->AddTreeItemToTreeOwner(otherTreeItem, ourOwner, ourParentType,
nullptr);
// SetSubDocumentFor nulls out parent documents on the old child doc if a
// new non-null document is passed in, so just go ahead and remove both
@ -1222,9 +1229,6 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
ourWindow->SetFrameElementInternal(otherFrameElement);
otherWindow->SetFrameElementInternal(ourFrameElement);
SetOwnerContent(otherContent);
aOther->SetOwnerContent(ourContent);
nsRefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
nsRefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
// Swap pointers in child message managers.
@ -1383,6 +1387,10 @@ nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
void
nsFrameLoader::SetOwnerContent(Element* aContent)
{
if (mObservingOwnerContent) {
mObservingOwnerContent = false;
mOwnerContent->RemoveMutationObserver(this);
}
mOwnerContent = aContent;
if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
rfp->OwnerContentChanged(aContent);
@ -1559,8 +1567,8 @@ nsFrameLoader::MaybeCreateDocShell()
parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
NS_ENSURE_STATE(parentTreeOwner);
mIsTopLevelContent =
AddTreeItemToTreeOwner(docShellAsItem, mOwnerContent, parentTreeOwner,
parentType, parentAsNode);
AddTreeItemToTreeOwner(docShellAsItem, parentTreeOwner, parentType,
parentAsNode);
// Make sure all shells have links back to the content element
// in the nearest enclosing chrome shell.
@ -2404,3 +2412,78 @@ nsFrameLoader::GetDetachedSubdocView(nsIDocument** aContainerDoc) const
return mDetachedSubdocViews;
}
/* virtual */ void
nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
mozilla::dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType)
{
MOZ_ASSERT(mObservingOwnerContent);
// TODO: Implement ContentShellAdded for remote browsers (bug 658304)
MOZ_ASSERT(!mRemoteBrowser);
if (aNameSpaceID != kNameSpaceID_None || aAttribute != TypeAttrName()) {
return;
}
if (aElement != mOwnerContent) {
return;
}
// Note: This logic duplicates a lot of logic in
// MaybeCreateDocshell. We should fix that.
// Notify our enclosing chrome that our type has changed. We only do this
// if our parent is chrome, since in all other cases we're random content
// subframes and the treeowner shouldn't worry about us.
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
if (!docShellAsItem) {
return;
}
nsCOMPtr<nsIDocShellTreeItem> parentItem;
docShellAsItem->GetParent(getter_AddRefs(parentItem));
if (!parentItem) {
return;
}
int32_t parentType;
parentItem->GetItemType(&parentType);
if (parentType != nsIDocShellTreeItem::typeChrome) {
return;
}
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
if (!parentTreeOwner) {
return;
}
nsAutoString value;
aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
#ifdef MOZ_XUL
// when a content panel is no longer primary, hide any open popups it may have
if (!is_primary) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->HidePopupsInDocShell(docShellAsItem);
}
#endif
parentTreeOwner->ContentShellRemoved(docShellAsItem);
if (value.LowerCaseEqualsLiteral("content") ||
StringBeginsWith(value, NS_LITERAL_STRING("content-"),
nsCaseInsensitiveStringComparator())) {
bool is_targetable = is_primary ||
value.LowerCaseEqualsLiteral("content-targetable");
parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
is_targetable, value);
}
}

View File

@ -22,6 +22,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/Attributes.h"
#include "FrameMetrics.h"
#include "nsStubMutationObserver.h"
class nsIURI;
class nsSubDocumentFrame;
@ -29,6 +30,9 @@ class nsIView;
class nsIInProcessContentFrameMessageManager;
class AutoResetInShow;
class nsITabParent;
class nsIDocShellTreeItem;
class nsIDocShellTreeOwner;
class nsIDocShellTreeNode;
namespace mozilla {
namespace dom {
@ -135,7 +139,8 @@ private:
class nsFrameLoader MOZ_FINAL : public nsIFrameLoader,
public nsIContentViewManager
public nsIContentViewManager,
public nsStubMutationObserver
{
friend class AutoResetInShow;
typedef mozilla::dom::PBrowserParent PBrowserParent;
@ -166,6 +171,7 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameLoader, nsIFrameLoader)
NS_DECL_NSIFRAMELOADER
NS_DECL_NSICONTENTVIEWMANAGER
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI);
nsresult ReallyStartLoading();
void Finalize();
@ -337,9 +343,19 @@ private:
// Tell the remote browser that it's now "virtually visible"
bool ShowRemoteFrame(const nsIntSize& size);
bool AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
nsIDocShellTreeOwner* aOwner,
int32_t aParentType,
nsIDocShellTreeNode* aParentNode);
nsIAtom* TypeAttrName() const {
return mOwnerContent->IsXUL() ? nsGkAtoms::type : nsGkAtoms::mozframetype;
}
nsCOMPtr<nsIDocShell> mDocShell;
nsCOMPtr<nsIURI> mURIToLoad;
mozilla::dom::Element* mOwnerContent; // WEAK
public:
// public because a callback needs these.
nsRefPtr<nsFrameMessageManager> mMessageManager;
@ -373,6 +389,7 @@ private:
bool mClipSubdocument : 1;
bool mClampScrollPosition : 1;
bool mRemoteBrowserInitialized : 1;
bool mObservingOwnerContent : 1;
// XXX leaking
nsCOMPtr<nsIObserver> mChildHost;

View File

@ -54,10 +54,6 @@
#include "nsIServiceManager.h"
#include "nsContentUtils.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#endif
// For Accessibility
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
@ -703,76 +699,6 @@ nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
if (frameloader)
frameloader->MarginsChanged(margins.width, margins.height);
}
else if (aAttribute == nsGkAtoms::type) {
if (!mFrameLoader)
return NS_OK;
if (!mContent->IsXUL()) {
return NS_OK;
}
if (mFrameLoader->GetRemoteBrowser()) {
// TODO: Implement ContentShellAdded for remote browsers (bug 658304)
return NS_OK;
}
// Note: This logic duplicates a lot of logic in
// nsFrameLoader::EnsureDocShell. We should fix that.
// Notify our enclosing chrome that our type has changed. We only do this
// if our parent is chrome, since in all other cases we're random content
// subframes and the treeowner shouldn't worry about us.
nsCOMPtr<nsIDocShell> docShell;
mFrameLoader->GetDocShell(getter_AddRefs(docShell));
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
if (!docShellAsItem) {
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeItem> parentItem;
docShellAsItem->GetParent(getter_AddRefs(parentItem));
if (!parentItem) {
return NS_OK;
}
int32_t parentType;
parentItem->GetItemType(&parentType);
if (parentType != nsIDocShellTreeItem::typeChrome) {
return NS_OK;
}
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
if (parentTreeOwner) {
nsAutoString value;
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
#ifdef MOZ_XUL
// when a content panel is no longer primary, hide any open popups it may have
if (!is_primary) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->HidePopupsInDocShell(docShellAsItem);
}
#endif
parentTreeOwner->ContentShellRemoved(docShellAsItem);
if (value.LowerCaseEqualsLiteral("content") ||
StringBeginsWith(value, NS_LITERAL_STRING("content-"),
nsCaseInsensitiveStringComparator())) {
bool is_targetable = is_primary ||
value.LowerCaseEqualsLiteral("content-targetable");
parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
is_targetable, value);
}
}
}
return NS_OK;
}