Bug 549682 - Port the message-manager API to mozilla-central, r=jst
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Tue, 18 May 2010 11:52:24 +0300
changeset 42410 b62ac40565f28cd4e77d8d6d380b45628da11c37
parent 42409 41e6a1ad820d55043f9f8132b3e30f91dd1add9b
child 42411 5127e4bfa12768f67bc2823cc216e4af4e8263dc
push id13324
push useropettay@mozilla.com
push dateTue, 18 May 2010 09:03:14 +0000
treeherdermozilla-central@b62ac40565f2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs549682
milestone1.9.3a5pre
first release with
nightly linux32
b62ac40565f2 / 3.7a5pre / 20100518030131 / files
nightly linux64
b62ac40565f2 / 3.7a5pre / 20100518030710 / files
nightly mac
b62ac40565f2 / 3.7a5pre / 20100518030645 / files
nightly win32
b62ac40565f2 / 3.7a5pre / 20100518035958 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 549682 - Port the message-manager API to mozilla-central, r=jst
caps/src/nsScriptSecurityManager.cpp
content/base/public/Makefile.in
content/base/public/nsContentUtils.h
content/base/public/nsIFrameLoader.idl
content/base/public/nsIFrameMessageManager.idl
content/base/src/Makefile.in
content/base/src/nsContentUtils.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
content/base/src/nsInProcessTabChildGlobal.cpp
content/base/src/nsInProcessTabChildGlobal.h
content/base/src/nsScriptLoader.cpp
content/base/test/chrome/Makefile.in
content/base/test/chrome/file_bug549682.xul
content/base/test/chrome/test_bug549682.xul
content/events/public/nsPIDOMEventTarget.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsDOMJSUtils.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIScriptContext.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
dom/interfaces/base/nsIDOMChromeWindow.idl
js/src/xpconnect/src/xpcthreadcontext.cpp
layout/base/nsPresContext.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2130,25 +2130,25 @@ nsScriptSecurityManager::GetCodebasePrin
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetPrincipalFromContext(JSContext *cx,
                                                  nsIPrincipal **result)
 {
     *result = nsnull;
 
-    nsIScriptContext *scriptContext = GetScriptContext(cx);
-
-    if (!scriptContext)
+    nsIScriptContextPrincipal* scp =
+        GetScriptContextPrincipalFromJSContext(cx);
+
+    if (!scp)
     {
         return NS_ERROR_FAILURE;
     }
 
-    nsCOMPtr<nsIScriptObjectPrincipal> globalData =
-        do_QueryInterface(scriptContext->GetGlobalObject());
+    nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
     if (globalData)
         NS_IF_ADDREF(*result = globalData->GetPrincipal());
 
     return NS_OK;
 }
 
 // static
 nsIPrincipal*
@@ -2323,21 +2323,21 @@ nsScriptSecurityManager::GetPrincipalAnd
             {
                 JSStackFrame *inner = nsnull;
                 *frameResult = JS_FrameIterator(cx, &inner);
             }
 
             return targetPrincipal;
         }
 
-        nsIScriptContext *scriptContext = GetScriptContext(cx);
-        if (scriptContext)
+        nsIScriptContextPrincipal* scp =
+            GetScriptContextPrincipalFromJSContext(cx);
+        if (scp)
         {
-            nsCOMPtr<nsIScriptObjectPrincipal> globalData =
-                do_QueryInterface(scriptContext->GetGlobalObject());
+            nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
             if (!globalData)
             {
                 *rv = NS_ERROR_FAILURE;
                 return nsnull;
             }
 
             // Note that we're not in a loop or anything, and nothing comes
             // after this point in the function, so we can just return here.
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -117,12 +117,13 @@ XPIDLSRCS	= \
 		nsIDroppedLinkHandler.idl \
 		nsIScriptEventHandler.idl \
 		nsIScriptEventManager.idl \
 		nsIImageLoadingContent.idl \
 		nsIObjectLoadingContent.idl \
 		nsIFrameLoader.idl \
 		nsIXMLHttpRequest.idl \
 		nsIContentSecurityPolicy.idl \
+		nsIFrameMessageManager.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1716,17 +1716,17 @@ public:
 
   // Returns PR_FALSE if something erroneous happened.
   PRBool Push(nsPIDOMEventTarget *aCurrentTarget);
   // If nothing has been pushed to stack, this works like Push.
   // Otherwise if context will change, Pop and Push will be called.
   PRBool RePush(nsPIDOMEventTarget *aCurrentTarget);
   // If a null JSContext is passed to Push(), that will cause no
   // push to happen and false to be returned.
-  PRBool Push(JSContext *cx);
+  PRBool Push(JSContext *cx, PRBool aRequiresScriptContext = PR_TRUE);
   // Explicitly push a null JSContext on the the stack
   PRBool PushNull();
 
   // Pop() will be a no-op if Push() or PushNull() fail
   void Pop();
 
   nsIScriptContext* GetCurrentScriptContext() { return mScx; }
 private:
--- a/content/base/public/nsIFrameLoader.idl
+++ b/content/base/public/nsIFrameLoader.idl
@@ -36,18 +36,19 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIDocShell;
 interface nsIURI;
+interface nsIChromeFrameMessageManager;
 
-[scriptable, uuid(d675c531-6bdc-417c-b176-635060105f07)]
+[scriptable, uuid(3b256c12-20e1-4fd3-8edb-b9c793919f15)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -69,16 +70,19 @@ interface nsIFrameLoader : nsISupports
   void destroy();
 
   /**
    * Find out whether the loader's frame is at too great a depth in
    * the frame tree.  This can be used to decide what operations may
    * or may not be allowed on the loader's docshell.
    */
   readonly attribute boolean depthTooGreat;
+
+  // Note, when frameloaders are swapped, also messageManagers are swapped.
+  readonly attribute nsIChromeFrameMessageManager messageManager;
 };
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
 [scriptable, uuid(8f3b12a0-35ae-4e0d-9152-8e0d7e49d446)]
 interface nsIFrameLoaderOwner : nsISupports
 {
   /**
new file mode 100644
--- /dev/null
+++ b/content/base/public/nsIFrameMessageManager.idl
@@ -0,0 +1,119 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIDOMWindow;
+interface nsIDocShell;
+interface nsIContent;
+
+[scriptable, function, uuid(938fcb95-3d63-46be-aa72-94d08fd3b418)]
+interface nsIFrameMessageListener : nsISupports
+{
+  /**
+   * This is for JS only.
+   * receiveMessage is called with one parameter, which has the following
+   * properties:
+   *   {
+   *     name:    %message name%,
+   *     sync:    %true or false%.
+   *     json:    %json object or null%,
+   *     objects: %array of cpow or null, always null if sync is false%
+   *   }
+   * @note objects property isn't implemented yet.
+   *
+   * if the message is synchronous, possible return value is sent back
+   * as JSON.
+   *
+   * When the listener is called, 'this' value is the target of the message.
+   */
+  void receiveMessage();
+};
+
+[scriptable, uuid(6b736edb-863d-40bd-bca2-62f44da803c0)]
+interface nsIFrameMessageManager : nsISupports
+{
+  void addMessageListener(in AString aMessage, in nsIFrameMessageListener aListener);
+  void removeMessageListener(in AString aMessage, in nsIFrameMessageListener aListener);
+  void sendAsyncMessage(/*in messageName, in JSON*/);
+};
+
+[scriptable, uuid(c56e85b8-6736-4ae2-ae90-66bcef952a82)]
+interface nsIContentFrameMessageManager : nsIFrameMessageManager
+{
+  /**
+   * @note sending JS objects isn't implemented yet.
+   *
+   * Returns an array of JSON objects.
+   */
+  void sendSyncMessage(/*in messageName, in JSON, in an array of JS objects,*/);
+
+  /**
+   * The current top level window in the frame or null.
+   */
+  readonly attribute nsIDOMWindow content;
+
+  /**
+   * The top level docshell or null.
+   */
+  readonly attribute nsIDocShell docShell;
+
+  /**
+   * Print a string to stdout.
+   */
+  void dump(in DOMString aStr);
+};
+
+[uuid(9c48d557-92fe-4edb-95fc-bfe97e77bdc3)]
+interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
+{
+  [notxpcom] nsIContent getOwnerContent();
+};
+
+[scriptable, uuid(ed6522fd-ffb6-4920-b50d-cf629309616b)]
+interface nsIChromeFrameMessageManager : nsIFrameMessageManager
+{
+  /*
+   * Load a script in the (remote) frame. aURL must be the absolute URL.
+   * data: URLs are also supported. For example data:,dump("foo\n");
+   * If aAllowDelayedLoad is true, script will be loaded when the
+   * remote frame becomes available. Otherwise the script will be loaded
+   * only if the frame is already available.
+   */
+  void loadFrameScript(in AString aURL, in boolean aAllowDelayedLoad);
+};
+
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -139,16 +139,18 @@ CPPSRCS		= \
 		nsTraversal.cpp \
 		nsTreeWalker.cpp \
 		nsXHTMLContentSerializer.cpp \
 		nsXMLContentSerializer.cpp \
 		nsXMLHttpRequest.cpp \
 		nsXMLNameSpaceMap.cpp \
 		Link.cpp \
 		nsFileDataProtocolHandler.cpp \
+		nsFrameMessageManager.cpp \
+		nsInProcessTabChildGlobal.cpp \
 		$(NULL)
 
 GQI_SRCS = contentbase.gqi
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -2694,16 +2694,22 @@ nsCxPusher::Push(nsPIDOMEventTarget *aCu
 
   NS_ENSURE_TRUE(aCurrentTarget, PR_FALSE);
   nsresult rv;
   nsIScriptContext* scx =
     aCurrentTarget->GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
   if (!scx) {
+    // The target may have a special JS context for event handlers.
+    JSContext* cx = aCurrentTarget->GetJSContextForEventHandlers();
+    if (cx) {
+      DoPush(cx);
+    }
+
     // Nothing to do here, I guess.  Have to return true so that event firing
     // will still work correctly even if there is no associated JSContext
     return PR_TRUE;
   }
 
   JSContext* cx = nsnull;
 
   if (scx) {
@@ -2743,33 +2749,33 @@ nsCxPusher::RePush(nsPIDOMEventTarget *a
     }
   }
 
   Pop();
   return Push(aCurrentTarget);
 }
 
 PRBool
-nsCxPusher::Push(JSContext *cx)
+nsCxPusher::Push(JSContext *cx, PRBool aRequiresScriptContext)
 {
   if (mPushedSomething) {
     NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
 
     return PR_FALSE;
   }
 
   if (!cx) {
     return PR_FALSE;
   }
 
   // Hold a strong ref to the nsIScriptContext, just in case
   // XXXbz do we really need to?  If we don't get one of these in Pop(), is
   // that really a problem?  Or do we need to do this to effectively root |cx|?
   mScx = GetScriptContextFromJSContext(cx);
-  if (!mScx) {
+  if (!mScx && aRequiresScriptContext) {
     // Should probably return PR_FALSE. See bug 416916.
     return PR_TRUE;
   }
 
   return DoPush(cx);
 }
 
 PRBool
@@ -3183,24 +3189,32 @@ nsContentUtils::DispatchChromeEvent(nsID
   nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
                                   aCancelable, getter_AddRefs(event),
                                   getter_AddRefs(target));
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(aDoc, "GetEventAndTarget lied?");
   if (!aDoc->GetWindow())
     return NS_ERROR_INVALID_ARG;
-  if (!aDoc->GetWindow()->GetChromeEventHandler())
+
+  nsPIDOMEventTarget* piTarget = aDoc->GetWindow()->GetChromeEventHandler();
+  if (!target)
     return NS_ERROR_INVALID_ARG;
 
+  nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(piTarget);
+  if (flo) {
+    nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
+    if (fl) {
+      nsPIDOMEventTarget* t = fl->GetTabChildGlobalAsEventTarget();
+      piTarget = t ? t : piTarget;
+    }
+  }
+
   nsEventStatus status = nsEventStatus_eIgnore;
-  rv = aDoc->GetWindow()->GetChromeEventHandler()->DispatchDOMEvent(nsnull,
-                                                                    event,
-                                                                    nsnull,
-                                                                    &status);
+  rv = piTarget->DispatchDOMEvent(nsnull, event, nsnull, &status);
   if (aDefaultAction) {
     *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
   }
   return rv;
 }
 
 /* static */
 Element*
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -82,16 +82,18 @@
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 
 #include "nsGkAtoms.h"
 #include "nsINameSpaceManager.h"
 
 #include "nsThreadUtils.h"
 #include "nsIContentViewer.h"
+#include "nsIDOMChromeWindow.h"
+#include "nsInProcessTabChildGlobal.h"
 
 class nsAsyncDocShellDestroyer : public nsRunnable
 {
 public:
   nsAsyncDocShellDestroyer(nsIDocShell* aDocShell)
     : mDocShell(aDocShell)
   {
   }
@@ -119,17 +121,30 @@ public:
 // does not count chrome frames when determining depth, nor does it
 // prevent chrome recursion.  Number is fairly arbitrary, but meant to
 // keep number of shells to a reasonable number on accidental recursion with a
 // small (but not 1) branching factor.  With large branching factors the number
 // of shells can rapidly become huge and run us out of memory.  To solve that,
 // we'd need to re-institute a fixed version of bug 98158.
 #define MAX_DEPTH_CONTENT_FRAMES 10
 
-NS_IMPL_CYCLE_COLLECTION_1(nsFrameLoader, mDocShell)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameLoader)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameLoader)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocShell)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMessageManager)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChildMessageManager)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameLoader)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocShell)
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsFrameLoader::mMessageManager");
+  cb.NoteXPCOMChild(static_cast<nsIContentFrameMessageManager*>(tmp->mMessageManager.get()));
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChildMessageManager)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
@@ -826,16 +841,48 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
 
   ourWindow->SetFrameElementInternal(otherFrameElement);
   otherWindow->SetFrameElementInternal(ourFrameElement);
 
   mOwnerContent = otherContent;
   aOther->mOwnerContent = ourContent;
 
+  nsRefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
+  nsRefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
+  // Swap pointers in child message managers.
+  if (mChildMessageManager) {
+    nsInProcessTabChildGlobal* tabChild =
+      static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
+    tabChild->SetOwner(otherContent);
+    tabChild->SetChromeMessageManager(otherMessageManager);
+  }
+  if (aOther->mChildMessageManager) {
+    nsInProcessTabChildGlobal* otherTabChild =
+      static_cast<nsInProcessTabChildGlobal*>(aOther->mChildMessageManager.get());
+    otherTabChild->SetOwner(ourContent);
+    otherTabChild->SetChromeMessageManager(ourMessageManager);
+  }
+  // Swap and setup things in parent message managers.
+  nsFrameMessageManager* ourParentManager = mMessageManager ?
+    mMessageManager->GetParentManager() : nsnull;
+  nsFrameMessageManager* otherParentManager = aOther->mMessageManager ?
+    aOther->mMessageManager->GetParentManager() : nsnull;
+  if (mMessageManager) {
+    mMessageManager->Disconnect();
+    mMessageManager->SetParentManager(otherParentManager);
+    mMessageManager->SetCallbackData(aOther, PR_FALSE);
+  }
+  if (aOther->mMessageManager) {
+    aOther->mMessageManager->Disconnect();
+    aOther->mMessageManager->SetParentManager(ourParentManager);
+    aOther->mMessageManager->SetCallbackData(this, PR_FALSE);
+  }
+  mMessageManager.swap(aOther->mMessageManager);
+
   aFirstToSwap.swap(aSecondToSwap);
 
   // Drop any cached content viewers in the two session histories.
   nsCOMPtr<nsISHistoryInternal> ourInternalHistory =
     do_QueryInterface(ourHistory);
   nsCOMPtr<nsISHistoryInternal> otherInternalHistory =
     do_QueryInterface(otherHistory);
   if (ourInternalHistory) {
@@ -864,16 +911,23 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
 NS_IMETHODIMP
 nsFrameLoader::Destroy()
 {
   if (mDestroyCalled) {
     return NS_OK;
   }
   mDestroyCalled = PR_TRUE;
 
+  if (mMessageManager) {
+    mMessageManager->Disconnect();
+  }
+  if (mChildMessageManager) {
+    static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
+  }
+
   nsCOMPtr<nsIDocument> doc;
   if (mOwnerContent) {
     doc = mOwnerContent->GetOwnerDoc();
 
     if (doc) {
       doc->SetSubDocumentFor(mOwnerContent, nsnull);
     }
 
@@ -1014,16 +1068,18 @@ nsFrameLoader::EnsureDocShell()
       // handler from it and use that for our shell as well.
 
       parentShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
     }
 
     mDocShell->SetChromeEventHandler(chromeEventHandler);
   }
 
+  EnsureMessageManager();
+
   // This is nasty, this code (the do_GetInterface(mDocShell) below)
   // *must* come *after* the above call to
   // mDocShell->SetChromeEventHandler() for the global window to get
   // the right chrome event handler.
 
   // Tell the window about the frame that hosts it.
   nsCOMPtr<nsIDOMElement> frame_element(do_QueryInterface(mOwnerContent));
   NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
@@ -1168,8 +1224,106 @@ nsFrameLoader::CreateStaticClone(nsIFram
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
   NS_ENSURE_STATE(doc);
   nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell);
   nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc);
 
   viewer->SetDOMDocument(clonedDOMDoc);
   return NS_OK;
 }
+
+bool LoadScript(void* aCallbackData, const nsAString& aURL)
+{
+  nsFrameLoader* fl = static_cast<nsFrameLoader*>(aCallbackData);
+  nsRefPtr<nsInProcessTabChildGlobal> tabChild =
+    static_cast<nsInProcessTabChildGlobal*>(fl->GetTabChildGlobalAsEventTarget());
+  if (tabChild) {
+    tabChild->LoadFrameScript(aURL);
+  }
+  return true;
+}
+
+class nsAsyncMessageToChild : public nsRunnable
+{
+public:
+  nsAsyncMessageToChild(nsFrameLoader* aFrameLoader,
+                        const nsAString& aMessage, const nsAString& aJSON)
+    : mFrameLoader(aFrameLoader), mMessage(aMessage), mJSON(aJSON) {}
+
+  NS_IMETHOD Run()
+  {
+    nsInProcessTabChildGlobal* tabChild =
+      static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
+    if (tabChild && tabChild->GetInnerManager()) {
+      tabChild->GetInnerManager()->
+        ReceiveMessage(static_cast<nsPIDOMEventTarget*>(tabChild), mMessage,
+                       PR_FALSE, mJSON, nsnull, nsnull);
+    }
+    return NS_OK;
+  }
+  nsRefPtr<nsFrameLoader> mFrameLoader;
+  nsString mMessage;
+  nsString mJSON;
+};
+
+bool SendAsyncMessageToChild(void* aCallbackData,
+                             const nsAString& aMessage,
+                             const nsAString& aJSON)
+{
+  nsRefPtr<nsIRunnable> ev =
+    new nsAsyncMessageToChild(static_cast<nsFrameLoader*>(aCallbackData),
+                              aMessage, aJSON);
+  NS_DispatchToCurrentThread(ev);
+  return true;
+}
+
+NS_IMETHODIMP
+nsFrameLoader::GetMessageManager(nsIChromeFrameMessageManager** aManager)
+{
+  NS_IF_ADDREF(*aManager = mMessageManager);
+  return NS_OK;
+}
+
+nsresult
+nsFrameLoader::EnsureMessageManager()
+{
+  NS_ENSURE_STATE(mOwnerContent);
+  //XXX Should we create message manager also for chrome iframes?
+  if (!mIsTopLevelContent) {
+    return NS_OK;
+  }
+
+  EnsureDocShell();
+  if (mMessageManager) {
+    return NS_OK;
+  }
+
+  nsresult rv = NS_OK;
+  nsIScriptContext* sctx = mOwnerContent->GetContextForEventHandlers(&rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_STATE(sctx);
+  JSContext* cx = static_cast<JSContext*>(sctx->GetNativeContext());
+  NS_ENSURE_STATE(cx);
+
+  nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
+    do_QueryInterface(mOwnerContent->GetOwnerDoc()->GetWindow());
+  NS_ENSURE_STATE(chromeWindow);
+  nsCOMPtr<nsIChromeFrameMessageManager> parentManager;
+  chromeWindow->GetMessageManager(getter_AddRefs(parentManager));
+
+  mMessageManager = new nsFrameMessageManager(PR_TRUE,
+                                              nsnull,
+                                              SendAsyncMessageToChild,
+                                              LoadScript,
+                                              this,
+                                              static_cast<nsFrameMessageManager*>(parentManager.get()),
+                                              cx);
+  NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
+  mChildMessageManager =
+    new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
+  return NS_OK;
+}
+
+nsPIDOMEventTarget*
+nsFrameLoader::GetTabChildGlobalAsEventTarget()
+{
+  return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
+}
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -43,20 +43,22 @@
 
 #ifndef nsFrameLoader_h_
 #define nsFrameLoader_h_
 
 #include "nsIDocShell.h"
 #include "nsStringFwd.h"
 #include "nsIFrameLoader.h"
 #include "nsIURI.h"
+#include "nsFrameMessageManager.h"
 
 class nsIContent;
 class nsIURI;
 class nsIFrameFrame;
+class nsIInProcessContentFrameMessageManager;
 
 class nsFrameLoader : public nsIFrameLoader
 {
 protected:
   nsFrameLoader(nsIContent *aOwner) :
     mOwnerContent(aOwner),
     mDepthTooGreat(PR_FALSE),
     mIsTopLevelContent(PR_FALSE),
@@ -75,17 +77,17 @@ public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsFrameLoader)
   NS_DECL_NSIFRAMELOADER
   NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI);
   nsresult ReallyStartLoading();
   void Finalize();
   nsIDocShell* GetExistingDocShell() { return mDocShell; }
-
+  nsPIDOMEventTarget* GetTabChildGlobalAsEventTarget();
   nsresult CreateStaticClone(nsIFrameLoader* aDest);
 
   /**
    * Called from the layout frame associated with this frame loader;
    * this notifies us to hook up with the widget and view.
    */
   bool Show(PRInt32 marginWidth, PRInt32 marginHeight,
             PRInt32 scrollbarPrefX, PRInt32 scrollbarPrefY,
@@ -104,24 +106,30 @@ public:
   // 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();
+  nsresult EnsureMessageManager();
   NS_HIDDEN_(void) GetURL(nsString& aURL);
   nsresult CheckURILoad(nsIURI* aURI);
   void FireErrorEvent();
   nsresult ReallyStartLoadingInternal();
 
   nsCOMPtr<nsIDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURIToLoad;
   nsIContent *mOwnerContent; // WEAK
+public:
+  // public because a callback needs these.
+  nsRefPtr<nsFrameMessageManager> mMessageManager;
+  nsCOMPtr<nsIInProcessContentFrameMessageManager> mChildMessageManager;
+private:
   PRPackedBool mDepthTooGreat : 1;
   PRPackedBool mIsTopLevelContent : 1;
   PRPackedBool mDestroyCalled : 1;
   PRPackedBool mNeedsAsyncDestroy : 1;
   PRPackedBool mInSwap : 1;
 };
 
 #endif
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -0,0 +1,457 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsFrameMessageManager.h"
+#include "nsContentUtils.h"
+#include "nsIXPConnect.h"
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsinterp.h"
+#include "nsJSUtils.h"
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
+  PRUint32 count = tmp->mListeners.Length();
+  for (PRUint32 i = 0; i < count; i++) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mListeners[i] mListener");
+    cb.NoteXPCOMChild(tmp->mListeners[i].mListener.get());
+  }
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mChildManagers)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameMessageManager)
+  tmp->mListeners.Clear();
+  for (PRInt32 i = tmp->mChildManagers.Count(); i > 0; --i) {
+    static_cast<nsFrameMessageManager*>(tmp->mChildManagers[i - 1])->
+      Disconnect(PR_FALSE);
+  }
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mChildManagers)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentFrameMessageManager)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIFrameMessageManager, nsIContentFrameMessageManager)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIContentFrameMessageManager, !mChrome)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIChromeFrameMessageManager, mChrome)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsFrameMessageManager,
+                                          nsIContentFrameMessageManager)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsFrameMessageManager,
+                                           nsIContentFrameMessageManager)
+
+NS_IMETHODIMP
+nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
+                                          nsIFrameMessageListener* aListener)
+{
+  nsCOMPtr<nsIAtom> message = do_GetAtom(aMessage);
+  PRUint32 len = mListeners.Length();
+  for (PRUint32 i = 0; i < len; ++i) {
+    if (mListeners[i].mMessage == message &&
+      mListeners[i].mListener == aListener) {
+      return NS_OK;
+    }
+  }
+  nsMessageListenerInfo* entry = mListeners.AppendElement();
+  NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
+  entry->mMessage = message;
+  entry->mListener = aListener;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessage,
+                                             nsIFrameMessageListener* aListener)
+{
+  nsCOMPtr<nsIAtom> message = do_GetAtom(aMessage);
+  PRUint32 len = mListeners.Length();
+  for (PRUint32 i = 0; i < len; ++i) {
+    if (mListeners[i].mMessage == message &&
+      mListeners[i].mListener == aListener) {
+      mListeners.RemoveElementAt(i);
+      return NS_OK;
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
+                                       PRBool aAllowDelayedLoad)
+{
+  if (aAllowDelayedLoad && !mCallbackData && !mChildManagers.Count()) {
+    mPendingScripts.AppendElement(aURL);
+    return NS_OK;
+  }
+
+  if (mCallbackData) {
+#ifdef DEBUG_smaug
+    printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get());
+#endif
+    NS_ENSURE_TRUE(mLoadScriptCallback(mCallbackData, aURL), NS_ERROR_FAILURE);
+  }
+
+  PRInt32 len = mChildManagers.Count();
+  for (PRInt32 i = 0; i < len; ++i) {
+    static_cast<nsFrameMessageManager*>(mChildManagers[i])->LoadFrameScript(aURL,
+                                                                            PR_FALSE);
+  }
+  return NS_OK;
+}
+
+static JSBool
+JSONCreator(const jschar* aBuf, uint32 aLen, void* aData)
+{
+  nsAString* result = static_cast<nsAString*>(aData);
+  result->Append((PRUnichar*)aBuf, (PRUint32)aLen);
+  return JS_TRUE;
+}
+
+nsresult
+nsFrameMessageManager::GetParamsForMessage(nsAString& aMessageName,
+                                           nsAString& aJSON)
+{
+  aMessageName.Truncate();
+  aJSON.Truncate();
+  nsAXPCNativeCallContext* ncc = nsnull;
+  nsresult rv = nsContentUtils::XPConnect()->GetCurrentNativeCallContext(&ncc);
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_STATE(ncc);
+
+  JSContext* ctx = nsnull;
+  rv = ncc->GetJSContext(&ctx);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRUint32 argc;
+  jsval* argv = nsnull;
+  ncc->GetArgc(&argc);
+  ncc->GetArgvPtr(&argv);
+
+  JSAutoRequest ar(ctx);
+  JSString* str;
+  if (argc && (str = JS_ValueToString(ctx, argv[0])) && str) {
+    aMessageName.Assign(nsDependentJSString(str));
+  }
+
+  if (argc >= 2) {
+    jsval v = argv[1];
+    nsAutoGCRoot root(&v, &rv);
+    NS_ENSURE_SUCCESS(rv, JS_FALSE);
+    if (JS_TryJSON(ctx, &v)) {
+      JS_Stringify(ctx, &v, nsnull, JSVAL_NULL, JSONCreator, &aJSON);
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::SendSyncMessage()
+{
+  if (mSyncCallback) {
+    NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
+    nsString messageName;
+    nsString json;
+    nsresult rv = GetParamsForMessage(messageName, json);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsTArray<nsString> retval;
+    if (mSyncCallback(mCallbackData, messageName, json, &retval)) {
+      nsAXPCNativeCallContext* ncc = nsnull;
+      rv = nsContentUtils::XPConnect()->GetCurrentNativeCallContext(&ncc);
+      NS_ENSURE_SUCCESS(rv, rv);
+      NS_ENSURE_STATE(ncc);
+
+      JSContext* ctx = nsnull;
+      rv = ncc->GetJSContext(&ctx);
+      NS_ENSURE_SUCCESS(rv, rv);
+      JSAutoRequest ar(ctx);
+
+      PRUint32 len = retval.Length();
+      jsval* dest = nsnull;
+      JSObject* dataArray = js_NewArrayObjectWithCapacity(ctx, len, &dest);
+      NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
+      nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      for (PRUint32 i = 0; i < len; ++i) {
+        jsval ret = JSVAL_VOID;
+        nsAutoGCRoot root(&ret, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+        JSONParser* parser = JS_BeginJSONParse(ctx, &ret);
+        JSBool ok = JS_ConsumeJSONText(ctx, parser, (jschar*)retval[i].get(),
+                                       (uint32)retval[i].Length());
+        ok = JS_FinishJSONParse(ctx, parser, JSVAL_NULL) && ok;
+        if (ok) {
+          dest[i] = ret;
+        }
+      }
+
+      jsval* retvalPtr;
+      ncc->GetRetValPtr(&retvalPtr);
+      *retvalPtr = OBJECT_TO_JSVAL(dataArray);
+      ncc->SetReturnValueWasSet(PR_TRUE);
+    }
+  }
+  NS_ASSERTION(!mParentManager, "Should not have parent manager in content!");
+  return NS_OK;
+}
+
+nsresult
+nsFrameMessageManager::SendAsyncMessageInternal(const nsAString& aMessage,
+                                                const nsAString& aJSON)
+{
+  if (mAsyncCallback) {
+    NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
+    mAsyncCallback(mCallbackData, aMessage, aJSON);
+  }
+  PRInt32 len = mChildManagers.Count();
+  for (PRInt32 i = 0; i < len; ++i) {
+    static_cast<nsFrameMessageManager*>(mChildManagers[i])->
+      SendAsyncMessageInternal(aMessage, aJSON);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::SendAsyncMessage()
+{
+  nsString messageName;
+  nsString json;
+  nsresult rv = GetParamsForMessage(messageName, json);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return SendAsyncMessageInternal(messageName, json);
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::Dump(const nsAString& aStr)
+{
+  fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout);
+  fflush(stdout);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::GetContent(nsIDOMWindow** aContent)
+{
+  *aContent = nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
+{
+  *aDocShell = nsnull;
+  return NS_OK;
+}
+
+nsresult
+nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
+                                      const nsAString& aMessage,
+                                      PRBool aSync, const nsAString& aJSON,
+                                      JSObject* aObjectsArray,
+                                      nsTArray<nsString>* aJSONRetVal)
+{
+  if (mListeners.Length()) {
+    nsCOMPtr<nsIAtom> name = do_GetAtom(aMessage);
+    nsRefPtr<nsFrameMessageManager> kungfuDeathGrip(this);
+
+    for (PRUint32 i = 0; i < mListeners.Length(); ++i) {
+      if (mListeners[i].mMessage == name) {
+        nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS =
+          do_QueryInterface(mListeners[i].mListener);
+        if (!wrappedJS) {
+          continue;
+        }
+        JSObject* object = nsnull;
+        wrappedJS->GetJSObject(&object);
+        if (!object) {
+          continue;
+        }
+        nsCxPusher pusher;
+        NS_ENSURE_STATE(pusher.Push(mContext, PR_FALSE));
+
+        JSAutoRequest ar(mContext);
+
+        // The parameter for the listener function.
+        JSObject* param = JS_NewObject(mContext, NULL, NULL, NULL);
+        NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
+
+        nsresult rv;
+        nsAutoGCRoot resultGCRoot(&param, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        jsval targetv;
+        nsAutoGCRoot resultGCRoot2(&targetv, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+        nsContentUtils::WrapNative(mContext,
+                                   JS_GetGlobalObject(mContext),
+                                   aTarget, &targetv);
+
+        // To keep compatibility with e10s message manager,
+        // define empty objects array.
+        if (!aObjectsArray) {
+          jsval* dest = nsnull;
+          // Because we want JS messages to have always the same properties,
+          // create array even if len == 0.
+          aObjectsArray = js_NewArrayObjectWithCapacity(mContext, 0, &dest);
+          if (!aObjectsArray) {
+            return false;
+          }
+        }
+        nsAutoGCRoot arrayGCRoot(&aObjectsArray, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        jsval json = JSVAL_NULL;
+        nsAutoGCRoot root(&json, &rv);
+        if (NS_SUCCEEDED(rv) && !aJSON.IsEmpty()) {
+          JSONParser* parser = JS_BeginJSONParse(mContext, &json);
+          if (parser) {
+            JSBool ok = JS_ConsumeJSONText(mContext, parser,
+                                           (jschar*)nsString(aJSON).get(),
+                                           (uint32)aJSON.Length());
+            ok = JS_FinishJSONParse(mContext, parser, JSVAL_NULL) && ok;
+            if (!ok) {
+              json = JSVAL_NULL;
+            }
+          }
+        }
+        JSString* jsMessage =
+          JS_NewUCStringCopyN(mContext,
+                              reinterpret_cast<const jschar *>(nsString(aMessage).get()),
+                              aMessage.Length());
+        NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
+        JS_DefineProperty(mContext, param, "target", targetv, NULL, NULL, JSPROP_ENUMERATE);
+        JS_DefineProperty(mContext, param, "name",
+                          STRING_TO_JSVAL(jsMessage), NULL, NULL, JSPROP_ENUMERATE);
+        JS_DefineProperty(mContext, param, "sync",
+                          BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE);
+        JS_DefineProperty(mContext, param, "json", json, NULL, NULL, JSPROP_ENUMERATE);
+        JS_DefineProperty(mContext, param, "objects", OBJECT_TO_JSVAL(aObjectsArray),
+                          NULL, NULL, JSPROP_ENUMERATE);
+
+        jsval thisValue = JSVAL_VOID;
+        nsAutoGCRoot resultGCRoot3(&thisValue, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        jsval funval = JSVAL_VOID;
+        if (JS_ObjectIsFunction(mContext, object)) {
+          // If the listener is a JS function:
+          funval = OBJECT_TO_JSVAL(object);
+          nsCOMPtr<nsISupports> defaultThisValue =
+            do_QueryInterface(static_cast<nsIContentFrameMessageManager*>(this));
+          nsContentUtils::WrapNative(mContext,
+                                     JS_GetGlobalObject(mContext),
+                                     defaultThisValue, &thisValue);
+        } else {
+          // If the listener is a JS object which has receiveMessage function:
+          NS_ENSURE_STATE(JS_GetProperty(mContext, object, "receiveMessage",
+                                         &funval) &&
+                          JSVAL_IS_OBJECT(funval) &&
+                          !JSVAL_IS_NULL(funval));
+          JSObject* funobject = JSVAL_TO_OBJECT(funval);
+          NS_ENSURE_STATE(JS_ObjectIsFunction(mContext, funobject));
+          thisValue = OBJECT_TO_JSVAL(object);
+        }
+
+        jsval rval = JSVAL_VOID;
+        nsAutoGCRoot resultGCRoot4(&rval, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        void* mark = nsnull;
+        jsval* argv = js_AllocStack(mContext, 1, &mark);
+        NS_ENSURE_TRUE(argv, NS_ERROR_OUT_OF_MEMORY);
+
+        argv[0] = OBJECT_TO_JSVAL(param);
+        JSObject* thisObject = JSVAL_TO_OBJECT(thisValue);
+        JS_CallFunctionValue(mContext, thisObject,
+                             funval, 1, argv, &rval);
+        if (aJSONRetVal) {
+          nsString json;
+          if (JS_TryJSON(mContext, &rval) &&
+              JS_Stringify(mContext, &rval, nsnull, JSVAL_NULL,
+                           JSONCreator, &json)) {
+            aJSONRetVal->AppendElement(json);
+          }
+        }
+        js_FreeStack(mContext, mark);
+      }
+    }
+  }
+  return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
+                                                         aSync, aJSON, aObjectsArray,
+                                                         aJSONRetVal) : NS_OK;
+}
+
+void
+nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager,
+                                       PRBool aLoadScripts)
+{
+  mChildManagers.AppendObject(aManager);
+  if (aLoadScripts) {
+    for (PRUint32 i = 0; i < mPendingScripts.Length(); ++i) {
+      aManager->LoadFrameScript(mPendingScripts[i], PR_FALSE);
+    }
+  }
+}
+
+void
+nsFrameMessageManager::SetCallbackData(void* aData, PRBool aLoadScripts)
+{
+  if (aData && mCallbackData != aData) {
+    mCallbackData = aData;
+    // First load global scripts by adding this to parent manager.
+    if (mParentManager) {
+      mParentManager->AddChildManager(this, aLoadScripts);
+    }
+    if (aLoadScripts) {
+      for (PRUint32 i = 0; i < mPendingScripts.Length(); ++i) {
+        LoadFrameScript(mPendingScripts[i], PR_FALSE);
+      }
+    }
+  }
+}
+
+void
+nsFrameMessageManager::Disconnect(PRBool aRemoveFromParent)
+{
+  if (mParentManager && aRemoveFromParent) {
+    mParentManager->RemoveChildManager(this);
+  }
+  mParentManager = nsnull;
+  mCallbackData = nsnull;
+}
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsFrameMessageManager.h
@@ -0,0 +1,143 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef nsFrameMessageManager_h__
+#define nsFrameMessageManager_h__
+
+#include "nsIFrameMessageManager.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
+#include "nsTArray.h"
+#include "nsIAtom.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsTArray.h"
+
+class nsAXPCNativeCallContext;
+struct JSContext;
+struct JSObject;
+
+struct nsMessageListenerInfo
+{
+  nsCOMPtr<nsIFrameMessageListener> mListener;
+  nsCOMPtr<nsIAtom> mMessage;
+};
+
+typedef bool (*nsLoadScriptCallback)(void* aCallbackData, const nsAString& aURL);
+typedef bool (*nsSyncMessageCallback)(void* aCallbackData,
+                                      const nsAString& aMessage,
+                                      const nsAString& aJSON,
+                                      nsTArray<nsString>* aJSONRetVal);
+typedef bool (*nsAsyncMessageCallback)(void* aCallbackData,
+                                       const nsAString& aMessage,
+                                       const nsAString& aJSON);
+
+class nsFrameMessageManager : public nsIContentFrameMessageManager,
+                              public nsIChromeFrameMessageManager
+{
+public:
+  nsFrameMessageManager(PRBool aChrome,
+                        nsSyncMessageCallback aSyncCallback,
+                        nsAsyncMessageCallback aAsyncCallback,
+                        nsLoadScriptCallback aLoadScriptCallback,
+                        void* aCallbackData,
+                        nsFrameMessageManager* aParentManager,
+                        JSContext* aContext)
+  : mChrome(aChrome), mParentManager(aParentManager),
+    mSyncCallback(aSyncCallback), mAsyncCallback(aAsyncCallback),
+    mLoadScriptCallback(aLoadScriptCallback), mCallbackData(aCallbackData),
+    mContext(aContext)
+  {
+    NS_ASSERTION(mContext, "Should have mContext!");
+    NS_ASSERTION(aChrome || !aParentManager, "Should not set parent manager!");
+    if (mParentManager && mCallbackData) {
+      mParentManager->AddChildManager(this);
+    }
+  }
+
+  ~nsFrameMessageManager()
+  {
+    for (PRInt32 i = mChildManagers.Count(); i > 0; --i) {
+      static_cast<nsFrameMessageManager*>(mChildManagers[i - 1])->
+        Disconnect(PR_FALSE);
+    }
+  }
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameMessageManager,
+                                           nsIContentFrameMessageManager)
+  NS_DECL_NSIFRAMEMESSAGEMANAGER
+  NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
+  NS_DECL_NSICHROMEFRAMEMESSAGEMANAGER
+
+  nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
+                          PRBool aSync, const nsAString& aJSON,
+                          JSObject* aObjectsArray,
+                          nsTArray<nsString>* aJSONRetVal);
+  void AddChildManager(nsFrameMessageManager* aManager,
+                       PRBool aLoadScripts = PR_TRUE);
+  void RemoveChildManager(nsFrameMessageManager* aManager)
+  {
+    mChildManagers.RemoveObject(aManager);
+  }
+
+  void Disconnect(PRBool aRemoveFromParent = PR_TRUE);
+  void SetCallbackData(void* aData, PRBool aLoadScripts = PR_TRUE);
+  nsresult GetParamsForMessage(nsAString& aMessageName, nsAString& aJSON);
+  nsresult SendAsyncMessageInternal(const nsAString& aMessage,
+                                    const nsAString& aJSON);
+  JSContext* GetJSContext() { return mContext; }
+  nsFrameMessageManager* GetParentManager() { return mParentManager; }
+  void SetParentManager(nsFrameMessageManager* aParent)
+  {
+    NS_ASSERTION(!mParentManager, "We have parent manager already!");
+    NS_ASSERTION(mChrome, "Should not set parent manager!");
+    mParentManager = aParent;
+  }
+protected:
+  nsTArray<nsMessageListenerInfo> mListeners;
+  nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
+  PRBool mChrome;
+  nsFrameMessageManager* mParentManager;
+  nsSyncMessageCallback mSyncCallback;
+  nsAsyncMessageCallback mAsyncCallback;
+  nsLoadScriptCallback mLoadScriptCallback;
+  void* mCallbackData;
+  JSContext* mContext;
+  nsTArray<nsString> mPendingScripts;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -0,0 +1,366 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsInProcessTabChildGlobal.h"
+#include "nsContentUtils.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsEventDispatcher.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsIJSRuntimeService.h"
+#include "nsComponentManagerUtils.h"
+#include "nsNetUtil.h"
+#include "nsScriptLoader.h"
+#include "nsIJSContextStack.h"
+#include "nsFrameLoader.h"
+
+bool SendSyncMessageToParent(void* aCallbackData,
+                             const nsAString& aMessage,
+                             const nsAString& aJSON,
+                             nsTArray<nsString>* aJSONRetVal)
+{
+  nsInProcessTabChildGlobal* tabChild =
+    static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
+  PRInt32 count = tabChild->mASyncMessages.Count();
+  for (PRInt32 i = 0; i < count; ++i) {
+    nsCOMPtr<nsIRunnable> async = tabChild->mASyncMessages.SafeObjectAt(i);
+    async->Run();
+  }
+  if (tabChild->mChromeMessageManager) {
+    tabChild->mChromeMessageManager->ReceiveMessage(tabChild->mOwner, aMessage, PR_TRUE,
+                                                    aJSON, nsnull, aJSONRetVal);
+  }
+  return true;
+}
+
+class nsAsyncMessageToParent : public nsRunnable
+{
+public:
+  nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
+                         const nsAString& aMessage, const nsAString& aJSON)
+    : mTabChild(aTabChild), mMessage(aMessage), mJSON(aJSON) {}
+
+  NS_IMETHOD Run()
+  {
+    mTabChild->mASyncMessages.RemoveObject(this);
+    if (mTabChild->mChromeMessageManager) {
+      mTabChild->mChromeMessageManager->ReceiveMessage(mTabChild->mOwner, mMessage,
+                                                       PR_FALSE,
+                                                       mJSON, nsnull, nsnull);
+    }
+    return NS_OK;
+  }
+  nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
+  nsString mMessage;
+  nsString mJSON;
+};
+
+bool SendAsyncMessageToParent(void* aCallbackData,
+                              const nsAString& aMessage,
+                              const nsAString& aJSON)
+{
+  nsInProcessTabChildGlobal* tabChild =
+    static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
+  nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToParent(tabChild, aMessage, aJSON);
+  tabChild->mASyncMessages.AppendObject(ev);
+  NS_DispatchToCurrentThread(ev);
+  return true;
+}
+
+static int tabChildC = 0;
+nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
+                                                     nsIContent* aOwner,
+                                                     nsFrameMessageManager* aChrome)
+: mCx(nsnull), mDocShell(aShell), mInitialized(PR_FALSE), mLoadingScript(PR_FALSE),
+  mDelayedDisconnect(PR_FALSE), mOwner(aOwner), mChromeMessageManager(aChrome)
+{
+}
+
+nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
+{
+  Disconnect();
+  NS_ASSERTION(!mCx, "Couldn't release JSContext?!?");
+}
+
+nsresult
+nsInProcessTabChildGlobal::Init()
+{
+  nsresult rv = InitTabChildGlobal();
+  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
+                   "Couldn't initialize nsInProcessTabChildGlobal");
+  mMessageManager = new nsFrameMessageManager(PR_FALSE,
+                                              SendSyncMessageToParent,
+                                              SendAsyncMessageToParent,
+                                              nsnull,
+                                              this,
+                                              nsnull,
+                                              mCx);
+  return NS_OK;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsInProcessTabChildGlobal)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsInProcessTabChildGlobal,
+                                                nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMessageManager)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobal)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsInProcessTabChildGlobal,
+                                                  nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobal)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal)
+  NS_INTERFACE_MAP_ENTRY(nsIFrameMessageManager)
+  NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
+  NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)
+  NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)
+  NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal, nsDOMEventTargetHelper)
+
+NS_IMETHODIMP
+nsInProcessTabChildGlobal::GetContent(nsIDOMWindow** aContent)
+{
+  *aContent = nsnull;
+  nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mDocShell);
+  window.swap(*aContent);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
+{
+  NS_IF_ADDREF(*aDocShell = mDocShell);
+  return NS_OK;
+}
+
+void
+nsInProcessTabChildGlobal::Disconnect()
+{
+  mDocShell = nsnull;
+  mOwner = nsnull;
+  mChromeMessageManager = nsnull;
+  if (mMessageManager) {
+    static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
+    mMessageManager = nsnull;
+  }
+  if (!mLoadingScript) {
+    if (mCx) {
+      JS_DestroyContext(mCx);
+      mCx = nsnull;
+    }
+  } else {
+    mDelayedDisconnect = PR_TRUE;
+  }
+}
+
+NS_IMETHODIMP_(nsIContent *)
+nsInProcessTabChildGlobal::GetOwnerContent()
+{
+  return mOwner;
+}
+
+nsresult
+nsInProcessTabChildGlobal::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+{
+  aVisitor.mCanHandle = PR_TRUE;
+  aVisitor.mParentTarget = mOwner;
+
+#ifdef DEBUG
+  if (mOwner) {
+    nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface(mOwner);
+    nsRefPtr<nsFrameLoader> fl = owner->GetFrameLoader();
+    if (fl) {
+      NS_ASSERTION(this == fl->GetTabChildGlobalAsEventTarget(),
+                   "Wrong event target!");
+      NS_ASSERTION(fl->mMessageManager == mChromeMessageManager,
+                   "Wrong message manager!");
+    }
+  }
+#endif
+
+  return NS_OK;
+}
+
+nsresult
+nsInProcessTabChildGlobal::InitTabChildGlobal()
+{
+  nsCOMPtr<nsIJSRuntimeService> runtimeSvc = 
+    do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+  NS_ENSURE_STATE(runtimeSvc);
+
+  JSRuntime* rt = nsnull;
+  runtimeSvc->GetRuntime(&rt);
+  NS_ENSURE_STATE(rt);
+
+  JSContext* cx = JS_NewContext(rt, 8192);
+  NS_ENSURE_STATE(cx);
+
+  mCx = cx;
+
+  nsContentUtils::XPConnect()->SetSecurityManagerForJSContext(cx, nsContentUtils::GetSecurityManager(), 0);
+  nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
+
+  PRUint32 stackDummy;
+  jsuword stackLimit, currentStackAddr = (jsuword)&stackDummy;
+
+  // 256k stack space.
+  const jsuword kStackSize = 0x40000;
+
+#if JS_STACK_GROWTH_DIRECTION < 0
+  stackLimit = (currentStackAddr > kStackSize) ?
+               currentStackAddr - kStackSize :
+               0;
+#else
+  stackLimit = (currentStackAddr + kStackSize > currentStackAddr) ?
+               currentStackAddr + kStackSize :
+               (jsuword) -1;
+#endif
+
+  JS_SetThreadStackLimit(cx, stackLimit);
+  JS_SetScriptStackQuota(cx, 100*1024*1024);
+
+  JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_ANONFUNFIX | JSOPTION_PRIVATE_IS_NSISUPPORTS);
+  JS_SetVersion(cx, JSVERSION_LATEST);
+  JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 1 * 1024 * 1024);
+
+  JSAutoRequest ar(cx);
+  nsIXPConnect* xpc = nsContentUtils::XPConnect();
+  const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES |
+                         /*nsIXPConnect::OMIT_COMPONENTS_OBJECT ?  |*/
+                         nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
+
+  nsISupports* scopeSupports =
+    NS_ISUPPORTS_CAST(nsPIDOMEventTarget*, this);
+  JS_SetContextPrivate(cx, scopeSupports);
+
+  nsresult rv =
+    xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports,
+                                         NS_GET_IID(nsISupports), flags,
+                                         getter_AddRefs(mGlobal));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  JSObject* global = nsnull;
+  rv = mGlobal->GetJSObject(&global);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  JS_SetGlobalObject(cx, global);
+
+  return NS_OK;
+}
+
+void
+nsInProcessTabChildGlobal::LoadFrameScript(const nsAString& aURL)
+{
+  if (!mInitialized) {
+    mInitialized = PR_TRUE;
+    Init();
+  }
+  if (!mGlobal || !mCx) {
+    return;
+  }
+
+  nsCString url = NS_ConvertUTF16toUTF8(aURL);
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  nsCOMPtr<nsIChannel> channel;
+  NS_NewChannel(getter_AddRefs(channel), uri);
+  if (!channel) {
+    return;
+  }
+
+  nsCOMPtr<nsIInputStream> input;
+  channel->Open(getter_AddRefs(input));
+  nsString dataString;
+  if (input) {
+    const PRUint32 bufferSize = 256;
+    char buffer[bufferSize];
+    nsCString data;
+    PRUint32 avail = 0;
+    input->Available(&avail);
+    PRUint32 read = 0;
+    if (avail) {
+      while (NS_SUCCEEDED(input->Read(buffer, bufferSize, &read)) && read) {
+        data.Append(buffer, read);
+        read = 0;
+      }
+    }
+    nsScriptLoader::ConvertToUTF16(channel, (PRUint8*)data.get(), data.Length(),
+                                   EmptyString(), nsnull, dataString);
+  }
+
+  if (!dataString.IsEmpty()) {
+    JSAutoRequest ar(mCx);
+    jsval retval;
+    JSObject* global = nsnull;
+    mGlobal->GetJSObject(&global);
+    if (!global) {
+      return;
+    }
+
+    JSPrincipals* jsprin = nsnull;
+    mPrincipal->GetJSPrincipals(mCx, &jsprin);
+    nsContentUtils::XPConnect()->FlagSystemFilenamePrefix(url.get(), PR_TRUE);
+    nsContentUtils::ThreadJSContextStack()->Push(mCx);
+    PRBool tmp = mLoadingScript;
+    mLoadingScript = PR_TRUE;
+    JS_EvaluateUCScriptForPrincipals(mCx, global, jsprin,
+                                     (jschar*)dataString.get(),
+                                     dataString.Length(),
+                                     url.get(), 1, &retval);
+    //XXX Argh, JSPrincipals are manually refcounted!
+    JSPRINCIPALS_DROP(mCx, jsprin);
+    mLoadingScript = tmp;
+    JSContext* unused;
+    nsContentUtils::ThreadJSContextStack()->Pop(&unused);
+  }
+  if (!mLoadingScript && mDelayedDisconnect) {
+    mDelayedDisconnect = PR_FALSE;
+    Disconnect();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsInProcessTabChildGlobal.h
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsInProcessTabChildGlobal_h
+#define nsInProcessTabChildGlobal_h
+
+#include "nsCOMPtr.h"
+#include "nsFrameMessageManager.h"
+#include "nsIScriptContext.h"
+#include "nsDOMEventTargetHelper.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsIScriptContext.h"
+#include "nsIClassInfo.h"
+#include "jsapi.h"
+#include "nsIDocShell.h"
+#include "nsIXPConnect.h"
+#include "nsIDOMElement.h"
+#include "nsCOMArray.h"
+#include "nsThreadUtils.h"
+
+class nsInProcessTabChildGlobal : public nsDOMEventTargetHelper,
+                                  public nsIInProcessContentFrameMessageManager,
+                                  public nsIScriptObjectPrincipal,
+                                  public nsIScriptContextPrincipal
+{
+public:
+  nsInProcessTabChildGlobal(nsIDocShell* aShell, nsIContent* aOwner,
+                            nsFrameMessageManager* aChrome);
+  virtual ~nsInProcessTabChildGlobal();
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsInProcessTabChildGlobal,
+                                           nsDOMEventTargetHelper)
+  NS_FORWARD_SAFE_NSIFRAMEMESSAGEMANAGER(mMessageManager)
+  NS_IMETHOD SendSyncMessage()
+  {
+    return mMessageManager ? mMessageManager->SendSyncMessage()
+                           : NS_ERROR_NULL_POINTER;
+  }
+  NS_IMETHOD GetContent(nsIDOMWindow** aContent);
+  NS_IMETHOD GetDocShell(nsIDocShell** aDocShell);
+  NS_IMETHOD Dump(const nsAString& aStr)
+  {
+    return mMessageManager ? mMessageManager->Dump(aStr) : NS_OK;
+  }
+  NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
+
+  virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
+  NS_IMETHOD AddEventListener(const nsAString& aType,
+                              nsIDOMEventListener* aListener,
+                              PRBool aUseCapture)
+  {
+    // By default add listeners only for trusted events!
+    return nsDOMEventTargetHelper::AddEventListener(aType, aListener,
+                                                    aUseCapture, PR_FALSE, 1);
+  }
+  NS_IMETHOD AddEventListener(const nsAString& aType,
+                              nsIDOMEventListener* aListener,
+                              PRBool aUseCapture, PRBool aWantsUntrusted,
+                              PRUint8 optional_argc)
+  {
+    return nsDOMEventTargetHelper::AddEventListener(aType, aListener,
+                                                    aUseCapture,
+                                                    aWantsUntrusted,
+                                                    optional_argc);
+  }
+
+  virtual nsIScriptObjectPrincipal* GetObjectPrincipal() { return this; }
+  virtual JSContext* GetJSContextForEventHandlers() { return mCx; }
+  virtual nsIPrincipal* GetPrincipal() { return mPrincipal; }
+  void LoadFrameScript(const nsAString& aURL);
+  void Disconnect();
+  void SendMessageToParent(const nsString& aMessage, PRBool aSync,
+                           const nsString& aJSON,
+                           nsTArray<nsString>* aJSONRetVal);
+  nsFrameMessageManager* GetInnerManager()
+  {
+    return static_cast<nsFrameMessageManager*>(mMessageManager.get());
+  }
+
+  void SetOwner(nsIContent* aOwner) { mOwner = aOwner; }
+  nsFrameMessageManager* GetChromeMessageManager()
+  {
+    return mChromeMessageManager;
+  }
+  void SetChromeMessageManager(nsFrameMessageManager* aParent)
+  {
+    mChromeMessageManager = aParent;
+  }
+protected:
+  nsresult Init();
+  nsresult InitTabChildGlobal();
+  nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
+  JSContext* mCx;
+  nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<nsIDocShell> mDocShell;
+  PRPackedBool mInitialized;
+  PRPackedBool mLoadingScript;
+  PRPackedBool mDelayedDisconnect;
+public:
+  nsIContent* mOwner;
+  nsFrameMessageManager* mChromeMessageManager;
+  nsCOMArray<nsIRunnable> mASyncMessages;
+};
+
+#endif
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -925,17 +925,17 @@ nsScriptLoader::ConvertToUTF16(nsIChanne
     // charset name is always ASCII.
     LossyCopyUTF16toASCII(aHintCharset, characterSet);
   }
 
   if (NS_FAILED(rv) || characterSet.IsEmpty()) {
     DetectByteOrderMark(aData, aLength, characterSet);
   }
 
-  if (characterSet.IsEmpty()) {
+  if (characterSet.IsEmpty() && aDocument) {
     // charset from document default
     characterSet = aDocument->GetDocumentCharacterSet();
   }
 
   if (characterSet.IsEmpty()) {
     // fall back to ISO-8859-1, see bug 118404
     characterSet.AssignLiteral("ISO-8859-1");
   }
--- a/content/base/test/chrome/Makefile.in
+++ b/content/base/test/chrome/Makefile.in
@@ -50,15 +50,17 @@ include $(topsrcdir)/config/rules.mk
 _CHROME_FILES = \
     test_bug206691.xul \
     test_bug421622.xul \
     test_bug429785.xul \
     test_bug430050.xul \
     test_bug467123.xul \
     test_title.xul \
     title_window.xul \
+    test_bug549682.xul \
+    file_bug549682.xul \
     $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_CHROME_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/base/test/chrome/file_bug549682.xul
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=549682
+-->
+<window title="Mozilla Bug 549682"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  onload="run()">
+  <label value="Mozilla Bug 549682"/>
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+  var didRunAsync = false;
+
+  function asyncL(m) {
+    didRunAsync = true;
+    opener.wrappedJSObject.is(m.name, "async", "Wrong message!");
+    opener.wrappedJSObject.is(m.json.data, 1234, "Wrong data!");
+  }
+
+  function syncL(m) {
+    opener.wrappedJSObject.is(m.name, "sync", "Wrong message!");
+    opener.wrappedJSObject.is(m.json.data, 1234, "Wrong data!");
+    opener.wrappedJSObject.ok(didRunAsync, "Should have run async!");
+    opener.setTimeout("done()", 0);
+    var i = document.getElementById("ifr");
+    i.parentNode.removeChild(i); // This is a crash test!
+    window.close();
+  }
+
+  function loadScript() {
+    // Async should be prosessed first!
+    messageManager.loadFrameScript("data:,sendAsyncMessage('async', { data: 1234 }); sendSyncMessage('sync', { data: 1234 });", true);
+  }
+
+  function run() {
+    messageManager.addMessageListener("async", asyncL);
+    messageManager.addMessageListener("sync", syncL);
+    setTimeout(loadScript, 0);
+  }
+
+  ]]></script>
+  <browser type="content" src="about:blank" id="ifr"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/content/base/test/chrome/test_bug549682.xul
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=549682
+-->
+<window title="Mozilla Bug 549682"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=549682"
+     target="_blank">Mozilla Bug 549682</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+
+  /** Test for Bug 549682 **/
+  SimpleTest.waitForExplicitFinish();
+
+  function done() {
+    SimpleTest.finish();
+  }
+
+  addLoadEvent(function() {
+    window.open("file_bug549682.xul", "", "chrome");
+  });
+  ]]></script>
+</window>
--- a/content/events/public/nsPIDOMEventTarget.h
+++ b/content/events/public/nsPIDOMEventTarget.h
@@ -44,21 +44,22 @@
 class nsIDOMEvent;
 class nsPresContext;
 class nsEventChainPreVisitor;
 class nsEventChainPostVisitor;
 class nsIEventListenerManager;
 class nsIDOMEventListener;
 class nsIDOMEventGroup;
 class nsIScriptContext;
+struct JSContext;
 
-// e6579895-a23c-4afc-872a-d53da71def5d
+// 89292f3a-535d-4ba0-882a-10cff9e21bcc
 #define NS_PIDOMEVENTTARGET_IID \
-  { 0xe6579895, 0xa23c, 0x4afc, \
-    { 0x87, 0x2a, 0xd5, 0x3d, 0xa7, 0x1d, 0xef, 0x5d } }
+  { 0x89292f3a, 0x535d, 0x4ba0, \
+    { 0x88, 0x2a, 0x10, 0xcf, 0xf9, 0xe2, 0x1b, 0xcc } }
 
 class nsPIDOMEventTarget : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMEVENTTARGET_IID)
 
   /**
    * Returns the nsPIDOMEventTarget object which should be used as the target
@@ -159,13 +160,19 @@ public:
   virtual nsresult GetSystemEventGroup(nsIDOMEventGroup** aGroup) = 0;
 
   /**
    * Get the script context in which the event handlers should be run.
    * May return null.
    * @note Caller *must* check the value of aRv.
    */
   virtual nsIScriptContext* GetContextForEventHandlers(nsresult* aRv) = 0;
+
+  /**
+   * If the method above returns null, but a success code, this method
+   * is called.
+   */
+   virtual JSContext* GetJSContextForEventHandlers() { return nsnull; }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMEventTarget, NS_PIDOMEVENTTARGET_IID)
 
 #endif // !defined(nsPIDOMEventTarget_h_)
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -464,16 +464,17 @@
 #include "nsIDOMFormData.h"
 
 // Simple gestures include
 #include "nsIDOMSimpleGestureEvent.h"
 
 #include "nsIDOMNSMouseEvent.h"
 
 #include "nsIEventListenerService.h"
+#include "nsIFrameMessageManager.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
@@ -545,16 +546,17 @@ static const char kDOMStringBundleURL[] 
 #else
 #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                \
   // nothing
 #endif
 
 DOMCI_DATA(Crypto, void)
 DOMCI_DATA(CRMFObject, void)
 DOMCI_DATA(SmartCardEvent, void)
+DOMCI_DATA(ContentFrameMessageManager, void)
 
 DOMCI_DATA(DOMPrototype, void)
 DOMCI_DATA(DOMConstructor, void)
 
 DOMCI_DATA(Worker, void)
 DOMCI_DATA(ChromeWorker, void)
 
 DOMCI_DATA(Notation, void)
@@ -1378,16 +1380,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PopStateEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TransitionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(ContentFrameMessageManager, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(FormData, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 };
 
 // Objects that should be constructable through |new Name();|
 struct nsContractIDMapData
 {
@@ -3829,16 +3833,23 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIEventListenerInfo)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(TransitionEvent, nsIDOMTransitionEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTransitionEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsIContentFrameMessageManager)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
+    DOM_CLASSINFO_MAP_ENTRY(nsIFrameMessageManager)
+    DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(FormData, nsIDOMFormData)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFormData)
   DOM_CLASSINFO_MAP_END
 
 #ifdef NS_DEBUG
   {
     PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData);
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -463,10 +463,11 @@ DOMCI_CLASS(PaintRequest)
 DOMCI_CLASS(PaintRequestList)
 
 DOMCI_CLASS(ScrollAreaEvent)
 DOMCI_CLASS(PopStateEvent)
 
 DOMCI_CLASS(EventListenerInfo)
 
 DOMCI_CLASS(TransitionEvent)
+DOMCI_CLASS(ContentFrameMessageManager)
 
 DOMCI_CLASS(FormData)
--- a/dom/base/nsDOMJSUtils.h
+++ b/dom/base/nsDOMJSUtils.h
@@ -18,16 +18,32 @@ GetScriptContextFromJSContext(JSContext 
     do_QueryInterface(static_cast<nsISupports *>
                                  (::JS_GetContextPrivate(cx)));
 
   // This will return a pointer to something that's about to be
   // released, but that's ok here.
   return scx;
 }
 
+inline nsIScriptContextPrincipal*
+GetScriptContextPrincipalFromJSContext(JSContext *cx)
+{
+  if (!(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
+    return nsnull;
+  }
+
+  nsCOMPtr<nsIScriptContextPrincipal> scx =
+    do_QueryInterface(static_cast<nsISupports *>
+                                 (::JS_GetContextPrivate(cx)));
+
+  // This will return a pointer to something that's about to be
+  // released, but that's ok here.
+  return scx;
+}
+
 // A factory function for turning a jsval argv into an nsIArray
 // but also supports an effecient way of extracting the original argv.
 // Bug 312003 describes why this must be "void *", but argv will be cast to
 // jsval* and the args are found at:
 //    ((jsval*)aArgv)[0], ..., ((jsval*)aArgv)[aArgc - 1]
 // The resulting object will take a copy of the array, and ensure each
 // element is rooted.
 // Optionally, aArgv may be NULL, in which case the array is allocated and
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -199,16 +199,17 @@
 #include "nsIXBLService.h"
 
 // used for popup blocking, needs to be converted to something
 // belonging to the back-end like nsIContentPolicy
 #include "nsIPopupWindowManager.h"
 
 #include "nsIDragService.h"
 #include "mozilla/dom/Element.h"
+#include "nsFrameLoader.h"
 #include "nsISupportsPrimitives.h"
 #include "nsXPCOMCID.h"
 
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
@@ -291,16 +292,27 @@ static PRBool               gDOMWindowDu
     if (!outer) {                                                             \
       NS_WARNING("No outer window available!");                               \
       return err_rval;                                                        \
     }                                                                         \
     return ((nsGlobalChromeWindow *)outer)->method args;                      \
   }                                                                           \
   PR_END_MACRO
 
+#define FORWARD_TO_INNER_CHROME(method, args, err_rval)                       \
+  PR_BEGIN_MACRO                                                              \
+  if (IsOuterWindow()) {                                                      \
+    if (!mInnerWindow) {                                                      \
+      NS_WARNING("No inner window available!");                               \
+      return err_rval;                                                        \
+    }                                                                         \
+    return ((nsGlobalChromeWindow *)mInnerWindow)->method args;               \
+  }                                                                           \
+  PR_END_MACRO
+
 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval)         \
   PR_BEGIN_MACRO                                                              \
   if (IsInnerWindow()) {                                                      \
     nsGlobalWindow *outer = GetOuterWindowInternal();                         \
     if (!outer) {                                                             \
       NS_WARNING("No outer window available!");                               \
       return err_rval;                                                        \
     }                                                                         \
@@ -2368,17 +2380,26 @@ nsGlobalWindow::PreHandleEvent(nsEventCh
         do_GetService("@mozilla.org/widget/dragservice;1");
       if (ds) {
         gDragServiceDisabled = PR_FALSE;
         ds->Unsuppress();
       }
     }
   }
 
-  aVisitor.mParentTarget = mChromeEventHandler;
+  nsPIDOMEventTarget* chromeTarget = mChromeEventHandler;
+  nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mChromeEventHandler);
+  if (flo) {
+    nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
+    if (fl) {
+      nsPIDOMEventTarget* t = fl->GetTabChildGlobalAsEventTarget();
+      chromeTarget = t ? t : chromeTarget;
+    }
+  }
+  aVisitor.mParentTarget = chromeTarget;
   return NS_OK;
 }
 
 nsresult
 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
 
@@ -9371,16 +9392,17 @@ nsGlobalWindow::SetHasOrientationEventLi
 }
 
 // nsGlobalChromeWindow implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
                                                   nsGlobalWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
 
 // QueryInterface implementation for nsGlobalChromeWindow
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
   NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
@@ -9603,16 +9625,38 @@ nsGlobalChromeWindow::NotifyDefaultButto
   if (rv == NS_ERROR_NOT_IMPLEMENTED)
     return NS_OK;
   return rv;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
+NS_IMETHODIMP
+nsGlobalChromeWindow::GetMessageManager(nsIChromeFrameMessageManager** aManager)
+{
+  FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_FAILURE);
+  if (!mMessageManager) {
+    nsIScriptContext* scx = GetContextInternal();
+    NS_ENSURE_STATE(scx);
+    JSContext* cx = (JSContext *)scx->GetNativeContext();
+    NS_ENSURE_STATE(cx);
+    mMessageManager = new nsFrameMessageManager(PR_TRUE,
+                                                nsnull,
+                                                nsnull,
+                                                nsnull,
+                                                nsnull,
+                                                nsnull,
+                                                cx);
+    NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
+  }
+  NS_ADDREF(*aManager = mMessageManager);
+  return NS_OK;
+}
+
 // nsGlobalModalWindow implementation
 
 // QueryInterface implementation for nsGlobalModalWindow
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalModalWindow)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalModalWindow,
                                                   nsGlobalWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReturnValue)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -96,16 +96,17 @@
 #include "nsIDOMStorageObsolete.h"
 #include "nsIDOMStorageList.h"
 #include "nsIDOMStorageWindow.h"
 #include "nsIDOMStorageEvent.h"
 #include "nsIDOMOfflineResourceList.h"
 #include "nsPIDOMEventTarget.h"
 #include "nsIArray.h"
 #include "nsIContent.h"
+#include "nsFrameMessageManager.h"
 
 #define DEFAULT_HOME_PAGE "www.mozilla.org"
 #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
 
 class nsIDOMBarProp;
 class nsIDocument;
 class nsPresContext;
 class nsIDOMEvent;
@@ -853,16 +854,17 @@ public:
     mIsChrome = PR_TRUE;
   }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGlobalChromeWindow,
                                                      nsGlobalWindow)
 
 protected:
   nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
+  nsCOMPtr<nsIChromeFrameMessageManager> mMessageManager;
 };
 
 /*
  * nsGlobalModalWindow inherits from nsGlobalWindow. It is the global
  * object created for a modal content windows only (i.e. not modal
  * chrome dialogs).
  */
 class nsGlobalModalWindow : public nsGlobalWindow,
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -48,36 +48,52 @@ class nsIScriptGlobalObject;
 class nsIScriptSecurityManager;
 class nsIPrincipal;
 class nsIAtom;
 class nsIArray;
 class nsIVariant;
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class nsScriptObjectHolder;
+class nsIScriptObjectPrincipal;
 
 typedef void (*nsScriptTerminationFunc)(nsISupports* aRef);
 
+#define NS_ISCRIPTCONTEXTPRINCIPAL_IID \
+  { 0xd012cdb3, 0x8f1e, 0x4440, \
+    { 0x8c, 0xbd, 0x32, 0x7f, 0x98, 0x1d, 0x37, 0xb4 } }
+
+class nsIScriptContextPrincipal : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTCONTEXTPRINCIPAL_IID)
+
+  virtual nsIScriptObjectPrincipal* GetObjectPrincipal() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
+                              NS_ISCRIPTCONTEXTPRINCIPAL_IID)
+
 // A4FE2B52-62B5-40C3-BF9C-5E0A27B10F90
 #define NS_ISCRIPTCONTEXT_IID \
 { 0xA4FE2B52, 0x62B5, 0x40C3, \
   { 0xBF, 0x9C, 0x5E, 0x0A, 0x27, 0xB1, 0x0F, 0x90 } }
 
 /* This MUST match JSVERSION_DEFAULT.  This version stuff if we don't
    know what language we have is a little silly... */
 #define SCRIPTVERSION_DEFAULT JSVERSION_DEFAULT
 
 /**
  * It is used by the application to initialize a runtime and run scripts.
  * A script runtime would implement this interface.
  * <P><I>It does have a bit too much java script information now, that
  * should be removed in a short time. Ideally this interface will be
  * language neutral</I>
  */
-class nsIScriptContext : public nsISupports
+class nsIScriptContext : public nsIScriptContextPrincipal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTCONTEXT_IID)
 
   /* Get the ID of this language. */
   virtual PRUint32 GetScriptTypeID() = 0;
 
   /**
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1475,16 +1475,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_REFCNT(nsJSContext, tmp->GetCCRefcnt())
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGlobalWrapperRef)
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContext");
   nsContentUtils::XPConnect()->NoteJSContext(tmp->mContext, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext)
   NS_INTERFACE_MAP_ENTRY(nsIScriptContext)
+  NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)
   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptNotify)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptContext)
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSContext, nsIScriptContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSContext, nsIScriptContext)
 
@@ -1663,16 +1664,23 @@ JSValueToAString(JSContext *cx, jsval va
 
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   return NS_OK;
 }
 
+nsIScriptObjectPrincipal*
+nsJSContext::GetObjectPrincipal()
+{
+  nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(GetGlobalObject());
+  return prin;
+}
+
 nsresult
 nsJSContext::EvaluateString(const nsAString& aScript,
                             void *aScopeObject,
                             nsIPrincipal *aPrincipal,
                             const char *aURL,
                             PRUint32 aLineNo,
                             PRUint32 aVersion,
                             nsAString *aRetValue,
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -60,16 +60,18 @@ class nsJSContext : public nsIScriptCont
 public:
   nsJSContext(JSRuntime *aRuntime);
   virtual ~nsJSContext();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext,
                                                          nsIScriptContext)
 
+  virtual nsIScriptObjectPrincipal* GetObjectPrincipal();
+
   virtual PRUint32 GetScriptTypeID()
     { return nsIProgrammingLanguage::JAVASCRIPT; }
 
   virtual nsresult EvaluateString(const nsAString& aScript,
                                   void *aScopeObject,
                                   nsIPrincipal *principal,
                                   const char *aURL,
                                   PRUint32 aLineNo,
--- a/dom/interfaces/base/nsIDOMChromeWindow.idl
+++ b/dom/interfaces/base/nsIDOMChromeWindow.idl
@@ -35,18 +35,19 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIBrowserDOMWindow;
 interface nsIDOMElement;
+interface nsIChromeFrameMessageManager;
 
-[scriptable, uuid(09b86cbd-9784-4fe4-9be6-70b9bbca3a9c)]
+[scriptable, uuid(adf6b19f-459f-4892-93eb-71c527bae2af)]
 interface nsIDOMChromeWindow : nsISupports
 {
   const unsigned short STATE_MAXIMIZED = 1;
   const unsigned short STATE_MINIMIZED = 2;
   const unsigned short STATE_NORMAL = 3;
   const unsigned short STATE_FULLSCREEN = 4;
 
   readonly attribute unsigned short              windowState;
@@ -68,9 +69,11 @@ interface nsIDOMChromeWindow : nsISuppor
   void                      minimize();
   void                      restore();
 
   /**
    * Notify a default button is loaded on a dialog or a wizard.
    * defaultButton is the default button.
    */
   void notifyDefaultButtonLoaded(in nsIDOMElement defaultButton);
+
+  readonly attribute nsIChromeFrameMessageManager messageManager;
 };
--- a/js/src/xpconnect/src/xpcthreadcontext.cpp
+++ b/js/src/xpconnect/src/xpcthreadcontext.cpp
@@ -118,21 +118,20 @@ XPCJSContextStack::Pop(JSContext * *_ret
         }
     }
     return NS_OK;
 }
 
 static nsIPrincipal*
 GetPrincipalFromCx(JSContext *cx)
 {
-    nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
-    if(scriptContext)
+    nsIScriptContextPrincipal* scp = GetScriptContextPrincipalFromJSContext(cx);
+    if(scp)
     {
-        nsCOMPtr<nsIScriptObjectPrincipal> globalData =
-            do_QueryInterface(scriptContext->GetGlobalObject());
+        nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
         if(globalData)
             return globalData->GetPrincipal();
     }
     return nsnull;
 }
 
 /* void push (in JSContext cx); */
 NS_IMETHODIMP
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -91,16 +91,17 @@
 #include "nsStyleStructInlines.h"
 #include "nsIAppShell.h"
 #include "prenv.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMEventTarget.h"
 #include "nsObjectFrame.h"
 #include "nsTransitionManager.h"
 #include "mozilla/dom/Element.h"
+#include "nsIFrameMessageManager.h"
 
 #ifdef MOZ_SMIL
 #include "nsSMILAnimationController.h"
 #endif // MOZ_SMIL
 
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif // IBMBIDI
@@ -2047,25 +2048,40 @@ MayHavePaintEventListener(nsPIDOMWindow*
     return PR_FALSE;
   if (aInnerWindow->HasPaintEventListeners())
     return PR_TRUE;
 
   nsPIDOMEventTarget* chromeEventHandler = aInnerWindow->GetChromeEventHandler();
   if (!chromeEventHandler)
     return PR_FALSE;
 
-  nsCOMPtr<nsINode> node = do_QueryInterface(chromeEventHandler);
+  nsIEventListenerManager* manager = nsnull;
+  nsCOMPtr<nsINode> node;
+  nsCOMPtr<nsIInProcessContentFrameMessageManager> mm =
+    do_QueryInterface(chromeEventHandler);
+  if (mm) {
+    nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(mm);
+    if (target && (manager = target->GetListenerManager(PR_FALSE)) &&
+        manager->MayHavePaintEventListener()) {
+      return PR_TRUE;
+    }
+    node = mm->GetOwnerContent();
+  }
+
+  if (!node) {
+    node = do_QueryInterface(chromeEventHandler);
+  }
   if (node)
     return MayHavePaintEventListener(node->GetOwnerDoc()->GetInnerWindow());
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(chromeEventHandler);
   if (window)
     return MayHavePaintEventListener(window);
 
-  nsIEventListenerManager* manager =
+  manager =
     chromeEventHandler->GetListenerManager(PR_FALSE);
   if (manager && manager->MayHavePaintEventListener())
     return PR_TRUE;
 
   return PR_FALSE;
 }
 
 PRBool