Bug 542242 - E10s, content process event handlers, r=jst, r=bsmedberg
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sat, 20 Feb 2010 19:05:20 +0200
changeset 46683 416375517820bf550a6bf64a0d5a4ba729eb6d97
parent 46682 eb57ae66e03f27e921848c2da38cf8cad140d5a8
child 46684 60b96935c8e1bc88623d9ec33257999d6231d5ec
push id14210
push userdougt@mozilla.com
push dateThu, 01 Jul 2010 06:28:42 +0000
treeherdermozilla-central@3aff97777291 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst, bsmedberg
bugs542242
milestone1.9.3a2pre
Bug 542242 - E10s, content process event handlers, r=jst, r=bsmedberg
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/nsScriptLoader.cpp
content/events/public/nsPIDOMEventTarget.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoID.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/base/nsPIWindowRoot.h
dom/base/nsWindowRoot.cpp
dom/base/nsWindowRoot.h
dom/interfaces/base/nsIDOMChromeWindow.idl
dom/ipc/Makefile.in
dom/ipc/PIFrameEmbedding.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/jar.mn
dom/ipc/remote-test.js
dom/ipc/test.xul
js/src/xpconnect/src/xpcthreadcontext.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2056,25 +2056,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*
@@ -2249,21 +2249,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
@@ -109,12 +109,13 @@ XPIDLSRCS	= \
 		nsIDragDropHandler.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
@@ -1601,17 +1601,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
@@ -37,18 +37,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIDocShell;
 interface nsIURI;
 interface nsIFrame;
+interface nsIChromeFrameMessageManager;
 
-[scriptable, uuid(8f94788d-ec69-4220-971c-0fd68d47b80f)]
+[scriptable, uuid(25b7a7e9-9507-4649-bba9-86852d72c5d3)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -99,16 +100,18 @@ interface nsIFrameLoader : nsISupports
                                   in long aClickCount,
                                   in long aModifiers,
                                   [optional] in boolean aIgnoreRootScrollFrame);
 
   /**
    * Activate event forwarding from client (remote frame) to parent.
    */
   void activateFrameEvent(in AString aType, in boolean capture);
+
+  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,106 @@
+/* -*- 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;
+
+[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(22de316b-a986-45bb-9e97-9af27e8afac3)]
+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;
+
+  /**
+   * Print a string to stdout.
+   */
+  void dump(in DOMString aStr);
+};
+
+[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
@@ -129,16 +129,17 @@ CPPSRCS		= \
 		nsTextNode.cpp \
 		nsTraversal.cpp \
 		nsTreeWalker.cpp \
 		nsXHTMLContentSerializer.cpp \
 		nsXMLContentSerializer.cpp \
 		nsXMLHttpRequest.cpp \
 		nsXMLNameSpaceMap.cpp \
 		Link.cpp \
+		nsFrameMessageManager.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
@@ -2795,16 +2795,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) {
@@ -2844,33 +2850,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
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -698,16 +698,19 @@ nsFrameLoader::ShowRemoteFrame(nsIFrameF
 #elif defined(XP_MACOSX)
 #  warning IMPLEMENT ME
 
 #else
 #error TODO for this platform
 #endif
 
   mChildProcess->Move(0, 0, size.width, size.height);
+  mRemoteWidgetCreated = PR_TRUE;
+  nsCOMPtr<nsIChromeFrameMessageManager> dummy;
+  GetMessageManager(getter_AddRefs(dummy)); // Initialize message manager.
 
   return true;
 }
 #endif
 
 void
 nsFrameLoader::Hide()
 {
@@ -1551,8 +1554,70 @@ 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;
 }
+
+#ifdef MOZ_IPC
+bool LoadScript(void* aCallbackData, const nsAString& aURL)
+{
+  mozilla::dom::PIFrameEmbeddingParent* tabParent =
+    static_cast<nsFrameLoader*>(aCallbackData)->GetChildProcess();
+  if (tabParent) {
+    return tabParent->SendloadRemoteScript(nsString(aURL));
+  }
+  return false;
+}
+
+bool SendAsyncMessageToChild(void* aCallbackData,
+                             const nsAString& aMessage,
+                             const nsAString& aJSON)
+{
+  mozilla::dom::PIFrameEmbeddingParent* tabParent =
+    static_cast<nsFrameLoader*>(aCallbackData)->GetChildProcess();
+  if (tabParent) {
+    return tabParent->SendsendAsyncMessageToChild(nsString(aMessage),
+                                                  nsString(aJSON));
+  }
+  return false;
+}
+#endif
+
+NS_IMETHODIMP
+nsFrameLoader::GetMessageManager(nsIChromeFrameMessageManager** aManager)
+{
+#ifdef MOZ_IPC
+  NS_ENSURE_STATE(mOwnerContent);
+  if (!mMessageManager) {
+    nsresult rv;
+    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,
+                                                mRemoteWidgetCreated ? this : nsnull,
+                                                static_cast<nsFrameMessageManager*>(parentManager.get()),
+                                                cx);
+    NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
+  } else {
+    mMessageManager->SetCallbackData(mRemoteWidgetCreated ? this : nsnull);
+  }
+  return CallQueryInterface(mMessageManager.get(), aManager);
+#else
+  *aManager = nsnull;
+  return NS_OK;
+#endif
+}
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -45,16 +45,17 @@
 #define nsFrameLoader_h_
 
 #include "nsIDocShell.h"
 #include "nsStringFwd.h"
 #include "nsIFrameLoader.h"
 #include "nsSize.h"
 #include "nsIURI.h"
 #include "nsAutoPtr.h"
+#include "nsFrameMessageManager.h"
 
 class nsIContent;
 class nsIURI;
 class nsIFrameFrame;
 class nsIView;
 
 #ifdef MOZ_IPC
 namespace mozilla {
@@ -78,27 +79,31 @@ protected:
   nsFrameLoader(nsIContent *aOwner) :
     mOwnerContent(aOwner),
     mDepthTooGreat(PR_FALSE),
     mIsTopLevelContent(PR_FALSE),
     mDestroyCalled(PR_FALSE),
     mNeedsAsyncDestroy(PR_FALSE),
     mInSwap(PR_FALSE)
 #ifdef MOZ_IPC
+    , mRemoteWidgetCreated(PR_FALSE)
     , mRemoteFrame(false)
     , mChildProcess(nsnull)
 #ifdef MOZ_WIDGET_GTK2
     , mRemoteSocket(nsnull)
 #endif
 #endif
   {}
 
 public:
   ~nsFrameLoader() {
     mNeedsAsyncDestroy = PR_TRUE;
+    if (mMessageManager) {
+      mMessageManager->Disconnect();
+    }
     nsFrameLoader::Destroy();
   }
 
   static nsFrameLoader* Create(nsIContent* aOwner);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsFrameLoader)
   NS_DECL_NSIFRAMELOADER
@@ -132,16 +137,18 @@ public:
   nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
                                nsRefPtr<nsFrameLoader>& aFirstToSwap,
                                nsRefPtr<nsFrameLoader>& aSecondToSwap);
 
 #ifdef MOZ_IPC
   mozilla::dom::PIFrameEmbeddingParent* GetChildProcess();
 #endif
 
+  nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; }
+
 private:
 
 #ifdef MOZ_IPC
   bool ShouldUseRemoteProcess();
 #endif
 
   /**
    * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
@@ -172,21 +179,23 @@ private:
   nsIContent *mOwnerContent; // WEAK
   PRPackedBool mDepthTooGreat : 1;
   PRPackedBool mIsTopLevelContent : 1;
   PRPackedBool mDestroyCalled : 1;
   PRPackedBool mNeedsAsyncDestroy : 1;
   PRPackedBool mInSwap : 1;
 
 #ifdef MOZ_IPC
+  PRPackedBool mRemoteWidgetCreated : 1;
   bool mRemoteFrame;
   // XXX leaking
   mozilla::dom::TabParent* mChildProcess;
 
 #ifdef MOZ_WIDGET_GTK2
   GtkWidget* mRemoteSocket;
 #elif defined(MOZ_WIDGET_QT)
   QX11EmbedContainer* mRemoteSocket;
 #endif
 #endif
+  nsRefPtr<nsFrameMessageManager> mMessageManager;
 };
 
 #endif
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -0,0 +1,403 @@
+/* -*- 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 "jsnum.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) {
+    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;
+}
+
+void
+nsFrameMessageManager::SendAsyncMessageInternal(const nsAString& aMessage,
+                                                const nsAString& aJSON)
+{
+  if (mAsyncCallback) {
+    mAsyncCallback(mCallbackData, aMessage, aJSON);
+  }
+  PRInt32 len = mChildManagers.Count();
+  for (PRInt32 i = 0; i < len; ++i) {
+    static_cast<nsFrameMessageManager*>(mChildManagers[i])->
+      SendAsyncMessageInternal(aMessage, aJSON);
+  }
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::SendAsyncMessage()
+{
+  nsString messageName;
+  nsString json;
+  nsresult rv = GetParamsForMessage(messageName, json);
+  NS_ENSURE_SUCCESS(rv, rv);
+  SendAsyncMessageInternal(messageName, json);
+  return NS_OK;
+}
+
+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;
+}
+
+nsresult
+nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
+                                      const nsAString& aMessage,
+                                      PRBool aSync, const nsAString& aJSON,
+                                      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, NS_ERROR_FAILURE));
+
+        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 json = JSVAL_NULL;
+        nsAutoGCRoot root(&json, &rv);
+        if (NS_SUCCEEDED(rv)) {
+          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, "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);
+
+        jsval funval = OBJECT_TO_JSVAL(static_cast<JSObject *>(object));
+        jsval targetv;
+        nsAutoGCRoot resultGCRoot2(&targetv, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+        nsContentUtils::WrapNative(mContext,
+                                   JS_GetGlobalObject(mContext),
+                                   aTarget, &targetv);
+
+        jsval rval = JSVAL_VOID;
+        nsAutoGCRoot resultGCRoot3(&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* target = JSVAL_TO_OBJECT(targetv);
+        JS_CallFunctionValue(mContext, target,
+                             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,
+                                                         aJSONRetVal) : NS_OK;
+}
+
+void
+nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager)
+{
+  mChildManagers.AppendObject(aManager);
+  for (PRUint32 i = 0; i < mPendingScripts.Length(); ++i) {
+    aManager->LoadFrameScript(mPendingScripts[i], PR_FALSE);
+  }
+}
+
+void
+nsFrameMessageManager::SetCallbackData(void* aData)
+{
+  if (aData && mCallbackData != aData) {
+    mCallbackData = aData;
+    // First load global scripts by adding this to parent manager.
+    if (mParentManager) {
+      mParentManager->AddChildManager(this);
+    }
+    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,131 @@
+/* -*- 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 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!");
+    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,
+                          nsTArray<nsString>* aJSONRetVal);
+  void AddChildManager(nsFrameMessageManager* aManager);
+  void RemoveChildManager(nsFrameMessageManager* aManager)
+  {
+    mChildManagers.RemoveObject(aManager);
+  }
+
+  void Disconnect(PRBool aRemoveFromParent = PR_TRUE);
+  void SetCallbackData(void* aData);
+  nsresult GetParamsForMessage(nsAString& aMessageName, nsAString& aJSON);
+  void SendAsyncMessageInternal(const nsAString& aMessage,
+                                const nsAString& aJSON);
+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
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -878,17 +878,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/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
@@ -460,16 +460,17 @@
 #include "nsIDOMFileError.h"
 
 // Simple gestures include
 #include "nsIDOMSimpleGestureEvent.h"
 
 #include "nsIDOMNSMouseEvent.h"
 
 #include "nsIEventListenerService.h"
+#include "nsIFrameMessageManager.h"
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
 
 // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
 //       are defined in nsIDOMClassInfo.h.
@@ -1332,16 +1333,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)
 };
 
 // Objects that should be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
   const char *mContractID;
 };
@@ -3743,16 +3746,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
+
 #ifdef NS_DEBUG
   {
     PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData);
 
     if (i != eDOMClassInfoIDCount) {
       NS_ERROR("The number of items in sClassInfoData doesn't match the "
                "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
 
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -474,16 +474,18 @@ enum nsDOMClassInfoID {
 
   eDOMClassInfo_ScrollAreaEvent_id,
   eDOMClassInfo_PopStateEvent_id,
 
   eDOMClassInfo_EventListenerInfo_id,
 
   eDOMClassInfo_TransitionEvent_id,
 
+  eDOMClassInfo_ContentFrameMessageManager_id,
+
   // This one better be the last one in this list
   eDOMClassInfoIDCount
 };
 
 /**
  * nsIClassInfo helper macros
  */
 
--- 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
@@ -285,16 +285,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;                                                        \
     }                                                                         \
@@ -9185,16 +9196,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
 
 // QueryInterface implementation for nsGlobalChromeWindow
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
   NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
 
@@ -9415,16 +9427,42 @@ 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)
+{
+#ifdef MOZ_IPC
+  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);
+#else
+  *aManager = nsnull;
+#endif
+  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;
@@ -819,16 +820,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
@@ -1460,16 +1460,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)
 
@@ -1648,16 +1649,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
@@ -58,16 +58,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/base/nsPIWindowRoot.h
+++ b/dom/base/nsPIWindowRoot.h
@@ -40,26 +40,29 @@
 #ifndef nsPIWindowRoot_h__
 #define nsPIWindowRoot_h__
 
 #include "nsISupports.h"
 #include "nsPIDOMEventTarget.h"
 
 class nsIDOMWindow;
 class nsIFocusController;
+struct JSContext;
 
-// 440f8d32-818d-468a-ac75-5916fa1ea198
+// a9f58a8b-55cd-47fb-aeaa-f54010ffd154
 #define NS_IWINDOWROOT_IID \
-{ 0x440f8d32, 0x818d, 0x468a, \
-  { 0xac, 0x75, 0x59, 0x16, 0xfa, 0x1e, 0xa1, 0x98 } }
+{ 0xa9f58a8b, 0x55cd, 0x47fb, \
+  { 0xae, 0xaa, 0xf5, 0x40, 0x10, 0xff, 0xd1, 0x54 } }
 
 class nsPIWindowRoot : public nsPIDOMEventTarget {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)
 
   NS_IMETHOD GetFocusController(nsIFocusController** aResult)=0;
 
   virtual nsIDOMWindow* GetWindow()=0;
+
+  virtual void SetParentTarget(nsPIDOMEventTarget* aTarget) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIWindowRoot, NS_IWINDOWROOT_IID)
 
 #endif // nsPIWindowRoot_h__
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -70,17 +70,18 @@ nsWindowRoot::nsWindowRoot(nsIDOMWindow*
 
 nsWindowRoot::~nsWindowRoot()
 {
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
 }
 
-NS_IMPL_CYCLE_COLLECTION_2(nsWindowRoot, mListenerManager, mFocusController)
+NS_IMPL_CYCLE_COLLECTION_3(nsWindowRoot, mListenerManager, mFocusController,
+                           mParent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
@@ -227,16 +228,17 @@ nsWindowRoot::GetSystemEventGroup(nsIDOM
 
 nsresult
 nsWindowRoot::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = PR_TRUE;
   aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
   // To keep mWindow alive
   aVisitor.mItemData = mWindow;
+  aVisitor.mParentTarget = mParent;
   return NS_OK;
 }
 
 nsresult
 nsWindowRoot::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   return NS_OK;
 }
--- a/dom/base/nsWindowRoot.h
+++ b/dom/base/nsWindowRoot.h
@@ -88,23 +88,30 @@ public:
     return nsnull;
   }
 
   // nsPIWindowRoot
   NS_IMETHOD GetFocusController(nsIFocusController** aResult);
 
   virtual nsIDOMWindow* GetWindow();
 
+  virtual void SetParentTarget(nsPIDOMEventTarget* aTarget)
+  {
+    mParent = aTarget;
+  }
+
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsWindowRoot, nsIDOMEventTarget)
 
 protected:
   // Members
   nsIDOMWindow* mWindow; // [Weak]. The window will hold on to us and let go when it dies.
   nsCOMPtr<nsIEventListenerManager> mListenerManager; // [Strong]. We own the manager, which owns event listeners attached
                                                       // to us.
   nsCOMPtr<nsIFocusController> mFocusController; // The focus controller for the root.
+
+  nsCOMPtr<nsPIDOMEventTarget> mParent;
 };
 
 extern nsresult
 NS_NewWindowRoot(nsIDOMWindow* aWindow,
                  nsPIDOMEventTarget** aResult);
 
 #endif
--- 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/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -71,11 +71,12 @@ CPPSRCS = \
   $(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
 		-I$(srcdir)/../../content/base/src \
+		-I$(srcdir)/../../content/events/src \
 		$(NULL)
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
--- a/dom/ipc/PIFrameEmbedding.ipdl
+++ b/dom/ipc/PIFrameEmbedding.ipdl
@@ -62,16 +62,19 @@ parent:
      * When child sends this message, parent should move focus to
      * the next or previous focusable element.
      */
     moveFocus(bool forward);
 
     sendEvent(RemoteDOMEvent aEvent);
 
     rpc createWindow() returns (PIFrameEmbedding window);
+
+    sync sendSyncMessageToParent(nsString aMessage, nsString aJSON) returns (nsString[] retval);
+    sendAsyncMessageToParent(nsString aMessage, nsString aJSON);
 child:
     createWidget(MagicWindowHandle parentWidget);
 
     loadURL(nsCString uri);
 
     move(PRUint32 x,
          PRUint32 y,
          PRUint32 width,
@@ -93,13 +96,17 @@ child:
                    PRInt32 aModifiers,
                    bool aIgnoreRootScrollFrame);
 
     /**
      * Activate event forwarding from client to parent.
      */
     activateFrameEvent(nsString aType, bool capture);
 
+    loadRemoteScript(nsString aURL);
+
+    sendAsyncMessageToChild(nsString aMessage, nsString aJSON);
+
     PDocumentRenderer(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h, nsString bgcolor, PRUint32 flags, bool flush);
 };
 
 }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -53,16 +53,28 @@
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsISupportsImpl.h"
 #include "nsIWebBrowserFocus.h"
 #include "nsIDOMEvent.h"
 #include "nsIPrivateDOMEvent.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsIJSRuntimeService.h"
+#include "nsContentUtils.h"
+#include "nsIDOMClassInfo.h"
+#include "nsIXPCSecurityManager.h"
+#include "nsIJSContextStack.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsScriptLoader.h"
+#include "nsPIWindowRoot.h"
+#include "nsIScriptContext.h"
 
 #ifdef MOZ_WIDGET_GTK2
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 #endif
 
 using namespace mozilla::dom;
 
@@ -314,17 +326,17 @@ TabChild::RecvcreateWidget(const MagicWi
 #endif
 
 #if !defined(XP_MACOSX)
     baseWindow->InitWindow(win, 0, 0, 0, 0, 0);
     baseWindow->Create();
     baseWindow->SetVisibility(PR_TRUE);
 #endif
 
-    return true;
+    return InitTabChildGlobal();
 }
 
 bool
 TabChild::destroyWidget()
 {
     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mWebNav);
     if (baseWindow)
         baseWindow->Destroy();
@@ -339,16 +351,24 @@ TabChild::~TabChild()
       delete gQApp; 
     gQApp = nsnull; 
 #endif
     destroyWidget();
     nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(mWebNav);
     if (webBrowser) {
       webBrowser->SetContainerWindow(nsnull);
     }
+    if (mCx) {
+      nsIXPConnect* xpc = nsContentUtils::XPConnect();
+      if (xpc) {
+         xpc->ReleaseJSContext(mCx, PR_FALSE);
+      } else {
+        JS_DestroyContext(mCx);
+      }
+    }
 }
 
 bool
 TabChild::RecvloadURL(const nsCString& uri)
 {
     printf("loading %s, %d\n", uri.get(), NS_IsMainThread());
 
     nsresult rv = mWebNav->LoadURI(NS_ConvertUTF8toUTF16(uri).get(),
@@ -461,8 +481,231 @@ TabChild::RecvactivateFrameEvent(const n
   nsCOMPtr<nsIDOMEventTarget> chromeHandler =
     do_QueryInterface(window->GetChromeEventHandler());
   NS_ENSURE_TRUE(chromeHandler, true);
   nsRefPtr<ContentListener> listener = new ContentListener(this);
   NS_ENSURE_TRUE(listener, true);
   chromeHandler->AddEventListener(aType, listener, capture);
   return true;
 }
+
+bool
+TabChild::RecvloadRemoteScript(const nsString& aURL)
+{
+  nsCString url = NS_ConvertUTF16toUTF8(aURL);
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
+  NS_ENSURE_SUCCESS(rv, true);
+  NS_NewChannel(getter_AddRefs(mChannel), uri);
+  NS_ENSURE_TRUE(mChannel, true);
+
+  nsCOMPtr<nsIInputStream> input;
+  mChannel->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(mChannel, (PRUint8*)data.get(), data.Length(),
+                                   EmptyString(), nsnull, dataString);
+  }
+
+  if (!dataString.IsEmpty()) {
+    JSAutoRequest ar(mCx);
+    nsCOMPtr<nsPIDOMWindow> w = do_GetInterface(mWebNav);
+    jsval retval;
+    JSObject* global = nsnull;
+    rv = mRootGlobal->GetJSObject(&global);
+    NS_ENSURE_SUCCESS(rv, false);
+    JSPrincipals* jsprin = nsnull;
+    mPrincipal->GetJSPrincipals(mCx, &jsprin);
+
+    nsContentUtils::XPConnect()->FlagSystemFilenamePrefix(url.get(), PR_TRUE);
+
+    nsContentUtils::ThreadJSContextStack()->Push(mCx);
+    JSBool ret = JS_EvaluateUCScriptForPrincipals(mCx, global, jsprin,
+                                                  (jschar*)dataString.get(),
+                                                  dataString.Length(),
+                                                  url.get(), 1, &retval);
+    JSContext *unused;
+    nsContentUtils::ThreadJSContextStack()->Pop(&unused);
+    NS_ENSURE_TRUE(ret, true); // This gives us a useful warning!
+  }
+  return true;
+}
+
+bool
+TabChild::RecvsendAsyncMessageToChild(const nsString& aMessage,
+                                      const nsString& aJSON)
+{
+  if (mTabChildGlobal) {
+    nsTArray<nsString> dummy;
+    static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get())->
+      ReceiveMessage(static_cast<nsPIDOMEventTarget*>(mTabChildGlobal),
+                     aMessage, PR_FALSE, aJSON, nsnull);
+  }
+  return true;
+}
+
+
+bool
+TabChild::InitTabChildGlobal()
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
+  NS_ENSURE_TRUE(window, false);
+  nsCOMPtr<nsIDOMEventTarget> chromeHandler =
+    do_QueryInterface(window->GetChromeEventHandler());
+  NS_ENSURE_TRUE(chromeHandler, false);
+
+  nsCOMPtr<nsIJSRuntimeService> runtimeSvc = 
+    do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+  NS_ENSURE_TRUE(runtimeSvc, false);
+
+  JSRuntime* rt = nsnull;
+  runtimeSvc->GetRuntime(&rt);
+  NS_ENSURE_TRUE(rt, false);
+
+  JSContext* cx = JS_NewContext(rt, 8192);
+  NS_ENSURE_TRUE(cx, false);
+
+  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_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;
+
+  nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
+  NS_ENSURE_TRUE(scope, false);
+
+  mTabChildGlobal = scope;
+
+  nsISupports* scopeSupports =
+    NS_ISUPPORTS_CAST(nsPIDOMEventTarget*, scope);
+  JS_SetContextPrivate(cx, scopeSupports);
+
+  nsresult rv =
+    xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports,
+                                         NS_GET_IID(nsISupports), flags,
+                                         getter_AddRefs(mRootGlobal));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
+  NS_ENSURE_TRUE(root, false);
+  root->SetParentTarget(scope);
+  
+  JSObject* global = nsnull;
+  rv = mRootGlobal->GetJSObject(&global);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  JS_SetGlobalObject(cx, global);
+
+  return true;
+}
+
+bool SendSyncMessageToParent(void* aCallbackData,
+                             const nsAString& aMessage,
+                             const nsAString& aJSON,
+                             nsTArray<nsString>* aJSONRetVal)
+{
+  return static_cast<TabChild*>(aCallbackData)->
+    SendsendSyncMessageToParent(nsString(aMessage), nsString(aJSON), aJSONRetVal);
+}
+
+bool SendAsyncMessageToParent(void* aCallbackData,
+                              const nsAString& aMessage,
+                              const nsAString& aJSON)
+{
+  return static_cast<TabChild*>(aCallbackData)->
+    SendsendAsyncMessageToParent(nsString(aMessage), nsString(aJSON));
+}
+
+TabChildGlobal::TabChildGlobal(TabChild* aTabChild)
+: mTabChild(aTabChild)
+{
+  mMessageManager = new nsFrameMessageManager(PR_FALSE,
+                                              SendSyncMessageToParent,
+                                              SendAsyncMessageToParent,
+                                              nsnull,
+                                              mTabChild,
+                                              nsnull,
+                                              aTabChild->GetJSContext());
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildGlobal)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TabChildGlobal,
+                                                nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMessageManager)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TabChildGlobal,
+                                                  nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChildGlobal)
+  NS_INTERFACE_MAP_ENTRY(nsIFrameMessageManager)
+  NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
+  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(TabChildGlobal, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(TabChildGlobal, nsDOMEventTargetHelper)
+
+NS_IMETHODIMP
+TabChildGlobal::GetContent(nsIDOMWindow** aContent)
+{
+  *aContent = nsnull;
+  nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mTabChild->WebNavigation());
+  window.swap(*aContent);
+  return NS_OK;
+}
+
+JSContext*
+TabChildGlobal::GetJSContextForEventHandlers()
+{
+  return mTabChild->GetJSContext();
+}
+
+nsIPrincipal* 
+TabChildGlobal::GetPrincipal()
+{
+  return mTabChild->GetPrincipal();
+}
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -34,33 +34,95 @@
  * 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 mozilla_tabs_TabChild_h
 #define mozilla_tabs_TabChild_h
 
+#ifndef _IMPL_NS_LAYOUT
 #include "mozilla/dom/PIFrameEmbeddingChild.h"
+#endif
 #include "nsIWebNavigation.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIWebBrowserChrome2.h"
 #include "nsIEmbeddingSiteWindow2.h"
 #include "nsIWebBrowserChromeFocus.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIWindowProvider.h"
+#include "nsIXPCScriptable.h"
+#include "nsIClassInfo.h"
+#include "jsapi.h"
+#include "nsIXPConnect.h"
+#include "nsIDOMWindow.h"
+#include "nsNetUtil.h"
+#include "nsFrameMessageManager.h"
+#include "nsIScriptContext.h"
+#include "nsDOMEventTargetHelper.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsIScriptContext.h"
 
 namespace mozilla {
 namespace dom {
 
 class TabChild;
 
+class TabChildGlobal : public nsDOMEventTargetHelper,
+                       public nsIContentFrameMessageManager,
+                       public nsIScriptObjectPrincipal,
+                       public nsIScriptContextPrincipal
+{
+public:
+  TabChildGlobal(TabChild* aTabChild);
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TabChildGlobal, nsDOMEventTargetHelper)
+  NS_FORWARD_SAFE_NSIFRAMEMESSAGEMANAGER(mMessageManager)
+  NS_IMETHOD SendSyncMessage()
+  {
+    return mMessageManager ? mMessageManager->SendSyncMessage()
+                           : NS_ERROR_NULL_POINTER;
+  }
+  NS_IMETHOD GetContent(nsIDOMWindow** aContent);
+  NS_IMETHOD Dump(const nsAString& aStr)
+  {
+    return mMessageManager ? mMessageManager->Dump(aStr) : NS_OK;
+  }
+
+  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();
+  virtual nsIPrincipal* GetPrincipal();
+
+  nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
+  TabChild* mTabChild;
+};
+
 class ContentListener : public nsIDOMEventListener
 {
 public:
   ContentListener(TabChild* aTabChild) : mTabChild(aTabChild) {}
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 protected:
   TabChild* mTabChild;
@@ -98,16 +160,19 @@ public:
     virtual bool RecvsendMouseEvent(const nsString& aType,
                                     const PRInt32&  aX,
                                     const PRInt32&  aY,
                                     const PRInt32&  aButton,
                                     const PRInt32&  aClickCount,
                                     const PRInt32&  aModifiers,
                                     const bool&     aIgnoreRootScrollFrame);
     virtual bool RecvactivateFrameEvent(const nsString& aType, const bool& capture);
+    virtual bool RecvloadRemoteScript(const nsString& aURL);
+    virtual bool RecvsendAsyncMessageToChild(const nsString& aMessage,
+                                             const nsString& aJSON);
     virtual mozilla::ipc::PDocumentRendererChild* AllocPDocumentRenderer(
             const PRInt32& x,
             const PRInt32& y,
             const PRInt32& w,
             const PRInt32& h,
             const nsString& bgcolor,
             const PRUint32& flags,
             const bool& flush);
@@ -117,18 +182,35 @@ public:
             const PRInt32& x,
             const PRInt32& y,
             const PRInt32& w,
             const PRInt32& h,
             const nsString& bgcolor,
             const PRUint32& flags,
             const bool& flush);
 
+    nsIWebNavigation* WebNavigation() { return mWebNav; }
+
+    JSContext* GetJSContext() { return mCx; }
+
+    nsIPrincipal* GetPrincipal() { return mPrincipal; }
 private:
+    bool InitTabChildGlobal();
+
     nsCOMPtr<nsIWebNavigation> mWebNav;
 
+    nsCOMPtr<nsIXPConnectJSObjectHolder> mRootGlobal;
+
+    JSContext* mCx;
+
+    nsCOMPtr<nsIChannel> mChannel;
+
+    TabChildGlobal* mTabChildGlobal;
+
+    nsCOMPtr<nsIPrincipal> mPrincipal;
+
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 }
 }
 
 #endif // mozilla_tabs_TabChild_h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -159,10 +159,50 @@ void
 TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
                           PRInt32 aButton, PRInt32 aClickCount,
                           PRInt32 aModifiers, PRBool aIgnoreRootScrollFrame)
 {
   SendsendMouseEvent(nsString(aType), aX, aY, aButton, aClickCount,
                      aModifiers, aIgnoreRootScrollFrame);
 }
 
+bool
+TabParent::RecvsendSyncMessageToParent(const nsString& aMessage,
+                                       const nsString& aJSON,
+                                       nsTArray<nsString>* aJSONRetVal)
+{
+  nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner =
+    do_QueryInterface(mFrameElement);
+  if (frameLoaderOwner) {
+    nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
+    if (frameLoader && frameLoader->GetFrameMessageManager()) {
+      frameLoader->GetFrameMessageManager()->ReceiveMessage(mFrameElement,
+                                                            aMessage,
+                                                            PR_TRUE,
+                                                            aJSON,
+                                                            aJSONRetVal);
+    }
+  }
+  return true;
+}
+
+bool
+TabParent::RecvsendAsyncMessageToParent(const nsString& aMessage,
+                                        const nsString& aJSON)
+{
+  nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner =
+    do_QueryInterface(mFrameElement);
+  if (frameLoaderOwner) {
+    nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
+    if (frameLoader && frameLoader->GetFrameMessageManager()) {
+      nsTArray<nsString> dummy;
+      frameLoader->GetFrameMessageManager()->ReceiveMessage(mFrameElement,
+                                                            aMessage,
+                                                            PR_FALSE,
+                                                            aJSON,
+                                                            nsnull);
+    }
+  }
+  return true;
+}
+
 } // namespace tabs
 } // namespace mozilla
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -60,16 +60,21 @@ public:
     void SetOwnerElement(nsIDOMElement* aElement) { mFrameElement = aElement; }
     void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) {
         mBrowserDOMWindow = aBrowserDOMWindow;
     }
 
     virtual bool RecvmoveFocus(const bool& aForward);
     virtual bool RecvsendEvent(const RemoteDOMEvent& aEvent);
     virtual bool AnswercreateWindow(PIFrameEmbeddingParent** retval);
+    virtual bool RecvsendSyncMessageToParent(const nsString& aMessage,
+                                             const nsString& aJSON,
+                                             nsTArray<nsString>* aJSONRetVal);
+    virtual bool RecvsendAsyncMessageToParent(const nsString& aMessage,
+                                              const nsString& aJSON);
 
     void LoadURL(nsIURI* aURI);
     void Move(PRUint32 x, PRUint32 y, PRUint32 width, PRUint32 height);
     void Activate();
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
                         PRInt32 aButton, PRInt32 aClickCount,
                         PRInt32 aModifiers, PRBool aIgnoreRootScrollFrame);
 
--- a/dom/ipc/jar.mn
+++ b/dom/ipc/jar.mn
@@ -1,2 +1,3 @@
 toolkit.jar:
         content/global/test-ipc.xul (test.xul)
+        content/global/remote-test-ipc.js (remote-test.js)
new file mode 100644
--- /dev/null
+++ b/dom/ipc/remote-test.js
@@ -0,0 +1,29 @@
+dump("Loading remote script!\n");
+dump(content + "\n");
+
+addEventListener("click",
+  function(e) {
+    dump(e.target + "\n");
+    if (e.target instanceof Components.interfaces.nsIDOMHTMLAnchorElement) {
+      var retval = sendSyncMessage("linkclick", { href : e.target.href });
+      dump(uneval(retval[0]) + "\n");
+      // Test here also that both retvals are the same
+      sendAsyncMessage("linkclick-reply-object", uneval(retval[0]) == uneval(retval[1]) ? retval[0] : "");
+    }
+  },
+  true);
+
+addMessageListener("chrome-message",
+  function(m) {
+    dump(uneval(m.json) + "\n");
+    sendAsyncMessage("chrome-message-reply", m.json);
+  });
+
+addMessageListener("speed-test-start",
+  function(m) {
+    while (sendSyncMessage("speed-test")[0].message != "done");
+  });
+
+addMessageListener("async-echo", function(m) {
+  sendAsyncMessage(m.name);
+});
--- a/dom/ipc/test.xul
+++ b/dom/ipc/test.xul
@@ -1,12 +1,12 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        width="800" height="800" orient="vertical">
+        width="800" height="800" orient="vertical" onload="initRemoteFrameScript();">
   <script>
 
     function dumpClientRect(r) {
       dump(r.left + "," + r.top + "," + r.right + "," +
            r.bottom + "," + r.width + "," + r.height + "\n");
     }
 
     function handleMozAfterPaint(e) {
@@ -72,23 +72,124 @@
 
     function openWindow() {
       window.open('chrome://global/content/test-ipc.xul', '_blank', 'chrome,resizable,width=800,height=800');
     }
     
     function closeWindow() {
       window.close();
     }
+
+    function initRemoteFrameScript() {
+      // 1. Test that loading a script works
+      messageManager.loadFrameScript("chrome://global/content/remote-test-ipc.js", true);
+
+      // 2. Test that adding message listener works, and that receiving a sync message works.
+      messageManager.addMessageListener("linkclick",
+        function(m) {
+          document.getElementById("messageLog").value = m.name + ": " + m.json.href;
+          return { message: "linkclick-received" };
+        });
+
+      // 3. Test that returning multiple json results works.
+      messageManager.addMessageListener("linkclick",
+        function(m) {
+          return { message: "linkclick-received" };
+        });
+
+      // 4. Test that receiving an async message works.
+      //    Test also that sending async message to content works.
+      messageManager.addMessageListener("linkclick-reply-object",
+        function(m) {
+           var s = (m.json.message == "linkclick-received") ? "PASS" : "FAIL";
+           messageManager.sendAsyncMessage("chrome-message", { ok : s } );
+        });
+
+      // 5. Final test to check that everything went ok.
+      messageManager.addMessageListener("chrome-message-reply",
+        function(m) {
+          // Check that 'this' value is handled correctly.
+          if (this == document.getElementById("page")) {
+            // Check that the message properties are enumerable.
+            var hasName = false;
+            var hasSync = false;
+            var hasJSON = false;
+            for (i in m) {
+              if (i == "name") {
+                hasName = true;
+              } else if (i == "sync") {
+                hasSync = true;
+              } else if (i == "json") {
+                hasJSON = true;
+              }
+            }
+            if (hasName &amp;&amp; hasSync &amp;&amp; hasJSON) {
+              document.getElementById("messageLog").value += ", " + m.json.ok;
+            }
+          }
+        });
+    }
+
+    var speedTestStartTime = 0;
+    var speedTestCount = 0;
+    function messageSpeed() {
+      speedTestCount = 0;
+      messageManager.addMessageListener("speed-test", speedHandler);
+      messageManager.sendAsyncMessage("speed-test-start");
+    }
+
+    function speedHandler() {
+      if (!speedTestCount) {
+        speedTestStartTime = new Date().getTime();
+      }
+      if (++speedTestCount == 1000) {
+        setTimeout("alert('" + speedTestCount + " in "  + (new Date().getTime() - speedTestStartTime) +  "ms')", 0);
+        return { message: "done" };
+      }
+      return { message: "continue" };
+    }
+
+    var addRemoveTestCount = 0;
+
+    function echoListener() {
+      if (++addRemoveTestCount == 1) {
+        alert("Expected echo message");
+        messageManager.removeMessageListener("async-echo", echoListener);
+        messageManager.sendAsyncMessage("async-echo");
+        return;
+      }
+      alert("Unexpected echo message");
+    }
+
+    function listenerAddRemove() {
+      addRemoveTestCount = 0;
+      messageManager.addMessageListener("async-echo", echoListener);
+      messageManager.sendAsyncMessage("async-echo");
+    }
   </script>
 
   <toolbar id="controls">
     <toolbarbutton label="Back"/>
     <toolbarbutton label="Forward"/>
     <textbox onchange="loadURL(this.value)" flex="1" id="URL"/>
+  </toolbar>
+  <toolbar>
     <toolbarbutton onclick="restart()" label="Recover"/>
     <toolbarbutton onclick="randomClick()" label="random click"/>
+    <toolbarbutton onclick="messageSpeed()" label="test message handling speed"/>
+    <toolbarbutton onclick="listenerAddRemove()" label="test listener add/remove"/>
     <toolbarbutton onclick="openWindow()" label="open new window"/>
     <toolbarbutton onclick="closeWindow()" label="close this window"/>
   </toolbar>
+  <toolbar><label value="Load a script (URL) to content process:"/>
+    <textbox flex="1" id="script"/><button
+      label="send" oncommand="document.getElementById('page').QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.
+                              messageManager.loadFrameScript(this.previousSibling.value, false);"/>
+  </toolbar>
+  <toolbar>
+    <label value="Eval script in chrome context"/>
+    <textbox flex="1"/><button label="run" oncommand="eval(this.previousSibling.value);"/>
+  </toolbar>
 
   <browser type="content" src="http://www.google.com/" flex="1" id="page" remote="true"
            onfocus="this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.activateRemoteFrame();"/>
+  <label id="messageLog" value="" crop="center"/>
 </window>
--- a/js/src/xpconnect/src/xpcthreadcontext.cpp
+++ b/js/src/xpconnect/src/xpcthreadcontext.cpp
@@ -117,21 +117,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