mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 113934. Backend and some minimal front end for dragging tabs between windows. r=gavin, r+sr=jst
This commit is contained in:
parent
a972f7cd1c
commit
1b9a4caf46
@ -278,7 +278,6 @@
|
||||
mTab: aTab,
|
||||
mBrowser: aBrowser,
|
||||
mBlank: aStartsBlank,
|
||||
mLastURI: null,
|
||||
|
||||
// cache flags for correct status bar update after tab switching
|
||||
mStateFlags: 0,
|
||||
@ -1389,6 +1388,18 @@
|
||||
|
||||
<method name="removeTab">
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._endRemoveTab(this._beginRemoveTab(aTab, true));
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<!-- Returns the tab being removed. This might not be the same as aTab,
|
||||
in cases when aTab is not actually a tab -->
|
||||
<method name="_beginRemoveTab">
|
||||
<parameter name="aTab"/>
|
||||
<parameter name="aFireBeforeUnload"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._browsers = null; // invalidate cache
|
||||
@ -1403,9 +1414,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var ds = this.getBrowserForTab(aTab).docShell;
|
||||
if (ds.contentViewer && !ds.contentViewer.permitUnload())
|
||||
return;
|
||||
if (aFireBeforeUnload) {
|
||||
var ds = this.getBrowserForTab(aTab).docShell;
|
||||
if (ds.contentViewer && !ds.contentViewer.permitUnload())
|
||||
return;
|
||||
}
|
||||
|
||||
// see notes in addTab
|
||||
var _delayedUpdate = function(aTabContainer) {
|
||||
@ -1435,15 +1448,7 @@
|
||||
evt.initEvent("TabClose", true, false);
|
||||
aTab.dispatchEvent(evt);
|
||||
|
||||
var index = -1;
|
||||
if (this.mCurrentTab == aTab)
|
||||
index = this.mTabContainer.selectedIndex;
|
||||
else {
|
||||
// Find and locate the tab in our list.
|
||||
for (var i = 0; i < l; i++)
|
||||
if (this.mTabContainer.childNodes[i] == aTab)
|
||||
index = i;
|
||||
}
|
||||
var index = aTab._tPos;
|
||||
|
||||
// Remove the tab's filter and progress listener.
|
||||
const filter = this.mTabFilters[index];
|
||||
@ -1459,22 +1464,34 @@
|
||||
// We are no longer the primary content area.
|
||||
oldBrowser.setAttribute("type", "content-targetable");
|
||||
|
||||
// Get the index of the tab we're removing before unselecting it
|
||||
var currentIndex = this.mTabContainer.selectedIndex;
|
||||
|
||||
var oldTab = aTab;
|
||||
|
||||
// clean up the before/afterselected attributes before removing the tab
|
||||
oldTab._selected = false;
|
||||
|
||||
// Remove this tab as the owner of any other tabs, since it's going away.
|
||||
for (i = 0; i < this.mTabContainer.childNodes.length; ++i) {
|
||||
for (var i = 0; i < this.mTabs.length; ++i) {
|
||||
var tab = this.mTabContainer.childNodes[i];
|
||||
if ("owner" in tab && tab.owner == oldTab)
|
||||
if ("owner" in tab && tab.owner == aTab)
|
||||
// |tab| is a child of the tab we're removing, make it an orphan
|
||||
tab.owner = null;
|
||||
}
|
||||
|
||||
return aTab;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_endRemoveTab">
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var browser = this.getBrowserForTab(aTab);
|
||||
var length = this.mTabs.length;
|
||||
|
||||
// Get the index of the tab we're removing before unselecting it
|
||||
var currentIndex = this.mTabContainer.selectedIndex;
|
||||
var index = aTab._tPos;
|
||||
|
||||
// clean up the before/afterselected attributes before removing the
|
||||
// tab. But make sure this happens after we grab currentIndex.
|
||||
aTab._selected = false;
|
||||
|
||||
// Because of the way XBL works (fields just set JS
|
||||
// properties on the element) and the code we have in place
|
||||
// to preserve the JS objects for any elements that have
|
||||
@ -1485,16 +1502,18 @@
|
||||
// XBL implementation of nsIObserver still works. But
|
||||
// clearing focusedWindow happens below because it gets
|
||||
// reset by updateCurrentBrowser.
|
||||
oldBrowser.destroy();
|
||||
browser.destroy();
|
||||
|
||||
if (oldBrowser == this.mCurrentBrowser)
|
||||
if (browser == this.mCurrentBrowser)
|
||||
this.mCurrentBrowser = null;
|
||||
|
||||
// Remove the tab
|
||||
this.mTabContainer.removeChild(oldTab);
|
||||
this.mTabContainer.removeChild(aTab);
|
||||
// Update our length
|
||||
--length;
|
||||
// invalidate cache, because mTabContainer is about to change
|
||||
this._browsers = null;
|
||||
this.mPanelContainer.removeChild(oldBrowser.parentNode);
|
||||
this.mPanelContainer.removeChild(browser.parentNode);
|
||||
|
||||
try {
|
||||
// if we're at the right side (and not the logical end,
|
||||
@ -1523,24 +1542,24 @@
|
||||
else if (currentIndex < index)
|
||||
newIndex = currentIndex;
|
||||
else {
|
||||
if ("owner" in oldTab && oldTab.owner &&
|
||||
if ("owner" in aTab && aTab.owner &&
|
||||
this.mPrefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
|
||||
for (i = 0; i < this.mTabContainer.childNodes.length; ++i) {
|
||||
for (var i = 0; i < length; ++i) {
|
||||
tab = this.mTabContainer.childNodes[i];
|
||||
if (tab == oldTab.owner) {
|
||||
if (tab == aTab.owner) {
|
||||
newIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newIndex == -1)
|
||||
newIndex = (index == l - 1) ? index - 1 : index;
|
||||
newIndex = (index == length) ? index - 1 : index;
|
||||
}
|
||||
|
||||
// Select the new tab
|
||||
this.selectedTab = this.mTabContainer.childNodes[newIndex];
|
||||
this.selectedTab = this.mTabs[newIndex];
|
||||
|
||||
for (i = oldTab._tPos; i < this.mTabContainer.childNodes.length; i++) {
|
||||
for (i = aTab._tPos; i < length; i++) {
|
||||
this.mTabContainer.childNodes[i]._tPos = i;
|
||||
}
|
||||
this.mTabBox.selectedPanel = this.getBrowserForTab(this.mCurrentTab).parentNode;
|
||||
@ -1549,8 +1568,53 @@
|
||||
this.updateCurrentBrowser();
|
||||
|
||||
// see comment above destroy above
|
||||
oldBrowser.focusedWindow = null;
|
||||
oldBrowser.focusedElement = null;
|
||||
browser.focusedWindow = null;
|
||||
browser.focusedElement = null;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="swapBrowsersAndCloseOther">
|
||||
<parameter name="aOurTab"/>
|
||||
<parameter name="aOtherTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var remoteBrowser =
|
||||
aOtherTab.ownerDocument.defaultView.getBrowser();
|
||||
var tabCount = remoteBrowser.mTabs.length;
|
||||
|
||||
// First, start teardown of the other browser. Make sure to not
|
||||
// fire the beforeunload event in the process.
|
||||
var tabToRemove = remoteBrowser._beginRemoveTab(aOtherTab, false);
|
||||
|
||||
// Unhook our progress listener
|
||||
var ourIndex = aOurTab._tPos;
|
||||
const filter = this.mTabFilters[ourIndex];
|
||||
var tabListener = this.mTabListeners[ourIndex];
|
||||
var ourBrowser = this.getBrowserForTab(aOurTab);
|
||||
ourBrowser.webProgress.removeProgressListener(filter);
|
||||
filter.removeProgressListener(tabListener);
|
||||
var tabListenerBlank = tabListener.mBlank;
|
||||
|
||||
// Swap the docshells
|
||||
ourBrowser.swapDocShells(remoteBrowser.getBrowserForTab(aOtherTab));
|
||||
|
||||
// Finish tearing down the tab that's going away.
|
||||
remoteBrowser._endRemoveTab(tabToRemove);
|
||||
|
||||
// Restore the progress listener
|
||||
tabListener = this.mTabProgressListener(aOurTab, ourBrowser,
|
||||
tabListenerBlank);
|
||||
this.mTabListeners[ourIndex] = tabListener;
|
||||
filter.addProgressListener(tabListener,
|
||||
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
|
||||
ourBrowser.webProgress.addProgressListener(filter,
|
||||
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||
|
||||
// close the other window if this was its last tab
|
||||
if (tabCount == 1)
|
||||
aOtherTab.ownerDocument.defaultView.close();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
@ -1879,19 +1943,26 @@
|
||||
}
|
||||
}
|
||||
else if (draggedTab) {
|
||||
// copy the dropped tab and remove it from the other window
|
||||
// (making it seem to have moved between windows)
|
||||
// swap the dropped tab with a new one we create and then close
|
||||
// it in the other window (making it seem to have moved between
|
||||
// windows)
|
||||
newIndex = this.getNewIndex(aEvent);
|
||||
newTab = this.duplicateTab(draggedTab);
|
||||
this.moveTabTo(newTab, newIndex);
|
||||
this.selectedTab = newTab;
|
||||
newTab = this.addTab("about:blank");
|
||||
var newBrowser = this.getBrowserForTab(newTab);
|
||||
// Stop the about:blank load
|
||||
newBrowser.stop();
|
||||
// make sure it has a docshell
|
||||
newBrowser.docShell;
|
||||
|
||||
var remoteBrowser = draggedTab.ownerDocument.defaultView.getBrowser();
|
||||
var tabCount = remoteBrowser.tabContainer.childNodes.length;
|
||||
remoteBrowser.removeTab(draggedTab);
|
||||
// close the other window if this was its last tab
|
||||
if (tabCount == 1)
|
||||
draggedTab.ownerDocument.defaultView.close();
|
||||
this.moveTabTo(newTab, newIndex);
|
||||
|
||||
this.swapBrowsersAndCloseOther(newTab, draggedTab);
|
||||
|
||||
// We need to set selectedTab after we've done
|
||||
// swapBrowsersAndCloseOther, so that the updateCurrentBrowser
|
||||
// it triggers will correctly update our URL bar.
|
||||
this.selectedTab = newTab;
|
||||
this.setTabTitle(newTab);
|
||||
}
|
||||
else {
|
||||
var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
|
||||
|
@ -76,8 +76,23 @@ interface nsIFrameLoader : nsISupports
|
||||
readonly attribute boolean depthTooGreat;
|
||||
};
|
||||
|
||||
[scriptable, uuid(feaf9285-05ac-4898-a69f-c3bd350767e4)]
|
||||
[scriptable, uuid(641c2d90-4ada-4367-bdb1-80831614161d)]
|
||||
interface nsIFrameLoaderOwner : nsISupports
|
||||
{
|
||||
/**
|
||||
* The frame loader owned by this nsIFrameLoaderOwner
|
||||
*/
|
||||
readonly attribute nsIFrameLoader frameLoader;
|
||||
|
||||
/**
|
||||
* Swap frame loaders with the given nsIFrameLoaderOwner. This may
|
||||
* only be posible in a very limited range of circumstances, or
|
||||
* never, depending on the object implementing this interface.
|
||||
*
|
||||
* @throws NS_ERROR_NOT_IMPLEMENTED if the swapping logic is not
|
||||
* implemented for the two given frame loader owners.
|
||||
* @throws NS_ERROR_DOM_SECURITY_ERR if the swap is not allowed on
|
||||
* security grounds.
|
||||
*/
|
||||
void swapFrameLoaders(in nsIFrameLoaderOwner aOtherOwner);
|
||||
};
|
||||
|
@ -58,6 +58,11 @@ public:
|
||||
}
|
||||
return shell;
|
||||
}
|
||||
|
||||
PRBool HasMoreThanOneShell() {
|
||||
return mDoc->mPresShells.Length() > 1;
|
||||
}
|
||||
|
||||
private:
|
||||
static void* operator new(size_t) CPP_THROW_NEW { return 0; }
|
||||
static void operator delete(void*, size_t) {}
|
||||
|
@ -22,6 +22,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Johnny Stenback <jst@netscape.com> (original author)
|
||||
* Boris Zbarsky <bzbarsky@mit.edu>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
@ -65,6 +66,12 @@
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIFrameFrame.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsPresShellIterator.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
@ -281,6 +288,367 @@ nsFrameLoader::Finalize()
|
||||
mDocShell = nsnull;
|
||||
}
|
||||
|
||||
static void
|
||||
FirePageHideEvent(nsIDocShellTreeItem* aItem,
|
||||
nsIDOMEventTarget* aChromeEventHandler)
|
||||
{
|
||||
nsPageTransitionEvent event(PR_TRUE, NS_PAGE_HIDE, PR_TRUE);
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(aItem);
|
||||
event.target = do_QueryInterface(doc);
|
||||
nsEventDispatcher::Dispatch(aChromeEventHandler, nsnull, &event);
|
||||
|
||||
PRInt32 childCount = 0;
|
||||
aItem->GetChildCount(&childCount);
|
||||
nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
|
||||
kids.AppendElements(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; ++i) {
|
||||
aItem->GetChildAt(i, getter_AddRefs(kids[i]));
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < kids.Length(); ++i) {
|
||||
if (kids[i]) {
|
||||
FirePageHideEvent(kids[i], aChromeEventHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
FirePageShowEvent(nsIDocShellTreeItem* aItem,
|
||||
nsIDOMEventTarget* aChromeEventHandler)
|
||||
{
|
||||
PRInt32 childCount = 0;
|
||||
aItem->GetChildCount(&childCount);
|
||||
nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
|
||||
kids.AppendElements(childCount);
|
||||
for (PRInt32 i = 0; i < childCount; ++i) {
|
||||
aItem->GetChildAt(i, getter_AddRefs(kids[i]));
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < kids.Length(); ++i) {
|
||||
if (kids[i]) {
|
||||
FirePageShowEvent(kids[i], aChromeEventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
nsPageTransitionEvent event(PR_TRUE, NS_PAGE_SHOW, PR_TRUE);
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(aItem);
|
||||
event.target = do_QueryInterface(doc);
|
||||
nsEventDispatcher::Dispatch(aChromeEventHandler, nsnull, &event);
|
||||
}
|
||||
|
||||
static void
|
||||
SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
|
||||
nsIDocShellTreeOwner* aOwner,
|
||||
nsIDOMEventTarget* aHandler)
|
||||
{
|
||||
NS_PRECONDITION(aItem, "Must have item");
|
||||
#ifdef DEBUG
|
||||
PRInt32 itemType;
|
||||
aItem->GetItemType(&itemType);
|
||||
NS_ASSERTION(itemType == nsIDocShellTreeItem::typeContent,
|
||||
"How did something else get in here?");
|
||||
#endif
|
||||
|
||||
aItem->SetTreeOwner(aOwner);
|
||||
nsCOMPtr<nsIDocShell> shell(do_QueryInterface(aItem));
|
||||
shell->SetChromeEventHandler(aHandler);
|
||||
|
||||
PRInt32 childCount = 0;
|
||||
aItem->GetChildCount(&childCount);
|
||||
for (PRInt32 i = 0; i < childCount; ++i) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> item;
|
||||
aItem->GetChildAt(i, getter_AddRefs(item));
|
||||
SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of the treeitem and hook it up to the treeowner.
|
||||
* @param aItem the treeitem we're wrking 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 PRBool
|
||||
AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, nsIContent* aOwningContent,
|
||||
nsIDocShellTreeOwner* aOwner, PRInt32 aParentType,
|
||||
nsIDocShellTreeNode* aParentNode)
|
||||
{
|
||||
NS_PRECONDITION(aItem, "Must have docshell treeitem");
|
||||
NS_PRECONDITION(aOwningContent, "Must have owning content");
|
||||
|
||||
nsAutoString value;
|
||||
PRBool isContent = PR_FALSE;
|
||||
|
||||
if (aOwningContent->IsNodeOfType(nsINode::eXUL)) {
|
||||
aOwningContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
|
||||
}
|
||||
|
||||
// we accept "content" and "content-xxx" values.
|
||||
// at time of writing, we expect "xxx" to be "primary" or "targetable", but
|
||||
// someday it might be an integer expressing priority or something else.
|
||||
|
||||
isContent = value.LowerCaseEqualsLiteral("content") ||
|
||||
StringBeginsWith(value, NS_LITERAL_STRING("content-"),
|
||||
nsCaseInsensitiveStringComparator());
|
||||
|
||||
if (isContent) {
|
||||
// The web shell's type is content.
|
||||
|
||||
aItem->SetItemType(nsIDocShellTreeItem::typeContent);
|
||||
} else {
|
||||
// Inherit our type from our parent webshell. If it is
|
||||
// chrome, we'll be chrome. If it is content, we'll be
|
||||
// content.
|
||||
|
||||
aItem->SetItemType(aParentType);
|
||||
}
|
||||
|
||||
// Now that we have our type set, add ourselves to the parent, as needed.
|
||||
if (aParentNode) {
|
||||
aParentNode->AddChild(aItem);
|
||||
}
|
||||
|
||||
PRBool retval = PR_FALSE;
|
||||
if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
|
||||
retval = PR_TRUE;
|
||||
|
||||
PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary");
|
||||
|
||||
if (aOwner) {
|
||||
PRBool is_targetable = is_primary ||
|
||||
value.LowerCaseEqualsLiteral("content-targetable");
|
||||
aOwner->ContentShellAdded(aItem, is_primary, is_targetable, value);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
nsRefPtr<nsFrameLoader>& aFirstToSwap,
|
||||
nsRefPtr<nsFrameLoader>& aSecondToSwap)
|
||||
{
|
||||
NS_PRECONDITION((aFirstToSwap == this && aSecondToSwap == aOther) ||
|
||||
(aFirstToSwap == aOther && aSecondToSwap == this),
|
||||
"Swapping some sort of random loaders?");
|
||||
|
||||
nsIContent* ourContent = mOwnerContent;
|
||||
nsIContent* otherContent = aOther->mOwnerContent;
|
||||
|
||||
if (!ourContent || !otherContent) {
|
||||
// Can't handle this
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Make sure there are no same-origin issues
|
||||
PRBool equal;
|
||||
nsresult rv =
|
||||
ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
|
||||
if (NS_FAILED(rv) || !equal) {
|
||||
// Security problems loom. Just bail on it all
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> ourDochell = GetExistingDocShell();
|
||||
nsCOMPtr<nsIDocShell> otherDocshell = aOther->GetExistingDocShell();
|
||||
if (!ourDochell || !otherDocshell) {
|
||||
// How odd
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// To avoid having to mess with session history, avoid swapping
|
||||
// frameloaders that don't correspond to root same-type docshells.
|
||||
nsCOMPtr<nsIDocShellTreeItem> ourTreeItem = do_QueryInterface(ourDochell);
|
||||
nsCOMPtr<nsIDocShellTreeItem> otherTreeItem =
|
||||
do_QueryInterface(otherDocshell);
|
||||
nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem;
|
||||
ourTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
|
||||
otherTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
|
||||
if (ourRootTreeItem != ourTreeItem || otherRootTreeItem != otherTreeItem) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Also make sure that the two docshells are the same type. Otherwise
|
||||
// swapping is certainly not safe. As far as that goes, make sure we only
|
||||
// swap typeContent docshells, since otherwise it's hard to get treeowners
|
||||
// right.
|
||||
PRInt32 ourType = nsIDocShellTreeItem::typeChrome;
|
||||
PRInt32 otherType = nsIDocShellTreeItem::typeChrome;
|
||||
ourTreeItem->GetItemType(&ourType);
|
||||
otherTreeItem->GetItemType(&otherType);
|
||||
if (ourType != nsIDocShellTreeItem::typeContent ||
|
||||
otherType != nsIDocShellTreeItem::typeContent) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Save off the tree owners, frame elements, chrome event handlers, and
|
||||
// docshell and document parents before doing anything else.
|
||||
nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner;
|
||||
ourTreeItem->GetTreeOwner(getter_AddRefs(ourOwner));
|
||||
otherTreeItem->GetTreeOwner(getter_AddRefs(otherOwner));
|
||||
// Note: it's OK to have null treeowners.
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem;
|
||||
ourTreeItem->GetParent(getter_AddRefs(ourParentItem));
|
||||
otherTreeItem->GetParent(getter_AddRefs(otherParentItem));
|
||||
if (!ourParentItem || !otherParentItem) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(ourDochell);
|
||||
nsCOMPtr<nsPIDOMWindow> otherWindow = do_GetInterface(otherDocshell);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> ourFrameElement =
|
||||
ourWindow->GetFrameElementInternal();
|
||||
nsCOMPtr<nsIDOMElement> otherFrameElement =
|
||||
otherWindow->GetFrameElementInternal();
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> ourChromeEventHandler =
|
||||
do_QueryInterface(ourWindow->GetChromeEventHandler());
|
||||
nsCOMPtr<nsIDOMEventTarget> otherChromeEventHandler =
|
||||
do_QueryInterface(otherWindow->GetChromeEventHandler());
|
||||
|
||||
NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
|
||||
SameCOMIdentity(otherFrameElement, otherContent) &&
|
||||
SameCOMIdentity(ourChromeEventHandler, ourContent) &&
|
||||
SameCOMIdentity(otherChromeEventHandler, otherContent),
|
||||
"How did that happen, exactly?");
|
||||
|
||||
nsCOMPtr<nsIDocument> ourChildDocument =
|
||||
do_QueryInterface(ourWindow->GetExtantDocument());
|
||||
nsCOMPtr<nsIDocument> otherChildDocument =
|
||||
do_QueryInterface(otherWindow->GetExtantDocument());
|
||||
if (!ourChildDocument || !otherChildDocument) {
|
||||
// This shouldn't be happening
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> ourParentDocument =
|
||||
ourChildDocument->GetParentDocument();
|
||||
nsCOMPtr<nsIDocument> otherParentDocument =
|
||||
otherChildDocument->GetParentDocument();
|
||||
|
||||
// Make sure to swap docshells between the two frames.
|
||||
nsIDocument* ourDoc = ourContent->GetCurrentDoc();
|
||||
nsIDocument* otherDoc = otherContent->GetCurrentDoc();
|
||||
if (!ourDoc || !otherDoc) {
|
||||
// Again, how odd, given that we had docshells
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(ourDoc == ourParentDocument, "Unexpected parent document");
|
||||
NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document");
|
||||
|
||||
nsPresShellIterator iter1(ourDoc);
|
||||
nsPresShellIterator iter2(otherDoc);
|
||||
if (iter1.HasMoreThanOneShell() || iter2.HasMoreThanOneShell()) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsIPresShell* ourShell = ourDoc->GetPrimaryShell();
|
||||
nsIPresShell* otherShell = otherDoc->GetPrimaryShell();
|
||||
if (!ourShell || !otherShell) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (mInSwap || aOther->mInSwap) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
mInSwap = aOther->mInSwap = PR_TRUE;
|
||||
|
||||
// Fire pagehide events. Note that we do NOT fire these in the normal way,
|
||||
// but just fire them on the chrome event handlers.
|
||||
FirePageHideEvent(ourTreeItem, ourChromeEventHandler);
|
||||
FirePageHideEvent(otherTreeItem, otherChromeEventHandler);
|
||||
|
||||
nsIFrame* ourFrame = ourShell->GetPrimaryFrameFor(ourContent);
|
||||
nsIFrame* otherFrame = otherShell->GetPrimaryFrameFor(otherContent);
|
||||
if (!ourFrame || !otherFrame) {
|
||||
mInSwap = aOther->mInSwap = PR_FALSE;
|
||||
FirePageShowEvent(ourTreeItem, ourChromeEventHandler);
|
||||
FirePageShowEvent(otherTreeItem, otherChromeEventHandler);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsIFrameFrame* ourFrameFrame = nsnull;
|
||||
CallQueryInterface(ourFrame, &ourFrameFrame);
|
||||
if (!ourFrameFrame) {
|
||||
mInSwap = aOther->mInSwap = PR_FALSE;
|
||||
FirePageShowEvent(ourTreeItem, ourChromeEventHandler);
|
||||
FirePageShowEvent(otherTreeItem, otherChromeEventHandler);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// OK. First begin to swap the docshells in the two nsIFrames
|
||||
rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
mInSwap = aOther->mInSwap = PR_FALSE;
|
||||
FirePageShowEvent(ourTreeItem, ourChromeEventHandler);
|
||||
FirePageShowEvent(otherTreeItem, otherChromeEventHandler);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Now move the docshells to the right docshell trees. Note that this
|
||||
// resets their treeowners to null.
|
||||
ourParentItem->RemoveChild(ourTreeItem);
|
||||
otherParentItem->RemoveChild(otherTreeItem);
|
||||
if (ourType == nsIDocShellTreeItem::typeContent) {
|
||||
ourOwner->ContentShellRemoved(ourTreeItem);
|
||||
otherOwner->ContentShellRemoved(otherTreeItem);
|
||||
}
|
||||
|
||||
ourParentItem->AddChild(otherTreeItem);
|
||||
otherParentItem->AddChild(ourTreeItem);
|
||||
|
||||
// Restore the correct treeowners
|
||||
SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourTreeItem, otherOwner,
|
||||
otherChromeEventHandler);
|
||||
SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherTreeItem, ourOwner,
|
||||
ourChromeEventHandler);
|
||||
|
||||
AddTreeItemToTreeOwner(ourTreeItem, otherContent, otherOwner,
|
||||
nsIDocShellTreeItem::typeChrome, nsnull);
|
||||
AddTreeItemToTreeOwner(otherTreeItem, ourContent, ourOwner,
|
||||
nsIDocShellTreeItem::typeChrome, nsnull);
|
||||
|
||||
// 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
|
||||
// kids before reinserting in the parent subdoc maps, to avoid
|
||||
// complications.
|
||||
ourParentDocument->SetSubDocumentFor(ourContent, nsnull);
|
||||
otherParentDocument->SetSubDocumentFor(otherContent, nsnull);
|
||||
ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument);
|
||||
otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
|
||||
|
||||
ourWindow->SetFrameElementInternal(otherFrameElement);
|
||||
otherWindow->SetFrameElementInternal(ourFrameElement);
|
||||
|
||||
mOwnerContent = otherContent;
|
||||
aOther->mOwnerContent = ourContent;
|
||||
|
||||
aFirstToSwap.swap(aSecondToSwap);
|
||||
|
||||
// We shouldn't have changed frames, but be really careful about it
|
||||
if (ourFrame == ourShell->GetPrimaryFrameFor(ourContent) &&
|
||||
otherFrame == otherShell->GetPrimaryFrameFor(otherContent)) {
|
||||
ourFrameFrame->EndSwapDocShells(otherFrame);
|
||||
}
|
||||
|
||||
ourParentDocument->FlushPendingNotifications(Flush_Layout);
|
||||
otherParentDocument->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
FirePageShowEvent(ourTreeItem, otherChromeEventHandler);
|
||||
FirePageShowEvent(otherTreeItem, ourChromeEventHandler);
|
||||
|
||||
mInSwap = aOther->mInSwap = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::Destroy()
|
||||
{
|
||||
@ -402,52 +770,13 @@ nsFrameLoader::EnsureDocShell()
|
||||
PRInt32 parentType;
|
||||
parentAsItem->GetItemType(&parentType);
|
||||
|
||||
nsAutoString value;
|
||||
PRBool isContent = PR_FALSE;
|
||||
|
||||
if (mOwnerContent->IsNodeOfType(nsINode::eXUL)) {
|
||||
mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
|
||||
}
|
||||
|
||||
// we accept "content" and "content-xxx" values.
|
||||
// at time of writing, we expect "xxx" to be "primary" or "targetable", but
|
||||
// someday it might be an integer expressing priority or something else.
|
||||
|
||||
isContent = value.LowerCaseEqualsLiteral("content") ||
|
||||
StringBeginsWith(value, NS_LITERAL_STRING("content-"),
|
||||
nsCaseInsensitiveStringComparator());
|
||||
|
||||
if (isContent) {
|
||||
// The web shell's type is content.
|
||||
|
||||
docShellAsItem->SetItemType(nsIDocShellTreeItem::typeContent);
|
||||
} else {
|
||||
// Inherit our type from our parent webshell. If it is
|
||||
// chrome, we'll be chrome. If it is content, we'll be
|
||||
// content.
|
||||
|
||||
docShellAsItem->SetItemType(parentType);
|
||||
}
|
||||
|
||||
parentAsNode->AddChild(docShellAsItem);
|
||||
|
||||
if (parentType == nsIDocShellTreeItem::typeChrome && isContent) {
|
||||
mIsTopLevelContent = PR_TRUE;
|
||||
|
||||
// XXXbz why is this in content code, exactly? We should handle
|
||||
// this some other way..... Not sure how yet.
|
||||
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
|
||||
parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
|
||||
|
||||
PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary");
|
||||
|
||||
if (parentTreeOwner) {
|
||||
PRBool is_targetable = is_primary ||
|
||||
value.LowerCaseEqualsLiteral("content-targetable");
|
||||
parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
|
||||
is_targetable, value);
|
||||
}
|
||||
}
|
||||
// XXXbz why is this in content code, exactly? We should handle
|
||||
// this some other way..... Not sure how yet.
|
||||
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
|
||||
parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
|
||||
mIsTopLevelContent =
|
||||
AddTreeItemToTreeOwner(docShellAsItem, mOwnerContent, parentTreeOwner,
|
||||
parentType, parentAsNode);
|
||||
|
||||
// Make sure all shells have links back to the content element
|
||||
// in the nearest enclosing chrome shell.
|
||||
|
@ -60,7 +60,8 @@ public:
|
||||
mDepthTooGreat(PR_FALSE),
|
||||
mIsTopLevelContent(PR_FALSE),
|
||||
mDestroyCalled(PR_FALSE),
|
||||
mInDestructor(PR_FALSE)
|
||||
mInDestructor(PR_FALSE),
|
||||
mInSwap(PR_FALSE)
|
||||
{}
|
||||
|
||||
~nsFrameLoader() {
|
||||
@ -75,6 +76,13 @@ public:
|
||||
nsresult ReallyStartLoading();
|
||||
void Finalize();
|
||||
nsIDocShell* GetExistingDocShell() { return mDocShell; }
|
||||
|
||||
// The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation. A
|
||||
// frame loader owner needs to call this, and pass in the two references to
|
||||
// nsRefPtrs for frame loaders that need to be swapped.
|
||||
nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
nsRefPtr<nsFrameLoader>& aFirstToSwap,
|
||||
nsRefPtr<nsFrameLoader>& aSecondToSwap);
|
||||
private:
|
||||
|
||||
NS_HIDDEN_(nsresult) EnsureDocShell();
|
||||
@ -84,10 +92,11 @@ private:
|
||||
nsCOMPtr<nsIDocShell> mDocShell;
|
||||
nsCOMPtr<nsIURI> mURIToLoad;
|
||||
nsIContent *mOwnerContent; // WEAK
|
||||
PRPackedBool mDepthTooGreat;
|
||||
PRPackedBool mIsTopLevelContent;
|
||||
PRPackedBool mDestroyCalled;
|
||||
PRPackedBool mInDestructor;
|
||||
PRPackedBool mDepthTooGreat : 1;
|
||||
PRPackedBool mIsTopLevelContent : 1;
|
||||
PRPackedBool mDestroyCalled : 1;
|
||||
PRPackedBool mInDestructor : 1;
|
||||
PRPackedBool mInSwap : 1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -670,6 +670,12 @@ nsObjectLoadingContent::GetFrameLoader(nsIFrameLoader** aFrameLoader)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoader)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// nsIObjectLoadingContent
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::GetActualType(nsACString& aType)
|
||||
|
@ -3001,6 +3001,13 @@ nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
|
||||
{
|
||||
// We don't support this yet
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGenericHTMLFrameElement::LoadSrc()
|
||||
{
|
||||
|
@ -167,8 +167,6 @@
|
||||
#define XUL_ELEMENT_CONTAINER_CONTENTS_BUILT \
|
||||
(nsXULElement::eContainerContentsBuilt << XUL_ELEMENT_LAZY_STATE_OFFSET)
|
||||
|
||||
class nsIDocShell;
|
||||
|
||||
// Global object maintenance
|
||||
nsICSSParser* nsXULPrototypeElement::sCSSParser = nsnull;
|
||||
nsIXBLService * nsXULElement::gXBLService = nsnull;
|
||||
@ -2118,6 +2116,36 @@ nsXULElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
|
||||
{
|
||||
nsCOMPtr<nsIContent> otherContent(do_QueryInterface(aOtherOwner));
|
||||
NS_ENSURE_TRUE(otherContent, NS_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
nsXULElement* otherEl = FromContent(otherContent);
|
||||
NS_ENSURE_TRUE(otherEl, NS_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
if (otherEl == this) {
|
||||
// nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsXULSlots *ourSlots = static_cast<nsXULSlots*>(GetExistingDOMSlots());
|
||||
nsXULSlots *otherSlots =
|
||||
static_cast<nsXULSlots*>(otherEl->GetExistingDOMSlots());
|
||||
if (!ourSlots || !ourSlots->mFrameLoader ||
|
||||
!otherSlots || !otherSlots->mFrameLoader) {
|
||||
// Can't handle swapping when there is nothing to swap... yet.
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return
|
||||
ourSlots->mFrameLoader->SwapWithOtherLoader(otherSlots->mFrameLoader,
|
||||
ourSlots->mFrameLoader,
|
||||
otherSlots->mFrameLoader);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULElement::GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement)
|
||||
{
|
||||
|
@ -625,8 +625,8 @@ public:
|
||||
|
||||
nsresult GetStyle(nsIDOMCSSStyleDeclaration** aStyle);
|
||||
|
||||
|
||||
nsresult GetFrameLoader(nsIFrameLoader** aFrameLoader);
|
||||
nsresult SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner);
|
||||
|
||||
virtual void RecompileScriptEventListeners();
|
||||
|
||||
@ -664,7 +664,7 @@ protected:
|
||||
nsXULSlots(PtrBits aFlags);
|
||||
virtual ~nsXULSlots();
|
||||
|
||||
nsCOMPtr<nsIFrameLoader> mFrameLoader;
|
||||
nsRefPtr<nsFrameLoader> mFrameLoader;
|
||||
};
|
||||
|
||||
virtual nsINode::nsSlots* CreateSlots();
|
||||
|
@ -1190,12 +1190,10 @@ nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
|
||||
// Weak reference. Don't addref.
|
||||
mChromeEventHandler = piTarget;
|
||||
|
||||
NS_ASSERTION(!mScriptGlobal,
|
||||
"SetChromeEventHandler() called after the script global "
|
||||
"object was created! This means that the script global "
|
||||
"object in this docshell won't get the right chrome event "
|
||||
"handler. You really don't want to see this assert, FIX "
|
||||
"YOUR CODE!");
|
||||
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
|
||||
if (win) {
|
||||
win->SetChromeEventHandler(piTarget);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -96,6 +96,8 @@ public:
|
||||
return mChromeEventHandler;
|
||||
}
|
||||
|
||||
virtual void SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler) = 0;
|
||||
|
||||
PRBool HasMutationListeners(PRUint32 aMutationEventType) const
|
||||
{
|
||||
const nsPIDOMWindow *win;
|
||||
@ -401,6 +403,10 @@ protected:
|
||||
{
|
||||
}
|
||||
|
||||
void SetChromeEventHandlerInternal(nsPIDOMEventTarget* aChromeEventHandler) {
|
||||
mChromeEventHandler = aChromeEventHandler;
|
||||
}
|
||||
|
||||
// These two variables are special in that they're set to the same
|
||||
// value on both the outer window and the current inner window. Make
|
||||
// sure you keep them in sync!
|
||||
|
@ -6810,6 +6810,27 @@ nsGlobalWindow::Deactivate()
|
||||
return FireWidgetEvent(mDocShell, NS_DEACTIVATE);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler)
|
||||
{
|
||||
SetChromeEventHandlerInternal(aChromeEventHandler);
|
||||
if (IsOuterWindow()) {
|
||||
// update the chrome event handler on all our inner windows
|
||||
for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
|
||||
inner != this;
|
||||
inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
|
||||
NS_ASSERTION(inner->mOuterWindow == this, "bad outer window pointer");
|
||||
inner->SetChromeEventHandlerInternal(aChromeEventHandler);
|
||||
}
|
||||
} else if (mOuterWindow) {
|
||||
// Need the cast to be able to call the protected method on a
|
||||
// superclass. We could make the method public instead, but it's really
|
||||
// better this way.
|
||||
static_cast<nsGlobalWindow*>(mOuterWindow)->
|
||||
SetChromeEventHandlerInternal(aChromeEventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
nsIFocusController*
|
||||
nsGlobalWindow::GetRootFocusController()
|
||||
{
|
||||
|
@ -290,6 +290,7 @@ public:
|
||||
virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
|
||||
virtual NS_HIDDEN_(nsresult) Activate();
|
||||
virtual NS_HIDDEN_(nsresult) Deactivate();
|
||||
virtual NS_HIDDEN_(void) SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler);
|
||||
virtual NS_HIDDEN_(nsIFocusController*) GetRootFocusController();
|
||||
|
||||
virtual NS_HIDDEN_(void) SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal);
|
||||
|
@ -181,6 +181,8 @@ public:
|
||||
|
||||
// nsIFrameFrame
|
||||
NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
|
||||
NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther);
|
||||
virtual void EndSwapDocShells(nsIFrame* aOther);
|
||||
|
||||
NS_IMETHOD VerifyTree() const;
|
||||
|
||||
@ -199,6 +201,10 @@ protected:
|
||||
|
||||
virtual PRIntn GetSkipSides() const;
|
||||
|
||||
// Hide or show our document viewer
|
||||
void HideViewer();
|
||||
void ShowViewer();
|
||||
|
||||
/* Obtains the frame we should use for intrinsic size information if we are
|
||||
* an HTML <object>, <embed> or <applet> (a replaced element - not <iframe>)
|
||||
* and our sub-document has an intrinsic size. The frame returned is the
|
||||
@ -303,18 +309,27 @@ nsSubDocumentFrame::Init(nsIContent* aContent,
|
||||
view->CreateWidget(kCChildCID);
|
||||
}
|
||||
|
||||
if (!aPresContext->IsDynamic()) {
|
||||
ShowViewer();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSubDocumentFrame::ShowViewer()
|
||||
{
|
||||
if (!PresContext()->IsDynamic()) {
|
||||
// We let the printing code take care of loading the document; just
|
||||
// create a widget for it to use
|
||||
rv = CreateViewAndWidget(eContentTypeContent);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
nsresult rv = CreateViewAndWidget(eContentTypeContent);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
rv = ShowDocShell();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
nsresult rv = ShowDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
mDidCreateDoc = PR_TRUE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRIntn
|
||||
@ -745,6 +760,14 @@ nsSubDocumentFrame::Destroy()
|
||||
mPostedReflowCallback = PR_FALSE;
|
||||
}
|
||||
|
||||
HideViewer();
|
||||
|
||||
nsLeafFrame::Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
nsSubDocumentFrame::HideViewer()
|
||||
{
|
||||
if (mFrameLoader && mDidCreateDoc) {
|
||||
// Get the content viewer through the docshell, but don't call
|
||||
// GetDocShell() since we don't want to create one if we don't
|
||||
@ -774,12 +797,10 @@ nsSubDocumentFrame::Destroy()
|
||||
// Hide the content viewer now that the frame is going away...
|
||||
baseWin->SetVisibility(PR_FALSE);
|
||||
|
||||
// Clear out the parentWidget, since it's about to die with us
|
||||
// Clear out the parentWidget, since it might be about to die with us
|
||||
baseWin->SetParentWidget(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
nsLeafFrame::Destroy();
|
||||
}
|
||||
|
||||
nsSize nsSubDocumentFrame::GetMargin()
|
||||
@ -824,6 +845,46 @@ nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
|
||||
return mFrameLoader->GetDocShell(aDocShell);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
|
||||
{
|
||||
if (!aOther || aOther->GetType() != nsGkAtoms::subDocumentFrame) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
|
||||
if (!mFrameLoader || !mDidCreateDoc || !other->mFrameLoader ||
|
||||
!other->mDidCreateDoc) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
HideViewer();
|
||||
other->HideViewer();
|
||||
|
||||
mFrameLoader.swap(other->mFrameLoader);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
|
||||
{
|
||||
nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
|
||||
ShowViewer();
|
||||
other->ShowViewer();
|
||||
|
||||
// Now make sure we reflow both frames, in case their contents
|
||||
// determine their size.
|
||||
PresContext()->PresShell()->
|
||||
FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
|
||||
other->PresContext()->PresShell()->
|
||||
FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
|
||||
|
||||
// And repaint them, for good measure, in case there's nothing
|
||||
// interesting that happens during reflow.
|
||||
InvalidateOverflowRect();
|
||||
other->InvalidateOverflowRect();
|
||||
}
|
||||
|
||||
inline PRInt32 ConvertOverflow(PRUint8 aOverflow)
|
||||
{
|
||||
switch (aOverflow) {
|
||||
@ -935,6 +996,11 @@ nsSubDocumentFrame::ShowDocShell()
|
||||
nsresult
|
||||
nsSubDocumentFrame::CreateViewAndWidget(nsContentType aContentType)
|
||||
{
|
||||
if (mInnerView) {
|
||||
// Nothing to do here
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// create, init, set the parent of the view
|
||||
nsIView* outerView = GetView();
|
||||
NS_ASSERTION(outerView, "Must have an outer view already");
|
||||
|
@ -46,8 +46,8 @@
|
||||
class nsIDocShell;
|
||||
|
||||
#define NS_IFRAMEFRAME_IID \
|
||||
{ 0xda876f25, 0x1cff, 0x4f0a, { \
|
||||
0xbf, 0x7e, 0x83, 0xd7, 0x4f, 0xc5, 0x2a, 0x3b } }
|
||||
{ 0x22e34108, 0xc24b, 0x40ea, { \
|
||||
0xb9, 0x79, 0x50, 0x18, 0x38, 0x8d, 0xd5, 0x88 } }
|
||||
|
||||
class nsIFrameFrame : public nsISupports
|
||||
{
|
||||
@ -55,6 +55,14 @@ public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFRAMEFRAME_IID)
|
||||
|
||||
NS_IMETHOD GetDocShell(nsIDocShell **aDocShell) = 0;
|
||||
|
||||
/**
|
||||
* Only allowed to fail if the other frame is not the same type as
|
||||
* this one or if one of the frames has no docshell. Don't call
|
||||
* EndSwapDocShells() unless BeginSwapDocShells() succeeds.
|
||||
*/
|
||||
NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther) = 0;
|
||||
virtual void EndSwapDocShells(nsIFrame* aOther) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIFrameFrame, NS_IFRAMEFRAME_IID)
|
||||
|
@ -957,6 +957,39 @@
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="swapDocShells">
|
||||
<parameter name="aOtherBrowser"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// We need to swap fields that are tied to our docshell
|
||||
var fieldsToSwap = [ "_docShell", "_webBrowserFind" ];
|
||||
|
||||
var ourTabBrowser = this.getTabBrowser();
|
||||
|
||||
// _fastFind is tied to the docshell if we don't have a tabbrowser
|
||||
if ((ourTabBrowser != null) !=
|
||||
(aOtherBrowser.getTabBrowser() != null))
|
||||
throw "Unable to perform swap on <browsers> if one is in a <tabbrowser> and one is not";
|
||||
|
||||
if (!ourTabBrowser)
|
||||
fieldsToSwap.push("_fastFind");
|
||||
|
||||
var ourFieldValues = {};
|
||||
var otherFieldValues = {};
|
||||
for each (var field in fieldsToSwap) {
|
||||
ourFieldValues[field] = this[field];
|
||||
otherFieldValues[field] = aOtherBrowser[field];
|
||||
}
|
||||
this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner)
|
||||
.swapFrameLoaders(aOtherBrowser);
|
||||
for each (var field in fieldsToSwap) {
|
||||
this[field] = otherFieldValues[field];
|
||||
aOtherBrowser[field] = ourFieldValues[field];
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
|
Loading…
Reference in New Issue
Block a user