Index: Source/WebCore/loader/FrameLoader.cpp |
=================================================================== |
--- Source/WebCore/loader/FrameLoader.cpp (revision 93735) |
+++ Source/WebCore/loader/FrameLoader.cpp (working copy) |
@@ -367,7 +367,7 @@ |
Node* currentFocusedNode = m_frame->document()->focusedNode(); |
if (currentFocusedNode) |
currentFocusedNode->aboutToUnload(); |
- if (m_frame->domWindow()) { |
+ if (m_frame->domWindow() && m_pageDismissalEventBeingDispatched == NoDismissal) { |
if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) { |
m_pageDismissalEventBeingDispatched = PageHideDismissal; |
m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document()); |
@@ -1678,6 +1678,20 @@ |
m_documentLoader->detachFromFrame(); |
m_documentLoader = loader; |
+ |
+ // The following abomination is brought to you by the unload event. |
+ // The detachChildren() call above may trigger a child frame's unload event, |
+ // which could do something obnoxious like call document.write("") on |
+ // the main frame, which results in detaching children while detaching children. |
+ // This can cause the new m_documentLoader to be detached from its Frame*, but still |
+ // be alive. To make matters worse, DocumentLoaders with a null Frame* aren't supposed |
+ // to happen when they're still alive (and many places below us on the stack think the |
+ // DocumentLoader is still usable). Ergo, we reattach loader to its Frame, and pretend |
+ // like nothing ever happened. |
+ if (m_documentLoader && !m_documentLoader->frame()) { |
+ ASSERT(!m_documentLoader->isLoading()); |
+ m_documentLoader->setFrame(m_frame); |
+ } |
} |
void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader) |
@@ -2348,12 +2362,14 @@ |
void FrameLoader::detachChildren() |
{ |
- // FIXME: Is it really necessary to do this in reverse order? |
- Frame* previous; |
- for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) { |
- previous = child->tree()->previousSibling(); |
- child->loader()->detachFromParent(); |
- } |
+ typedef Vector<RefPtr<Frame> > FrameVector; |
+ FrameVector childrenToDetach; |
+ childrenToDetach.reserveCapacity(m_frame->tree()->childCount()); |
+ for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) |
+ childrenToDetach.append(child); |
+ FrameVector::iterator end = childrenToDetach.end(); |
+ for (FrameVector::iterator it = childrenToDetach.begin(); it != end; it++) |
+ (*it)->loader()->detachFromParent(); |
} |
void FrameLoader::closeAndRemoveChild(Frame* child) |