Revert the electrolysis-plugins-only branch so that the Electrolysis repository can return to its normal (plugins and tabs) state. electrolysis-not-just-plugins
authorBenjamin Smedberg <benjamin@smedbergs.us>
Mon, 14 Dec 2009 11:26:15 -0500
branchelectrolysis-not-just-plugins
changeset 36268 f80b4464d261a7ab6c6b340449dda2f7c272b511
parent 36181 683dfdc4adf03e4fd866da24f13390c938c7bf54
child 36269 f8fa55f60a969f7a5724a6b9beccbb5901dec6a4
child 50701 1bfb30cebf7daf412575e141b91562dfe9782c4d
push idunknown
push userunknown
push dateunknown
milestone1.9.3a1pre
Revert the electrolysis-plugins-only branch so that the Electrolysis repository can return to its normal (plugins and tabs) state.
.hgtags
content/base/public/nsIFrameLoader.idl
content/base/src/Makefile.in
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsGkAtomList.h
content/base/src/nsXMLHttpRequest.h
content/canvas/public/DocumentRendererChild.h
content/canvas/public/DocumentRendererParent.h
content/canvas/public/Makefile.in
content/canvas/public/nsICanvasRenderingContextInternal.h
content/canvas/src/DocumentRendererChild.cpp
content/canvas/src/DocumentRendererParent.cpp
content/canvas/src/Makefile.in
content/canvas/src/WebGLContext.h
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/events/public/nsIPrivateDOMEvent.h
content/events/src/Makefile.in
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMNotifyPaintEvent.cpp
content/events/src/nsDOMNotifyPaintEvent.h
content/events/src/nsDOMScrollAreaEvent.cpp
content/events/src/nsDOMScrollAreaEvent.h
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
dom/Makefile.in
dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
dom/ipc/ContentProcessChild.cpp
dom/ipc/ContentProcessChild.h
dom/ipc/ContentProcessParent.cpp
dom/ipc/ContentProcessParent.h
dom/ipc/ContentProcessThread.cpp
dom/ipc/ContentProcessThread.h
dom/ipc/Makefile.in
dom/ipc/PContentProcess.ipdl
dom/ipc/PDocumentRenderer.ipdl
dom/ipc/PIFrameEmbedding.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabMessageUtils.cpp
dom/ipc/TabMessageUtils.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/TabTypes.h
dom/ipc/ipdl.mk
dom/ipc/jar.mn
dom/ipc/test.xul
ipc/Makefile.in
ipc/ipdl/Makefile.in
ipc/testshell/Makefile.in
ipc/testshell/PTestShell.ipdl
ipc/testshell/PTestShellCommand.ipdl
ipc/testshell/TestShellChild.cpp
ipc/testshell/TestShellChild.h
ipc/testshell/TestShellParent.cpp
ipc/testshell/TestShellParent.h
ipc/testshell/XPCShellEnvironment.cpp
ipc/testshell/XPCShellEnvironment.h
ipc/testshell/ipdl.mk
ipc/testshell/tests/test_ipcshell.js
ipc/testshell/tests/test_ipcshell_child.js
js/src/xpconnect/shell/Makefile.in
js/src/xpconnect/shell/xpcshell.cpp
layout/generic/nsFrameFrame.cpp
layout/generic/nsIFrameFrame.h
netwerk/Makefile.in
netwerk/build.mk
netwerk/build/Makefile.in
netwerk/build/nsNetModule.cpp
netwerk/dns/src/nsIDNKitInterface.h
netwerk/ipc/Makefile.in
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
netwerk/ipc/ipdl.mk
netwerk/protocol/http/src/HttpChannelChild.cpp
netwerk/protocol/http/src/HttpChannelChild.h
netwerk/protocol/http/src/HttpChannelParent.cpp
netwerk/protocol/http/src/HttpChannelParent.h
netwerk/protocol/http/src/Makefile.in
netwerk/protocol/http/src/PHttpChannel.ipdl
netwerk/protocol/http/src/ipdl.mk
netwerk/protocol/http/src/nsHttp.h
netwerk/protocol/http/src/nsHttpChunkedDecoder.h
netwerk/protocol/http/src/nsHttpHandler.cpp
netwerk/protocol/http/src/nsHttpHeaderArray.h
netwerk/protocol/http/src/nsHttpRequestHead.h
security/manager/ssl/src/nsSmartCardEvent.cpp
security/manager/ssl/src/nsSmartCardEvent.h
toolkit/content/tests/fennec-tile-testapp/application.ini
toolkit/content/tests/fennec-tile-testapp/chrome/chrome.manifest
toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js
toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js
toolkit/content/tests/fennec-tile-testapp/chrome/content/TileManager.js
toolkit/content/tests/fennec-tile-testapp/chrome/content/WidgetStack.js
toolkit/content/tests/fennec-tile-testapp/chrome/content/firefoxOverlay.xul
toolkit/content/tests/fennec-tile-testapp/chrome/content/foo.xul
toolkit/content/tests/fennec-tile-testapp/chrome/content/main.xul
toolkit/content/tests/fennec-tile-testapp/chrome/content/overlay.js
toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.dtd
toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.properties
toolkit/content/tests/fennec-tile-testapp/chrome/skin/overlay.css
toolkit/content/tests/fennec-tile-testapp/defaults/preferences/prefs.js
toolkit/content/tests/fennec-tile-testapp/install.rdf
toolkit/content/tests/fennec-tile-testapp/logread.py
toolkit/library/dlldeps-xul.cpp
toolkit/library/libxul-config.mk
toolkit/xre/nsEmbedFunctions.cpp
--- a/.hgtags
+++ b/.hgtags
@@ -30,8 +30,16 @@ 8a601ed6bc4c7b3d1e35aa9e81f257512d984bd5
 d7d64f68423b68a671f623f123e90057ebc49dac UPDATE_PACKAGING_R7
 fb32f6e1859c07846a01b4478a7b1678019e0b45 UPDATE_PACKAGING_R7
 f817a4378f32b1ad0a7c4b5a9949586dba816da5 FENNEC_M11
 5c1e7c779b6edc8ff912001990edc579f80597f4 FENNEC_B1
 fe9cc55b8db7f56f7e68a246acba363743854979 UPDATE_PACKAGING_R8
 6fd4bb500d425c406c1b52f66e5b195b20ae5e0a chromium-import-r15462
 6fd4bb500d425c406c1b52f66e5b195b20ae5e0a chromium-import-latest
 376b78fc72230aaf2ca4e279a8f4ef1efd4a1d9f GECKO_1_9_2_BASE
+941ad9d7d079246481f365c3cfbfc75a5bbefc94 last-mozilla-central
+2bae3bbf866e7de2a4b2377e7c2f52cc9ac14a22 last-mozilla-central
+2bae3bbf866e7de2a4b2377e7c2f52cc9ac14a22 last-mozilla-central
+65c1582465efe99899189519fccaf7b2826fcb2e last-mozilla-central
+65c1582465efe99899189519fccaf7b2826fcb2e last-mozilla-central
+27937722da69ad0e8fd140a00671413068226a5b last-mozilla-central
+27937722da69ad0e8fd140a00671413068226a5b last-mozilla-central
+a732c6d3c078f80635255c78bfaadffa5828a8a5 last-mozilla-central
--- 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 nsIFrame;
 
-[scriptable, uuid(d675c531-6bdc-417c-b176-635060105f07)]
+[scriptable, uuid(8f94788d-ec69-4220-971c-0fd68d47b80f)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -69,16 +70,45 @@ 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;
+
+  /**
+   * Updates the position and size of the subdocument loaded by this frameloader.
+   *
+   *  @param aIFrame The nsIFrame for the content node that owns this frameloader
+   */
+  [noscript] void updatePositionAndSize(in nsIFrame aIFrame);
+
+  /**
+   * Activate remote frame.
+   * Throws an exception with non-remote frames.
+   */
+  void activateRemoteFrame();
+
+  /**
+   * @see nsIDOMWindowUtils sendMouseEvent.
+   */
+  void sendCrossProcessMouseEvent(in AString aType,
+                                  in float aX,
+                                  in float aY,
+                                  in long aButton,
+                                  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);
 };
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
 [scriptable, uuid(8f3b12a0-35ae-4e0d-9152-8e0d7e49d446)]
 interface nsIFrameLoaderOwner : nsISupports
 {
   /**
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -138,26 +138,29 @@ CPPSRCS		= \
 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
 
 EXTRA_COMPONENTS = $(srcdir)/nsBadCertHandler.js
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(srcdir)/../../events/src \
 		-I$(srcdir)/../../xml/content/src \
 		-I$(srcdir)/../../../layout/xul/base/src \
 		-I$(srcdir)/../../xul/content/src \
 		-I$(srcdir)/../../html/content/src \
 		-I$(srcdir)/../../base/src \
 		-I$(srcdir)/../../xbl/src \
 		-I$(srcdir)/../../../layout/generic \
 		-I$(srcdir)/../../../layout/style \
 		-I$(srcdir)/../../../dom/base \
 		-I$(srcdir)/../../xml/document/src \
 		-I$(topsrcdir)/xpcom/io \
+		-I$(topsrcdir)/dom/ipc \
 		$(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -18,16 +18,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Johnny Stenback <jst@netscape.com> (original author)
  *   Boris Zbarsky <bzbarsky@mit.edu>
+ *   Frederic Plourde <frederic.plourde@polymtl.ca>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * 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
@@ -38,16 +39,22 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * Class for managing loading of a subframe (creation of the docshell,
  * handling of loads in it, recursion-checking).
  */
 
+#ifdef MOZ_IPC
+#  include "base/basictypes.h"
+#endif
+
+#include "prenv.h"
+
 #include "nsIDOMHTMLIFrameElement.h"
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMWindow.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIContent.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
@@ -72,28 +79,44 @@
 #include "nsIFrameFrame.h"
 #include "nsDOMError.h"
 #include "nsPresShellIterator.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsISHistory.h"
 #include "nsISHistoryInternal.h"
 #include "nsIDOMNSHTMLDocument.h"
-#include "nsIView.h"
+#include "nsLayoutUtils.h"
 
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 
 #include "nsGkAtoms.h"
 #include "nsINameSpaceManager.h"
 
 #include "nsThreadUtils.h"
 #include "nsICSSStyleSheet.h"
 #include "nsIContentViewer.h"
+#include "nsIView.h"
+
+#ifdef MOZ_WIDGET_GTK2
+#include "mozcontainer.h"
+
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#endif
+
+#ifdef MOZ_IPC
+#include "ContentProcessParent.h"
+#include "TabParent.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+#endif
 
 class nsAsyncDocShellDestroyer : public nsRunnable
 {
 public:
   nsAsyncDocShellDestroyer(nsIDocShell* aDocShell)
     : mDocShell(aDocShell)
   {
   }
@@ -207,21 +230,44 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
   }
   return rv;
 }
 
 nsresult
 nsFrameLoader::ReallyStartLoading()
 {
   NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc());
+
+  nsresult rv = MaybeCreateDocShell();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+#ifdef MOZ_IPC
+  if (mRemoteFrame) {
+    if (!mChildProcess) {
+      TryNewProcess();
+    }
+
+    if (!mChildProcess) {
+      NS_WARNING("Couldn't create child process for iframe.");
+      return NS_ERROR_FAILURE;
+    }
+
+    // FIXME get error codes from child
+    mChildProcess->LoadURL(mURIToLoad);
+    return NS_OK;
+  }
+#endif
+
+  NS_ASSERTION(mDocShell,
+               "MaybeCreateDocShell succeeded with a null mDocShell");
+
   // Just to be safe, recheck uri.
-  nsresult rv = CheckURILoad(mURIToLoad);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = EnsureDocShell();
+  rv = CheckURILoad(mURIToLoad);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
 
   // We'll use our principal, not that of the document loaded inside us.  This
   // is very important; needed to prevent XSS attacks on documents loaded in
@@ -275,30 +321,48 @@ nsFrameLoader::CheckURILoad(nsIURI* aURI
   nsresult rv =
     secMan->CheckLoadURIWithPrincipal(principal, aURI,
                                       nsIScriptSecurityManager::STANDARD);
   if (NS_FAILED(rv)) {
     return rv; // We're not
   }
 
   // Bail out if this is an infinite recursion scenario
+  rv = MaybeCreateDocShell();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+#ifdef MOZ_IPC
+  if (mRemoteFrame) {
+    return NS_OK;
+  }
+#endif
   return CheckForRecursiveLoad(aURI);
 }
 
 NS_IMETHODIMP
 nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
 {
   *aDocShell = nsnull;
 
   // If we have an owner, make sure we have a docshell and return
   // that. If not, we're most likely in the middle of being torn down,
   // then we just return null.
   if (mOwnerContent) {
-    nsresult rv = EnsureDocShell();
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsresult rv = MaybeCreateDocShell();
+    if (NS_FAILED(rv))
+      return rv;
+#ifdef MOZ_IPC
+    if (mRemoteFrame) {
+      NS_WARNING("No docshells for remote frames!");
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+#endif
+    NS_ASSERTION(mDocShell,
+                 "MaybeCreateDocShell succeeded, but null mDocShell");
   }
 
   *aDocShell = mDocShell;
   NS_IF_ADDREF(*aDocShell);
 
   return NS_OK;
 }
 
@@ -475,73 +539,88 @@ AllDescendantsOfType(nsIDocShellTreeItem
 
 bool
 nsFrameLoader::Show(PRInt32 marginWidth, PRInt32 marginHeight,
                     PRInt32 scrollbarPrefX, PRInt32 scrollbarPrefY,
                     nsIFrameFrame* frame)
 {
   nsContentType contentType;
 
-  nsresult rv = EnsureDocShell();
+  nsresult rv = MaybeCreateDocShell();
   if (NS_FAILED(rv)) {
     return false;
   }
 
-  if (!mDocShell)
-    return false;
-
-  nsCOMPtr<nsIPresShell> presShell;
-  mDocShell->GetPresShell(getter_AddRefs(presShell));
-  if (presShell)
-    return true;
+#ifdef MOZ_IPC
+  if (mRemoteFrame) {
+    contentType = eContentTypeUI;
+  }
+  else
+#endif
+  {
+    if (!mDocShell)
+      return false;
 
-  mDocShell->SetMarginWidth(marginWidth);
-  mDocShell->SetMarginHeight(marginHeight);
+    nsCOMPtr<nsIPresShell> presShell;
+    mDocShell->GetPresShell(getter_AddRefs(presShell));
+    if (presShell)
+      return true;
+
+    mDocShell->SetMarginWidth(marginWidth);
+    mDocShell->SetMarginHeight(marginHeight);
 
-  nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
-  if (sc) {
-    sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
-                                       scrollbarPrefX);
-    sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
-                                       scrollbarPrefY);
-  }
+    nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
+    if (sc) {
+      sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
+                                         scrollbarPrefX);
+      sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
+                                         scrollbarPrefY);
+    }
 
 
-  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
-  NS_ASSERTION(treeItem,
-               "Found a nsIDocShell that isn't a nsIDocShellTreeItem.");
+    nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
+    NS_ASSERTION(treeItem,
+                 "Found a nsIDocShell that isn't a nsIDocShellTreeItem.");
 
-  PRInt32 itemType;
-  treeItem->GetItemType(&itemType);
+    PRInt32 itemType;
+    treeItem->GetItemType(&itemType);
 
-  if (itemType == nsIDocShellTreeItem::typeChrome)
-    contentType = eContentTypeUI;
-  else {
-    nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
-    treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
-    contentType = sameTypeParent ? eContentTypeContentFrame : eContentTypeContent;
+    if (itemType == nsIDocShellTreeItem::typeChrome)
+      contentType = eContentTypeUI;
+    else {
+      nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
+      treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
+      contentType = sameTypeParent ? eContentTypeContentFrame : eContentTypeContent;
+    }
   }
 
   nsIView* view = frame->CreateViewAndWidget(contentType);
   if (!view)
     return false;
 
+#ifdef MOZ_IPC
+  if (mRemoteFrame) {
+    return ShowRemoteFrame(frame, view);
+  }
+#endif
+
   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
   NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
   baseWindow->InitWindow(nsnull, view->GetWidget(), 0, 0, 10, 10);
   // This is kinda whacky, this "Create()" call doesn't really
   // create anything, one starts to wonder why this was named
   // "Create"...
   baseWindow->Create();
   baseWindow->SetVisibility(PR_TRUE);
 
   // Trigger editor re-initialization if midas is turned on in the
   // sub-document. This shouldn't be necessary, but given the way our
   // editor works, it is. See
   // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
+  nsCOMPtr<nsIPresShell> presShell;
   mDocShell->GetPresShell(getter_AddRefs(presShell));
   if (presShell) {
     nsCOMPtr<nsIDOMNSHTMLDocument> doc =
       do_QueryInterface(presShell->GetDocument());
 
     if (doc) {
       nsAutoString designMode;
       doc->GetDesignMode(designMode);
@@ -551,16 +630,77 @@ nsFrameLoader::Show(PRInt32 marginWidth,
         doc->SetDesignMode(NS_LITERAL_STRING("on"));
       }
     }
   }
 
   return true;
 }
 
+#ifdef MOZ_IPC
+bool
+nsFrameLoader::ShowRemoteFrame(nsIFrameFrame* frame, nsIView* view)
+{
+  NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
+
+  TryNewProcess();
+  if (!mChildProcess) {
+    NS_ERROR("Couldn't create child process.");
+    return false;
+  }
+
+  nsIWidget* w = view->GetWidget();
+  if (!w) {
+    NS_ERROR("Our view doesn't have a widget. Totally stuffed!");
+    return false;
+  }
+
+  nsIntSize size = GetSubDocumentSize(frame->GetFrame());
+
+#ifdef XP_WIN
+  HWND parentwin =
+    static_cast<HWND>(w->GetNativeData(NS_NATIVE_WINDOW));
+
+  mChildProcess->SendcreateWidget(parentwin);
+#elif defined(MOZ_WIDGET_GTK2)
+  GdkWindow* parent_win =
+    static_cast<GdkWindow*>(w->GetNativeData(NS_NATIVE_WINDOW));
+
+  gpointer user_data = nsnull;
+  gdk_window_get_user_data(parent_win, &user_data);
+
+  MozContainer* parentMozContainer = MOZ_CONTAINER(user_data);
+  GtkContainer* container = GTK_CONTAINER(parentMozContainer);
+
+  // create the socket for the child and add it to our view's widget
+  mRemoteSocket = gtk_socket_new();
+  gtk_widget_set_parent_window(mRemoteSocket, parent_win);
+  gtk_container_add(container, mRemoteSocket);
+  gtk_widget_realize(mRemoteSocket);
+
+  // set the child window's size and position
+  GtkAllocation alloc = { 0, 0, size.width, size.height };
+  gtk_widget_size_allocate(mRemoteSocket, &alloc);
+
+  gtk_widget_show(mRemoteSocket);
+  GdkNativeWindow id = gtk_socket_get_id(GTK_SOCKET(mRemoteSocket));
+  mChildProcess->SendcreateWidget(id);
+#elif defined(XP_MACOSX)
+#  warning IMPLEMENT ME
+
+#else
+#error TODO for this platform
+#endif
+
+  mChildProcess->Move(0, 0, size.width, size.height);
+
+  return true;
+}
+#endif
+
 void
 nsFrameLoader::Hide()
 {
   if (!mDocShell)
     return;
 
   nsCOMPtr<nsIContentViewer> contentViewer;
   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
@@ -854,30 +994,37 @@ nsFrameLoader::Destroy()
     doc = mOwnerContent->GetOwnerDoc();
 
     if (doc) {
       doc->SetSubDocumentFor(mOwnerContent, nsnull);
     }
 
     mOwnerContent = nsnull;
   }
+#ifdef MOZ_IPC
+  if (mChildProcess) {
+    mChildProcess->SetOwnerElement(nsnull);
+    PIFrameEmbeddingParent::Send__delete__(mChildProcess);
+    mChildProcess = nsnull;
+  }
+#endif
 
   // Let the tree owner know we're gone.
   if (mIsTopLevelContent) {
     nsCOMPtr<nsIDocShellTreeItem> ourItem = do_QueryInterface(mDocShell);
     if (ourItem) {
       nsCOMPtr<nsIDocShellTreeItem> parentItem;
       ourItem->GetParent(getter_AddRefs(parentItem));
       nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
       if (owner) {
         owner->ContentShellRemoved(ourItem);
       }
     }
   }
-  
+
   // Let our window know that we are gone
   nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
   if (win_private) {
     win_private->SetFrameElementInternal(nsnull);
   }
 
   if ((mNeedsAsyncDestroy || !doc ||
        NS_FAILED(doc->FinalizeFrameLoader(this))) && mDocShell) {
@@ -898,24 +1045,74 @@ nsFrameLoader::Destroy()
 
 NS_IMETHODIMP
 nsFrameLoader::GetDepthTooGreat(PRBool* aDepthTooGreat)
 {
   *aDepthTooGreat = mDepthTooGreat;
   return NS_OK;
 }
 
+#ifdef MOZ_IPC
+bool
+nsFrameLoader::ShouldUseRemoteProcess()
+{
+  // Check for *disabled* multi-process first: environment, prefs, attribute
+  // Then check for *enabled* multi-process pref: attribute, prefs
+  // Default is not-remote.
+
+  if (PR_GetEnv("MOZ_DISABLE_OOP_TABS")) {
+    return false;
+  }
+
+  PRBool remoteDisabled = nsContentUtils::GetBoolPref("dom.ipc.tabs.disabled",
+                                                      PR_FALSE);
+  if (remoteDisabled) {
+    return false;
+  }
+
+  static nsIAtom* const *const remoteValues[] = {
+    &nsGkAtoms::_false,
+    &nsGkAtoms::_true,
+    nsnull
+  };
+
+  switch (mOwnerContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::Remote,
+                                         remoteValues, eCaseMatters)) {
+  case 0:
+    return false;
+  case 1:
+    return true;
+  }
+
+  PRBool remoteEnabled = nsContentUtils::GetBoolPref("dom.ipc.tabs.enabled",
+                                                     PR_FALSE);
+  return (bool) remoteEnabled;
+}
+#endif
+
 nsresult
-nsFrameLoader::EnsureDocShell()
+nsFrameLoader::MaybeCreateDocShell()
 {
   if (mDocShell) {
     return NS_OK;
   }
+#ifdef MOZ_IPC
+  if (mRemoteFrame) {
+    return NS_OK;
+  }
+#endif
   NS_ENSURE_STATE(!mDestroyCalled);
 
+#ifdef MOZ_IPC
+  if (ShouldUseRemoteProcess()) {
+    mRemoteFrame = true;
+    return NS_OK;
+  }
+#endif
+
   // Get our parent docshell off the document of mOwnerContent
   // XXXbz this is such a total hack.... We really need to have a
   // better setup for doing this.
   nsIDocument* doc = mOwnerContent->GetOwnerDoc();
   if (!doc || !(doc->IsStaticDocument() || mOwnerContent->IsInDoc())) {
     return NS_ERROR_UNEXPECTED;
   }
 
@@ -930,16 +1127,17 @@ nsFrameLoader::EnsureDocShell()
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   // Get the frame name and tell the docshell about it.
   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
   NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
+
   nsAutoString frameName;
 
   PRInt32 namespaceID = mOwnerContent->GetNameSpaceID();
   if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
   } else {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
     // XXX if no NAME then use ID, after a transition period this will be
@@ -1036,19 +1234,30 @@ nsFrameLoader::GetURL(nsString& aURI)
   } else {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI);
   }
 }
 
 nsresult
 nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
 {
+  nsresult rv;
+
   mDepthTooGreat = PR_FALSE;
-  nsresult rv = EnsureDocShell();
-  NS_ENSURE_SUCCESS(rv, rv);
+  rv = MaybeCreateDocShell();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+#ifdef MOZ_IPC
+  NS_ASSERTION(!mRemoteFrame,
+               "Shouldn't call CheckForRecursiveLoad on remote frames.");
+#endif
+  if (!mDocShell) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
   NS_ASSERTION(treeItem, "docshell must be a treeitem!");
   
   PRInt32 ourType;
   rv = treeItem->GetItemType(&ourType);
   if (NS_SUCCEEDED(rv) && ourType != nsIDocShellTreeItem::typeContent) {
     // No need to do recursion-protection here XXXbz why not??  Do we really
@@ -1124,21 +1333,196 @@ nsFrameLoader::CheckForRecursiveLoad(nsI
     nsCOMPtr<nsIDocShellTreeItem> temp;
     temp.swap(parentAsItem);
     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::UpdatePositionAndSize(nsIFrame *aIFrame)
+{
+#ifdef MOZ_IPC
+  if (mRemoteFrame) {
+    if (mChildProcess) {
+      nsIntSize size = GetSubDocumentSize(aIFrame);
+
+#ifdef MOZ_WIDGET_GTK2
+      if (mRemoteSocket) {
+        GtkAllocation alloc = {0, 0, size.width, size.height };
+        gtk_widget_size_allocate(mRemoteSocket, &alloc);
+      }
+#endif
+
+      mChildProcess->Move(0, 0, size.width, size.height);
+    }
+    return NS_OK;
+  }
+#endif
+  return UpdateBaseWindowPositionAndSize(aIFrame);
+}
+
+nsresult
+nsFrameLoader::UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame)
+{
+  nsCOMPtr<nsIDocShell> docShell;
+  GetDocShell(getter_AddRefs(docShell));
+  nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
+
+  // resize the sub document
+  if (baseWindow) {
+    PRInt32 x = 0;
+    PRInt32 y = 0;
+
+    nsWeakFrame weakFrame(aIFrame);
+
+    baseWindow->GetPositionAndSize(&x, &y, nsnull, nsnull);
+
+    if (!weakFrame.IsAlive()) {
+      // GetPositionAndSize() killed us
+      return NS_OK;
+    }
+
+    nsIntSize size = GetSubDocumentSize(aIFrame);
+
+    baseWindow->SetPositionAndSize(x, y, size.width, size.height, PR_FALSE);
+  }
+
+  return NS_OK;
+}
+
+nsIntSize
+nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
+{
+  nsAutoDisableGetUsedXAssertions disableAssert;
+  nsSize docSizeAppUnits;
+  nsPresContext* presContext = aIFrame->PresContext();
+  nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = 
+    do_QueryInterface(aIFrame->GetContent());
+  if (frameElem) {
+    docSizeAppUnits = aIFrame->GetSize();
+  } else {
+    docSizeAppUnits = aIFrame->GetContentRect().Size();
+  }
+  return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
+                   presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
+}
+
+#ifdef MOZ_IPC
+bool
+nsFrameLoader::TryNewProcess()
+{
+  NS_ASSERTION(!mChildProcess, "TryNewProcess called with a process already?");
+
+  nsIDocument* doc = mOwnerContent->GetDocument();
+  if (!doc) {
+    return false;
+  }
+
+  if (doc->GetDisplayDocument()) {
+    // Don't allow subframe loads in external reference documents
+    return false;
+  }
+
+  nsCOMPtr<nsIWebNavigation> parentAsWebNav =
+    do_GetInterface(doc->GetScriptGlobalObject());
+
+  if (!parentAsWebNav) {
+    return false;
+  }
+
+  nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
+
+  PRInt32 parentType;
+  parentAsItem->GetItemType(&parentType);
+
+  if (parentType != nsIDocShellTreeItem::typeChrome) {
+    return false;
+  }
+
+  if (!mOwnerContent->IsXUL()) {
+    return false;
+  }
+
+  nsAutoString value;
+  mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
+
+  if (!value.LowerCaseEqualsLiteral("content") &&
+      !StringBeginsWith(value, NS_LITERAL_STRING("content-"),
+                        nsCaseInsensitiveStringComparator())) {
+    return false;
+  }
+
+  mChildProcess = ContentProcessParent::GetSingleton()->CreateTab();
+  if (mChildProcess) {
+    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
+    mChildProcess->SetOwnerElement(element);
+  }
+  return true;
+}
+#endif
+
+#ifdef MOZ_IPC
+mozilla::dom::PIFrameEmbeddingParent*
+nsFrameLoader::GetChildProcess()
+{
+  return mChildProcess;
+}
+#endif
+
+NS_IMETHODIMP
+nsFrameLoader::ActivateRemoteFrame() {
+#ifdef MOZ_IPC
+  if (mChildProcess) {
+    mChildProcess->Activate();
+    return NS_OK;
+  }
+#endif
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
+                                          float aX,
+                                          float aY,
+                                          PRInt32 aButton,
+                                          PRInt32 aClickCount,
+                                          PRInt32 aModifiers,
+                                          PRBool aIgnoreRootScrollFrame)
+{
+#ifdef MOZ_IPC
+  if (mChildProcess) {
+    mChildProcess->SendMouseEvent(aType, aX, aY, aButton,
+                                  aClickCount, aModifiers,
+                                  aIgnoreRootScrollFrame);
+    return NS_OK;
+  }
+#endif
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsFrameLoader::ActivateFrameEvent(const nsAString& aType,
+                                  PRBool aCapture)
+{
+#ifdef MOZ_IPC
+  if (mChildProcess) {
+    mChildProcess->SendactivateFrameEvent(nsString(aType), aCapture);
+    return NS_OK;
+  }
+#endif
+  return NS_ERROR_FAILURE;
+}
+
 nsresult
 nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
 {
   nsFrameLoader* dest = static_cast<nsFrameLoader*>(aDest);
-  dest->EnsureDocShell();
+  dest->MaybeCreateDocShell();
   NS_ENSURE_STATE(dest->mDocShell);
 
   nsCOMPtr<nsIDOMDocument> dummy = do_GetInterface(dest->mDocShell);
   nsCOMPtr<nsIContentViewer> viewer;
   dest->mDocShell->GetContentViewer(getter_AddRefs(viewer));
   NS_ENSURE_STATE(viewer);
 
   nsCOMPtr<nsIDocShell> origDocShell;
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -42,32 +42,55 @@
  */
 
 #ifndef nsFrameLoader_h_
 #define nsFrameLoader_h_
 
 #include "nsIDocShell.h"
 #include "nsStringFwd.h"
 #include "nsIFrameLoader.h"
+#include "nsSize.h"
 #include "nsIURI.h"
+#include "nsAutoPtr.h"
 
 class nsIContent;
 class nsIURI;
 class nsIFrameFrame;
+class nsIView;
+
+#ifdef MOZ_IPC
+namespace mozilla {
+  namespace dom {
+    class TabParent;
+    class PIFrameEmbeddingParent;
+  }
+}
+
+#ifdef MOZ_WIDGET_GTK2
+typedef struct _GtkWidget GtkWidget;
+#endif
+#endif
 
 class nsFrameLoader : public nsIFrameLoader
 {
 protected:
   nsFrameLoader(nsIContent *aOwner) :
     mOwnerContent(aOwner),
     mDepthTooGreat(PR_FALSE),
     mIsTopLevelContent(PR_FALSE),
     mDestroyCalled(PR_FALSE),
     mNeedsAsyncDestroy(PR_FALSE),
     mInSwap(PR_FALSE)
+#ifdef MOZ_IPC
+    , mRemoteFrame(false)
+    , mChildProcess(nsnull)
+#ifdef MOZ_WIDGET_GTK2
+    , mRemoteSocket(nsnull)
+#endif
+#endif
   {}
 
 public:
   ~nsFrameLoader() {
     mNeedsAsyncDestroy = PR_TRUE;
     nsFrameLoader::Destroy();
   }
 
@@ -101,25 +124,64 @@ public:
   nsresult CloneForStatic(nsIFrameLoader* aOriginal);
 
   // The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation.  A
   // frame loader owner needs to call this, and pass in the two references to
   // nsRefPtrs for frame loaders that need to be swapped.
   nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
                                nsRefPtr<nsFrameLoader>& aFirstToSwap,
                                nsRefPtr<nsFrameLoader>& aSecondToSwap);
+
+#ifdef MOZ_IPC
+  mozilla::dom::PIFrameEmbeddingParent* GetChildProcess();
+#endif
+
 private:
 
-  NS_HIDDEN_(nsresult) EnsureDocShell();
-  NS_HIDDEN_(void) GetURL(nsString& aURL);
+#ifdef MOZ_IPC
+  bool ShouldUseRemoteProcess();
+#endif
+
+  /**
+   * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
+   * initialize mDocShell.
+   */
+  nsresult MaybeCreateDocShell();
+  void GetURL(nsString& aURL);
+
+  // Properly retrieves documentSize of any subdocument type.
+  NS_HIDDEN_(nsIntSize) GetSubDocumentSize(const nsIFrame *aIFrame);
+
+  // Updates the subdocument position and size. This gets called only
+  // when we have our own in-process DocShell.
+  NS_HIDDEN_(nsresult) UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame);
   nsresult CheckURILoad(nsIURI* aURI);
 
+#ifdef MOZ_IPC
+  // True means new process started; nothing else to do
+  bool TryNewProcess();
+
+  // Do the hookup necessary to actually show a remote frame once the view and
+  // widget are available.
+  bool ShowRemoteFrame(nsIFrameFrame* frame, nsIView* view);
+#endif
+
   nsCOMPtr<nsIDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURIToLoad;
   nsIContent *mOwnerContent; // WEAK
   PRPackedBool mDepthTooGreat : 1;
   PRPackedBool mIsTopLevelContent : 1;
   PRPackedBool mDestroyCalled : 1;
   PRPackedBool mNeedsAsyncDestroy : 1;
   PRPackedBool mInSwap : 1;
+
+#ifdef MOZ_IPC
+  bool mRemoteFrame;
+  // XXX leaking
+  mozilla::dom::TabParent* mChildProcess;
+
+#ifdef MOZ_WIDGET_GTK2
+  GtkWidget* mRemoteSocket;
+#endif
+#endif
 };
 
 #endif
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1693,16 +1693,19 @@ GK_ATOM(Taiwanese, "zh-TW")
 GK_ATOM(HongKongChinese, "zh-HK")
 GK_ATOM(Unicode, "x-unicode")
 
 // Names for editor transactions
 GK_ATOM(TypingTxnName, "Typing")
 GK_ATOM(IMETxnName, "IME")
 GK_ATOM(DeleteTxnName, "Deleting")
 
+// IPC stuff
+GK_ATOM(Remote, "remote")
+
 // Names for system metrics
 GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward")
 GK_ATOM(scrollbar_start_forward, "scrollbar-start-forward")
 GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
 GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward")
 GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional")
 GK_ATOM(images_in_menus, "images-in-menus")
 GK_ATOM(images_in_buttons, "images-in-buttons")
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -481,16 +481,25 @@ public:
   NS_IMETHOD_(nsEvent*) GetInternalNSEvent()
   {
     return mInner->GetInternalNSEvent();
   }
   NS_IMETHOD SetTrusted(PRBool aTrusted)
   {
     return mInner->SetTrusted(aTrusted);
   }
+  virtual void Serialize(IPC::Message* aMsg,
+                         PRBool aSerializeInterfaceType)
+  {
+    mInner->Serialize(aMsg, aSerializeInterfaceType);
+  }
+  virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter)
+  {
+    return mInner->Deserialize(aMsg, aIter);
+  }
 
 protected:
   // Use nsDOMProgressEvent so that we can forward
   // most of the method calls easily.
   nsRefPtr<nsDOMProgressEvent> mInner;
   PRUint64 mCurProgress;
   PRUint64 mMaxProgress;
 };
new file mode 100644
--- /dev/null
+++ b/content/canvas/public/DocumentRendererChild.h
@@ -0,0 +1,68 @@
+/* ***** 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 Fennec Electrolysis.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 mozilla_dom_DocumentRendererChild
+#define mozilla_dom_DocumentRendererChild
+
+#include "mozilla/ipc/PDocumentRendererChild.h"
+#include "nsICanvasRenderingContextInternal.h"
+#include "nsString.h"
+#include "gfxContext.h"
+
+class nsIDOMWindow;
+
+namespace mozilla {
+namespace ipc {
+
+class DocumentRendererChild : public PDocumentRendererChild
+{
+public:
+    DocumentRendererChild();
+    virtual ~DocumentRendererChild();
+    
+    bool RenderDocument(nsIDOMWindow *window, const PRInt32& x, const PRInt32& y, const PRInt32& w, const PRInt32& h,
+			    const nsString& bgcolor, const PRUint32& flags, const PRBool& flush, 
+			    PRUint32& _width, PRUint32& _height, nsCString& data);
+
+private:
+
+    DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererChild);
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/canvas/public/DocumentRendererParent.h
@@ -0,0 +1,73 @@
+/* ***** 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 Fennec Electrolysis.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 mozilla_dom_DocumentRendererParent
+#define mozilla_dom_DocumentRendererParent
+
+#include "mozilla/ipc/PDocumentRendererParent.h"
+#include "nsICanvasRenderingContextInternal.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "gfxContext.h"
+
+namespace mozilla {
+namespace ipc {
+
+class DocumentRendererParent : public PDocumentRendererParent
+{
+public:
+    DocumentRendererParent();
+    virtual ~DocumentRendererParent();
+
+    void SetCanvasContext(nsICanvasRenderingContextInternal* aCanvas,
+			  gfxContext* ctx);
+    void DrawToCanvas(PRUint32 aWidth, PRUint32 aHeight,
+		      const nsCString& aData);
+
+    virtual bool Recv__delete__(const PRUint32& w, const PRUint32& h,
+                                const nsCString& data);
+
+private:
+    nsCOMPtr<nsICanvasRenderingContextInternal> mCanvas;
+    nsRefPtr<gfxContext> mCanvasContext;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererParent);
+};
+
+}
+}
+
+#endif
--- a/content/canvas/public/Makefile.in
+++ b/content/canvas/public/Makefile.in
@@ -40,19 +40,26 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
 XPIDL_MODULE = content_canvas
 
+EXPORTS_NAMESPACES = mozilla/ipc
+
 EXPORTS		= \
 		nsICanvasRenderingContextInternal.h \
 		nsICanvasElement.h \
 		WebGLArray.h \
 		$(NULL)
 
+EXPORTS_mozilla/ipc = \
+		DocumentRendererChild.h \
+		DocumentRendererParent.h \
+		$(NULL)
+
 XPIDLSRCS	= \
 		nsICanvasGLPrivate.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -82,14 +82,17 @@ public:
   // return the surface.  Otherwise returns an error.
   NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0;
 
   // If this context is opaque, the backing store of the canvas should
   // be created as opaque; all compositing operators should assume the
   // dst alpha is always 1.0.  If this is never called, the context
   // defaults to false (not opaque).
   NS_IMETHOD SetIsOpaque(PRBool isOpaque) = 0;
+
+  // Redraw the dirty rectangle of this canvas.
+  NS_IMETHOD Redraw(const gfxRect &dirty) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,
                               NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
 
 #endif /* nsICanvasRenderingContextInternal_h___ */
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/DocumentRendererChild.cpp
@@ -0,0 +1,147 @@
+/* ***** 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 Fennec Electrolysis.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 "base/basictypes.h"
+
+#include "gfxImageSurface.h"
+#include "gfxPattern.h"
+#include "nsPIDOMWindow.h"
+#include "nsIDOMWindow.h"
+#include "nsIDOMDocument.h"
+#include "nsIDocShellTreeNode.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsIDocument.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsICSSParser.h"
+#include "nsPresContext.h"
+#include "nsCOMPtr.h"
+#include "nsColor.h"
+#include "gfxContext.h"
+#include "gfxImageSurface.h"
+#include "nsLayoutUtils.h"
+
+#include "mozilla/ipc/DocumentRendererChild.h"
+
+using namespace mozilla::ipc;
+
+DocumentRendererChild::DocumentRendererChild()
+{}
+
+DocumentRendererChild::~DocumentRendererChild()
+{}
+
+static void
+FlushLayoutForTree(nsIDOMWindow* aWindow)
+{
+    nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
+    if (!piWin)
+        return;
+
+    // Note that because FlushPendingNotifications flushes parents, this
+    // is O(N^2) in docshell tree depth.  However, the docshell tree is
+    // usually pretty shallow.
+
+    nsCOMPtr<nsIDOMDocument> domDoc;
+    aWindow->GetDocument(getter_AddRefs(domDoc));
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+    if (doc) {
+        doc->FlushPendingNotifications(Flush_Layout);
+    }
+
+    nsCOMPtr<nsIDocShellTreeNode> node =
+        do_QueryInterface(piWin->GetDocShell());
+    if (node) {
+        PRInt32 i = 0, i_end;
+        node->GetChildCount(&i_end);
+        for (; i < i_end; ++i) {
+            nsCOMPtr<nsIDocShellTreeItem> item;
+            node->GetChildAt(i, getter_AddRefs(item));
+            nsCOMPtr<nsIDOMWindow> win = do_GetInterface(item);
+            if (win) {
+                FlushLayoutForTree(win);
+            }
+        }
+    }
+}
+
+bool
+DocumentRendererChild::RenderDocument(nsIDOMWindow *window, const PRInt32& x, const PRInt32& y, const PRInt32& w, const PRInt32& h,
+                                      const nsString& aBGColor, const PRUint32& flags, const PRBool& flush, 
+                                      PRUint32& _width, PRUint32& _height, nsCString& data)
+{
+    if (flush)
+        FlushLayoutForTree(window);
+
+    nsCOMPtr<nsPresContext> presContext;
+    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
+    if (win) {
+        nsIDocShell* docshell = win->GetDocShell();
+        if (docshell) {
+            docshell->GetPresContext(getter_AddRefs(presContext));
+        }
+    }
+    if (!presContext)
+        return false;
+
+    nscolor bgColor;
+    nsCOMPtr<nsICSSParser> parser = do_CreateInstance("@mozilla.org/content/css-parser;1");
+    nsresult rv = parser->ParseColorString(PromiseFlatString(aBGColor),
+                                           nsnull, 0, &bgColor);
+    if (NS_FAILED(rv))
+        return false;
+
+    nsIPresShell* presShell = presContext->PresShell();
+
+    nsRect r(x, y, w, h);
+
+    _width = nsPresContext::AppUnitsToIntCSSPixels(w);
+    _height = nsPresContext::AppUnitsToIntCSSPixels(h);
+
+    // Draw directly into the output array.
+    data.SetLength(_width * _height * 4);
+    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(reinterpret_cast<PRUint8*>(const_cast<char*>(data.get())),
+                                                         gfxIntSize(_width, _height),
+                                                         4 * _width, gfxASurface::ImageFormatARGB32);
+    nsRefPtr<gfxContext> ctx = new gfxContext(surf);
+
+    PRBool oldDisableValue = nsLayoutUtils::sDisableGetUsedXAssertions;
+    nsLayoutUtils::sDisableGetUsedXAssertions = oldDisableValue || !flush;
+    presShell->RenderDocument(r, flags, bgColor, ctx);
+    nsLayoutUtils::sDisableGetUsedXAssertions = oldDisableValue;
+
+    return true;
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/DocumentRendererParent.cpp
@@ -0,0 +1,85 @@
+/* ***** 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 Fennec Electrolysis.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 "mozilla/ipc/DocumentRendererParent.h"
+#include "gfxImageSurface.h"
+#include "gfxPattern.h"
+
+using namespace mozilla::ipc;
+
+DocumentRendererParent::DocumentRendererParent()
+{}
+
+DocumentRendererParent::~DocumentRendererParent()
+{}
+
+void DocumentRendererParent::SetCanvasContext(nsICanvasRenderingContextInternal* aCanvas,
+                                              gfxContext* ctx)
+{
+    mCanvas = aCanvas;
+    mCanvasContext = ctx;
+}
+
+void DocumentRendererParent::DrawToCanvas(PRUint32 aWidth, PRUint32 aHeight,
+                                          const nsCString& aData)
+{
+    if (!mCanvas || !mCanvasContext)
+        return;
+
+    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(reinterpret_cast<PRUint8*>(const_cast<char*>(aData.Data())),
+                                                         gfxIntSize(aWidth, aHeight),
+                                                         aWidth * 4,
+                                                         gfxASurface::ImageFormatARGB32);
+    nsRefPtr<gfxPattern> pat = new gfxPattern(surf);
+
+    mCanvasContext->NewPath();
+    mCanvasContext->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, aWidth, aHeight), pat);
+    mCanvasContext->Fill();
+
+    // get rid of the pattern surface ref, because aData is very likely to go away shortly
+    mCanvasContext->SetColor(gfxRGBA(1,1,1,1));
+
+    gfxRect damageRect = mCanvasContext->UserToDevice(gfxRect(0, 0, aWidth, aHeight));
+    mCanvas->Redraw(damageRect);
+}
+
+bool
+DocumentRendererParent::Recv__delete__(const PRUint32& w, const PRUint32& h,
+                                       const nsCString& data)
+{
+    DrawToCanvas(w, h, data);
+    return true;
+}
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -48,16 +48,23 @@ LIBXUL_LIBRARY  = 1
 
 
 
 CPPSRCS	= \
 	CanvasUtils.cpp \
 	nsCanvasRenderingContext2D.cpp \
 	$(NULL)
 
+ifdef MOZ_IPC
+CPPSRCS += \
+	DocumentRendererParent.cpp \
+	DocumentRendererChild.cpp \
+	$(NULL)
+endif
+
 # Canvas 3D Pieces
 
 ifdef MOZ_WEBGL
 
 ifeq (1_1,$(MOZ_X11)_$(NS_OSSO))
 WEBGL_PLATFORM = EGL
 DEFINES += -DUSE_GLES2
 endif
@@ -102,16 +109,17 @@ else
 CPPSRCS += WebGLContextNotSupported.cpp
 
 endif
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 CXXFLAGS	+= $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)
 
 INCLUDES	+= \
 		-I$(srcdir)/../../../layout/xul/base/src \
 		-I$(srcdir)/../../../layout/style \
 		-I$(srcdir)/../../../layout/generic \
 		-I$(srcdir)/../../base/src \
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -240,16 +240,17 @@ public:
     NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height)
         { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter f);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
     NS_IMETHOD GetThebesSurface(gfxASurface **surface);
     NS_IMETHOD SetIsOpaque(PRBool b) { return NS_OK; };
+    NS_IMETHOD Redraw(const gfxRect&) { return NS_ERROR_NOT_IMPLEMENTED; }
 
 protected:
     GLES20Wrap *gl;
 
     nsICanvasElement* mCanvasElement;
 
     nsGLPbuffer *mGLPbuffer;
     PRInt32 mWidth, mHeight;
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -32,16 +32,22 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#  include "base/basictypes.h"
+#endif
+
+#include "nsIDOMXULElement.h"
+
 #ifdef _MSC_VER
 #define _USE_MATH_DEFINES
 #endif
 #include <math.h>
 
 #include "prmem.h"
 
 #include "nsIServiceManager.h"
@@ -98,20 +104,30 @@
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxFont.h"
 #include "gfxTextRunCache.h"
 #include "gfxBlur.h"
 
 #include "nsFrameManager.h"
 
+#include "nsFrameLoader.h"
+
 #include "nsBidiPresUtils.h"
 
 #include "CanvasUtils.h"
 
+#ifdef MOZ_IPC
+#  include "mozilla/ipc/PDocumentRendererParent.h"
+#  include "mozilla/dom/PIFrameEmbeddingParent.h"
+#  include "mozilla/ipc/DocumentRendererParent.h"
+// windows.h (included by chromium code) defines this, in its infinite wisdom
+#  undef DrawText
+#endif
+
 using namespace mozilla;
 
 #ifndef M_PI
 #define M_PI		3.14159265358979323846
 #define M_PI_2		1.57079632679489661923
 #endif
 
 /* Float validation stuff */
@@ -306,29 +322,29 @@ class nsCanvasRenderingContext2D :
     public nsIDOMCanvasRenderingContext2D,
     public nsICanvasRenderingContextInternal
 {
 public:
     nsCanvasRenderingContext2D();
     virtual ~nsCanvasRenderingContext2D();
 
     nsresult Redraw();
-    // this rect is in CSS pixels
-    nsresult Redraw(const gfxRect& r);
 
     // nsICanvasRenderingContextInternal
     NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
     NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
     NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height);
     NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
     NS_IMETHOD GetThebesSurface(gfxASurface **surface);
     NS_IMETHOD SetIsOpaque(PRBool isOpaque);
+    // this rect is in CSS pixels
+    NS_IMETHOD Redraw(const gfxRect &r);
 
     // nsISupports interface
     NS_DECL_ISUPPORTS
 
     // nsIDOMCanvasRenderingContext2D interface
     NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D
 
     enum Style {
@@ -843,17 +859,17 @@ nsCanvasRenderingContext2D::Redraw()
 
     if (mIsEntireFrameInvalid)
         return NS_OK;
 
     mIsEntireFrameInvalid = PR_TRUE;
     return mCanvasElement->InvalidateFrame();
 }
 
-nsresult
+NS_IMETHODIMP
 nsCanvasRenderingContext2D::Redraw(const gfxRect& r)
 {
     if (!mCanvasElement)
         return NS_OK;
 
     if (mIsEntireFrameInvalid)
         return NS_OK;
 
@@ -3310,16 +3326,93 @@ nsCanvasRenderingContext2D::DrawWindow(n
     // space.
     gfxRect damageRect = mThebes->UserToDevice(gfxRect(0, 0, aW, aH));
 
     Redraw(damageRect);
 
     return rv;
 }
 
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::AsyncDrawXULElement(nsIDOMXULElement* aElem, float aX, float aY,
+                                                float aW, float aH,
+                                                const nsAString& aBGColor,
+                                                PRUint32 flags)
+{
+    NS_ENSURE_ARG(aElem != nsnull);
+
+    // We can't allow web apps to call this until we fix at least the
+    // following potential security issues:
+    // -- rendering cross-domain IFRAMEs and then extracting the results
+    // -- rendering the user's theme and then extracting the results
+    // -- rendering native anonymous content (e.g., file input paths;
+    // scrollbars should be allowed)
+    if (!nsContentUtils::IsCallerTrustedForRead()) {
+        // not permitted to use DrawWindow
+        // XXX ERRMSG we need to report an error to developers here! (bug 329026)
+        return NS_ERROR_DOM_SECURITY_ERR;
+    }
+
+    nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aElem);
+    if (!loaderOwner)
+        return NS_ERROR_FAILURE;
+
+    nsCOMPtr<nsFrameLoader> frameloader = loaderOwner->GetFrameLoader();
+    if (!frameloader)
+        return NS_ERROR_FAILURE;
+
+#ifdef MOZ_IPC
+    mozilla::dom::PIFrameEmbeddingParent *child = frameloader->GetChildProcess();
+    if (!child) {
+        nsCOMPtr<nsIDOMWindow> window =
+            do_GetInterface(frameloader->GetExistingDocShell());
+        if (!window)
+            return NS_ERROR_FAILURE;
+
+        return DrawWindow(window, aX, aY, aW, aH, aBGColor, flags);
+    }
+
+    // protect against too-large surfaces that will cause allocation
+    // or overflow issues
+    if (!gfxASurface::CheckSurfaceSize(gfxIntSize(aW, aH), 0xffff))
+        return NS_ERROR_FAILURE;
+
+    PRBool flush =
+        (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH) == 0;
+
+    PRUint32 renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
+    if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_CARET) {
+        renderDocFlags |= nsIPresShell::RENDER_CARET;
+    }
+    if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_VIEW) {
+        renderDocFlags &= ~nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
+    }
+
+    PRInt32 x = nsPresContext::CSSPixelsToAppUnits(aX),
+            y = nsPresContext::CSSPixelsToAppUnits(aY),
+            w = nsPresContext::CSSPixelsToAppUnits(aW),
+            h = nsPresContext::CSSPixelsToAppUnits(aH);
+
+    mozilla::ipc::PDocumentRendererParent *pdocrender =
+        child->SendPDocumentRendererConstructor(x, y, w, h, nsString(aBGColor), renderDocFlags, flush);
+    mozilla::ipc::DocumentRendererParent *docrender = static_cast<mozilla::ipc::DocumentRendererParent *>(pdocrender);
+
+    docrender->SetCanvasContext(this, mThebes);
+
+    return NS_OK;
+#else
+    nsCOMPtr<nsIDOMWindow> window =
+        do_GetInterface(frameloader->GetExistingDocShell());
+    if (!window)
+        return NS_ERROR_FAILURE;
+
+    return DrawWindow(window, aX, aY, aW, aH, aBGColor, flags);
+#endif
+}
+
 //
 // device pixel getting/setting
 //
 extern "C" {
 #include "jstypes.h"
 JS_FRIEND_API(JSBool)
 js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count,
                                 JSUint8 *dest);
--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -36,36 +36,42 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsIPrivateDOMEvent_h__
 #define nsIPrivateDOMEvent_h__
 
 #include "nsISupports.h"
 
 #define NS_IPRIVATEDOMEVENT_IID \
-{ 0x1da4c501, 0xe87e, 0x49b4, \
-  { 0xb0, 0x49, 0xdf, 0x9f, 0xc3, 0x6b, 0x56, 0xd4 } }
+{ 0x26f5f0e9, 0x2960, 0x4405, \
+  { 0xa1, 0x7e, 0xd8, 0x9f, 0xb0, 0xd9, 0x4c, 0x71 } }
 
 class nsIDOMEventTarget;
 class nsIDOMEvent;
 class nsEvent;
 class nsCommandEvent;
 class nsPresContext;
 class nsInvalidateRequestList;
+namespace IPC {
+class Message;
+}
 
 class nsIPrivateDOMEvent : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPRIVATEDOMEVENT_IID)
 
   NS_IMETHOD DuplicatePrivateData() = 0;
   NS_IMETHOD SetTarget(nsIDOMEventTarget* aTarget) = 0;
   NS_IMETHOD_(PRBool) IsDispatchStopped() = 0;
   NS_IMETHOD_(nsEvent*) GetInternalNSEvent() = 0;
   NS_IMETHOD SetTrusted(PRBool aTrusted) = 0;
+  virtual void Serialize(IPC::Message* aMsg,
+                         PRBool aSerializeInterfaceType) = 0;
+  virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIPrivateDOMEvent, NS_IPRIVATEDOMEVENT_IID)
 
 nsresult
 NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent *aEvent);
 nsresult
 NS_NewDOMDataContainerEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent *aEvent);
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -81,19 +81,21 @@ CPPSRCS		= \
 		nsDOMSimpleGestureEvent.cpp \
 		nsDOMEventTargetHelper.cpp \
 		nsDOMScrollAreaEvent.cpp \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
-LOCAL_INCLUDES	= \
+LOCAL_INCLUDES	+= \
              -I$(srcdir)/../../base/src \
              -I$(srcdir)/../../html/base/src \
              -I$(srcdir)/../../xul/content/src \
              -I$(srcdir)/../../xml/content/src \
              -I$(srcdir)/../../../dom/base \
              -I$(srcdir)/../../../layout/generic \
              -I$(srcdir)/../../../layout/xul/base/src \
              -I$(srcdir)/../../../layout/xul/base/src/tree/src \
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -32,16 +32,20 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "base/basictypes.h"
+#include "IPC/IPCMessageUtils.h"
+#endif
 #include "nsCOMPtr.h"
 #include "nsDOMEvent.h"
 #include "nsEventStateManager.h"
 #include "nsIFrame.h"
 #include "nsIContent.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsIPrivateCompositionEvent.h"
@@ -1528,16 +1532,71 @@ nsDOMEvent::ReportWrongPropertyAccessWar
 NS_IMETHODIMP
 nsDOMEvent::GetPreventDefault(PRBool* aReturn)
 {
   NS_ENSURE_ARG_POINTER(aReturn);
   *aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
   return NS_OK;
 }
 
+void
+nsDOMEvent::Serialize(IPC::Message* aMsg, PRBool aSerializeInterfaceType)
+{
+#ifdef MOZ_IPC
+  if (aSerializeInterfaceType) {
+    IPC::WriteParam(aMsg, NS_LITERAL_STRING("event"));
+  }
+
+  nsString type;
+  GetType(type);
+  IPC::WriteParam(aMsg, type);
+
+  PRBool bubbles = PR_FALSE;
+  GetBubbles(&bubbles);
+  IPC::WriteParam(aMsg, bubbles);
+
+  PRBool cancelable = PR_FALSE;
+  GetCancelable(&cancelable);
+  IPC::WriteParam(aMsg, cancelable);
+
+  PRBool trusted = PR_FALSE;
+  GetIsTrusted(&trusted);
+  IPC::WriteParam(aMsg, trusted);
+
+  // No timestamp serialization for now!
+#endif
+}
+
+PRBool
+nsDOMEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+{
+#ifdef MOZ_IPC
+  nsString type;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), PR_FALSE);
+
+  PRBool bubbles = PR_FALSE;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), PR_FALSE);
+
+  PRBool cancelable = PR_FALSE;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), PR_FALSE);
+
+  PRBool trusted = PR_FALSE;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), PR_FALSE);
+
+  nsresult rv = InitEvent(type, bubbles, cancelable);
+  NS_ENSURE_SUCCESS(rv, PR_FALSE);
+  SetTrusted(trusted);
+
+  return PR_TRUE;
+#else
+  return PR_FALSE;
+#endif
+}
+
+
 nsresult NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
                         nsPresContext* aPresContext,
                         nsEvent *aEvent) 
 {
   nsDOMEvent* it = new nsDOMEvent(aPresContext, aEvent);
   if (nsnull == it) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -188,16 +188,19 @@ public:
 
   // nsIPrivateDOMEvent interface
   NS_IMETHOD    DuplicatePrivateData();
   NS_IMETHOD    SetTarget(nsIDOMEventTarget* aTarget);
   NS_IMETHOD_(PRBool)    IsDispatchStopped();
   NS_IMETHOD_(nsEvent*)    GetInternalNSEvent();
   NS_IMETHOD    SetTrusted(PRBool aTrusted);
 
+  virtual void Serialize(IPC::Message* aMsg, PRBool aSerializeInterfaceType);
+  virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter);
+
   static PopupControlState GetEventPopupControlState(nsEvent *aEvent);
 
   static void PopupAllowedEventsChanged();
 
   static void Shutdown();
 
   static const char* GetEventName(PRUint32 aEventType);
 protected:
--- a/content/events/src/nsDOMNotifyPaintEvent.cpp
+++ b/content/events/src/nsDOMNotifyPaintEvent.cpp
@@ -31,16 +31,20 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "base/basictypes.h"
+#include "IPC/IPCMessageUtils.h"
+#endif
 #include "nsDOMNotifyPaintEvent.h"
 #include "nsContentUtils.h"
 #include "nsClientRect.h"
 #include "nsPaintRequest.h"
 #include "nsIFrame.h"
 
 nsDOMNotifyPaintEvent::nsDOMNotifyPaintEvent(nsPresContext* aPresContext,
                                              nsEvent* aEvent,
@@ -137,16 +141,60 @@ nsDOMNotifyPaintEvent::GetPaintRequests(
     r->SetRequest(mInvalidateRequests[i]);
     requests->Append(r);
   }
 
   requests.forget(aResult);
   return NS_OK;
 }
 
+#ifdef MOZ_IPC
+void
+nsDOMNotifyPaintEvent::Serialize(IPC::Message* aMsg,
+                                 PRBool aSerializeInterfaceType)
+{
+  if (aSerializeInterfaceType) {
+    IPC::WriteParam(aMsg, NS_LITERAL_STRING("notifypaintevent"));
+  }
+
+  nsDOMEvent::Serialize(aMsg, PR_FALSE);
+
+  PRUint32 length = mInvalidateRequests.Length();
+  IPC::WriteParam(aMsg, length);
+  for (PRUint32 i = 0; i < length; ++i) {
+    IPC::WriteParam(aMsg, mInvalidateRequests[i].mRect.x);
+    IPC::WriteParam(aMsg, mInvalidateRequests[i].mRect.y);
+    IPC::WriteParam(aMsg, mInvalidateRequests[i].mRect.width);
+    IPC::WriteParam(aMsg, mInvalidateRequests[i].mRect.height);
+    IPC::WriteParam(aMsg, mInvalidateRequests[i].mFlags);
+  }
+}
+
+PRBool
+nsDOMNotifyPaintEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+{
+  NS_ENSURE_TRUE(nsDOMEvent::Deserialize(aMsg, aIter), PR_FALSE);
+
+  PRUint32 length = 0;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &length), PR_FALSE);
+  mInvalidateRequests.SetCapacity(length);
+  for (PRUint32 i = 0; i < length; ++i) {
+    nsInvalidateRequestList::Request req;
+    NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &req.mRect.x), PR_FALSE);
+    NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &req.mRect.y), PR_FALSE);
+    NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &req.mRect.width), PR_FALSE);
+    NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &req.mRect.height), PR_FALSE);
+    NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &req.mFlags), PR_FALSE);
+    mInvalidateRequests.AppendElement(req);
+  }
+
+  return PR_TRUE;
+}
+#endif
+
 nsresult NS_NewDOMNotifyPaintEvent(nsIDOMEvent** aInstancePtrResult,
                                    nsPresContext* aPresContext,
                                    nsEvent *aEvent,
                                    PRUint32 aEventType,
                                    nsInvalidateRequestList* aInvalidateRequests) 
 {
   nsDOMNotifyPaintEvent* it =
     new nsDOMNotifyPaintEvent(aPresContext, aEvent, aEventType,
--- a/content/events/src/nsDOMNotifyPaintEvent.h
+++ b/content/events/src/nsDOMNotifyPaintEvent.h
@@ -56,15 +56,19 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMNOTIFYPAINTEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
+#ifdef MOZ_IPC
+  virtual void Serialize(IPC::Message* aMsg, PRBool aSerializeInterfaceType);
+  virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter);
+#endif
 private:
   nsRegion GetRegion();
 
   nsTArray<nsInvalidateRequestList::Request> mInvalidateRequests;
 };
 
 #endif // nsDOMNotifyPaintEvent_h_
--- a/content/events/src/nsDOMScrollAreaEvent.cpp
+++ b/content/events/src/nsDOMScrollAreaEvent.cpp
@@ -30,16 +30,20 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "base/basictypes.h"
+#include "IPC/IPCMessageUtils.h"
+#endif
 #include "nsDOMScrollAreaEvent.h"
 #include "nsGUIEvent.h"
 #include "nsClientRect.h"
 
 nsDOMScrollAreaEvent::nsDOMScrollAreaEvent(nsPresContext *aPresContext,
                                            nsScrollAreaEvent *aEvent)
   : nsDOMUIEvent(aPresContext, aEvent)
 {
@@ -101,16 +105,74 @@ nsDOMScrollAreaEvent::InitScrollAreaEven
   nsresult rv = nsDOMUIEvent::InitUIEvent(aEventType, aCanBubble, aCancelable, aView, aDetail);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mClientArea.SetRect(aX, aY, aWidth, aHeight);
 
   return NS_OK;
 }
 
+#ifdef MOZ_IPC
+void
+nsDOMScrollAreaEvent::Serialize(IPC::Message* aMsg,
+                                PRBool aSerializeInterfaceType)
+{
+  if (aSerializeInterfaceType) {
+    IPC::WriteParam(aMsg, NS_LITERAL_STRING("scrollareaevent"));
+  }
+
+  nsDOMUIEvent::Serialize(aMsg, PR_FALSE);
+
+  NS_ASSERTION(sizeof(PRInt32) == sizeof(float),
+               "PRInt32 and float should be the same size!");
+
+  float x = 0.0f;
+  GetX(&x);
+  IPC::WriteParam(aMsg, reinterpret_cast<PRInt32&>(x));
+
+  float y = 0.0f;
+  GetY(&y);
+  IPC::WriteParam(aMsg, reinterpret_cast<PRInt32&>(y));
+
+  float width = 0.0f;
+  GetWidth(&width);
+  IPC::WriteParam(aMsg, reinterpret_cast<PRInt32&>(width));
+
+  float height = 0.0f;
+  GetHeight(&height);
+  IPC::WriteParam(aMsg, reinterpret_cast<PRInt32&>(height));
+}
+
+PRBool
+nsDOMScrollAreaEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+{
+  NS_ENSURE_TRUE(nsDOMUIEvent::Deserialize(aMsg, aIter), PR_FALSE);
+
+  PRInt32 x_;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &x_), PR_FALSE);
+  float x = reinterpret_cast<float&>(x_);
+
+  PRInt32 y_;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &y_), PR_FALSE);
+  float y = reinterpret_cast<float&>(y_);
+
+  PRInt32 width_;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &width_), PR_FALSE);
+  float width = reinterpret_cast<float&>(width_);
+
+  PRInt32 height_;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &height_), PR_FALSE);
+  float height = reinterpret_cast<float&>(height_);
+
+  mClientArea.SetRect(x, y, width, height);
+
+  return PR_TRUE;
+}
+#endif
+
 nsresult
 NS_NewDOMScrollAreaEvent(nsIDOMEvent **aInstancePtrResult,
                          nsPresContext *aPresContext,
                          nsScrollAreaEvent *aEvent)
 {
   nsDOMScrollAreaEvent *ev = new nsDOMScrollAreaEvent(aPresContext, aEvent);
 
   if (!ev) {
--- a/content/events/src/nsDOMScrollAreaEvent.h
+++ b/content/events/src/nsDOMScrollAreaEvent.h
@@ -53,13 +53,17 @@ public:
   virtual ~nsDOMScrollAreaEvent();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMSCROLLAREAEVENT
 
   NS_FORWARD_TO_NSDOMUIEVENT
 
+#ifdef MOZ_IPC
+  virtual void Serialize(IPC::Message* aMsg, PRBool aSerializeInterfaceType);
+  virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter);
+#endif
 protected:
   nsClientRect mClientArea;
 };
 
 #endif // nsDOMScrollAreaEvent_h__
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -32,16 +32,20 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "base/basictypes.h"
+#include "IPC/IPCMessageUtils.h"
+#endif
 #include "nsCOMPtr.h"
 #include "nsDOMUIEvent.h"
 #include "nsIPresShell.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDOMNode.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
@@ -389,16 +393,40 @@ nsDOMUIEvent::DuplicatePrivateData()
   nsIntPoint screenPoint = GetScreenPoint();
   nsresult rv = nsDOMEvent::DuplicatePrivateData();
   if (NS_SUCCEEDED(rv)) {
     mEvent->refPoint = screenPoint;
   }
   return rv;
 }
 
+#ifdef MOZ_IPC
+void
+nsDOMUIEvent::Serialize(IPC::Message* aMsg, PRBool aSerializeInterfaceType)
+{
+  if (aSerializeInterfaceType) {
+    IPC::WriteParam(aMsg, NS_LITERAL_STRING("uievent"));
+  }
+
+  nsDOMEvent::Serialize(aMsg, PR_FALSE);
+
+  PRInt32 detail = 0;
+  GetDetail(&detail);
+  IPC::WriteParam(aMsg, detail);
+}
+
+PRBool
+nsDOMUIEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+{
+  NS_ENSURE_TRUE(nsDOMEvent::Deserialize(aMsg, aIter), PR_FALSE);
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &mDetail), PR_FALSE);
+  return PR_TRUE;
+}
+#endif
+
 nsresult NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult,
                           nsPresContext* aPresContext,
                           nsGUIEvent *aEvent) 
 {
   nsDOMUIEvent* it = new nsDOMUIEvent(aPresContext, aEvent);
   if (nsnull == it) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -59,17 +59,20 @@ public:
   // nsIDOMUIEvent Interface
   NS_DECL_NSIDOMUIEVENT
 
   // nsIDOMNSUIEvent Interface
   NS_DECL_NSIDOMNSUIEVENT
 
   // nsIPrivateDOMEvent interface
   NS_IMETHOD DuplicatePrivateData();
-  
+#ifdef MOZ_IPC
+  virtual void Serialize(IPC::Message* aMsg, PRBool aSerializeInterfaceType);
+  virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter);
+#endif
   // nsIPrivateCompositionEvent interface
   NS_IMETHOD GetCompositionReply(nsTextEventReply** aReply);
   
   // Forward to nsDOMEvent
   NS_FORWARD_TO_NSDOMEVENT
 
   NS_FORWARD_NSIDOMNSEVENT(nsDOMEvent::)
 protected:
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -77,14 +77,20 @@ endif
 DIRS += \
   public/coreEvents \
   base \
   src \
   locales \
   plugins \
   $(NULL)
 
+ifdef MOZ_IPC
+DIRS += \
+  ipc \
+  $(NULL)
+endif
+
 ifdef ENABLE_TESTS
 DIRS += tests
 endif
 
 include $(topsrcdir)/config/rules.mk
 
--- a/dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
+++ b/dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
@@ -38,16 +38,17 @@
 #include "nsISupports.idl"
 #include "nsIVariant.idl"
 
 interface nsIDOMWindow;
 interface nsIDOMElement;
 interface nsIDOMHTMLElement;
 interface nsIDOMHTMLImageElement;
 interface nsIDOMHTMLCanvasElement;
+interface nsIDOMXULElement;
 
 [scriptable, uuid(bbb20a59-524e-4662-981e-5e142814b20c)]
 interface nsIDOMCanvasGradient : nsISupports
 {
   void addColorStop(in float offset, in DOMString color);
 };
 
 [scriptable, uuid(21dea65c-5c08-4eb1-ac82-81fe95be77b8)]
@@ -56,17 +57,17 @@ interface nsIDOMCanvasPattern : nsISuppo
 };
 
 [scriptable, uuid(2d01715c-ec7d-424a-ab85-e0fd70c8665c)]
 interface nsIDOMTextMetrics : nsISupports
 {
   readonly attribute float width;
 };
 
-[scriptable, uuid(72635fb6-0c1c-47d7-bf69-49388d5980fc)]
+[scriptable, uuid(408be1b9-4d75-4873-b50b-9b651626e41d)]
 interface nsIDOMCanvasRenderingContext2D : nsISupports
 {
   // back-reference to the canvas element for which
   // this context was created
   readonly attribute nsIDOMHTMLCanvasElement canvas;
 
   // state
   void save();
@@ -217,9 +218,12 @@ interface nsIDOMCanvasRenderingContext2D
    * transparency.
    *
    * This API cannot currently be used by Web content. It is chrome
    * only.
    */
   void drawWindow(in nsIDOMWindow window, in float x, in float y,
                   in float w, in float h, in DOMString bgColor,
                   [optional] in unsigned long flags);
+  void asyncDrawXULElement(in nsIDOMXULElement elem, in float x, in float y,
+                  in float w, in float h, in DOMString bgColor,
+                  [optional] in unsigned long flags);
 };
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessChild.cpp
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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) 2009
+ * 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 "ContentProcessChild.h"
+#include "TabChild.h"
+
+#include "mozilla/ipc/TestShellChild.h"
+#include "mozilla/net/NeckoChild.h"
+
+#include "nsXULAppAPI.h"
+
+#include "base/message_loop.h"
+#include "base/task.h"
+
+using namespace mozilla::ipc;
+using namespace mozilla::net;
+
+namespace mozilla {
+namespace dom {
+
+ContentProcessChild* ContentProcessChild::sSingleton;
+
+ContentProcessChild::ContentProcessChild()
+    : mQuit(PR_FALSE)
+{
+}
+
+ContentProcessChild::~ContentProcessChild()
+{
+}
+
+bool
+ContentProcessChild::Init(MessageLoop* aIOLoop,
+                          base::ProcessHandle aParentHandle,
+                          IPC::Channel* aChannel)
+{
+    NS_ASSERTION(!sSingleton, "only one ContentProcessChild per child");
+  
+    Open(aChannel, aParentHandle, aIOLoop);
+    sSingleton = this;
+
+    return true;
+}
+
+PIFrameEmbeddingChild*
+ContentProcessChild::AllocPIFrameEmbedding()
+{
+  nsRefPtr<TabChild> iframe = new TabChild();
+  NS_ENSURE_TRUE(iframe && NS_SUCCEEDED(iframe->Init()) &&
+                 mIFrames.AppendElement(iframe),
+                 nsnull);
+  return iframe.forget().get();
+}
+
+bool
+ContentProcessChild::DeallocPIFrameEmbedding(PIFrameEmbeddingChild* iframe)
+{
+    if (mIFrames.RemoveElement(iframe)) {
+      TabChild* child = static_cast<TabChild*>(iframe);
+      NS_RELEASE(child);
+    }
+    return true;
+}
+
+PTestShellChild*
+ContentProcessChild::AllocPTestShell()
+{
+    PTestShellChild* testshell = new TestShellChild();
+    if (testshell && mTestShells.AppendElement(testshell)) {
+        return testshell;
+    }
+    delete testshell;
+    return nsnull;
+}
+
+bool
+ContentProcessChild::DeallocPTestShell(PTestShellChild* shell)
+{
+    mTestShells.RemoveElement(shell);
+    return true;
+}
+
+PNeckoChild* 
+ContentProcessChild::AllocPNecko()
+{
+    return new NeckoChild();
+}
+
+bool 
+ContentProcessChild::DeallocPNecko(PNeckoChild* necko)
+{
+    delete necko;
+    return true;
+}
+
+void
+ContentProcessChild::Quit()
+{
+    NS_ASSERTION(mQuit, "Exiting uncleanly!");
+    mIFrames.Clear();
+    mTestShells.Clear();
+}
+
+void
+ContentProcessChild::ActorDestroy(ActorDestroyReason why)
+{
+    if (AbnormalShutdown == why)
+        NS_WARNING("shutting down because of crash!");
+
+    mQuit = PR_TRUE;
+    Quit();
+
+    XRE_ShutdownChildProcess();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessChild.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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) 2009
+ * 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 mozilla_dom_ContentProcessChild_h
+#define mozilla_dom_ContentProcessChild_h
+
+#include "mozilla/dom/PContentProcessChild.h"
+
+#include "nsTArray.h"
+#include "nsAutoPtr.h"
+
+namespace mozilla {
+namespace dom {
+
+class ContentProcessChild : public PContentProcessChild
+{
+public:
+    ContentProcessChild();
+    virtual ~ContentProcessChild();
+
+    bool Init(MessageLoop* aIOLoop,
+              base::ProcessHandle aParentHandle,
+              IPC::Channel* aChannel);
+
+    static ContentProcessChild* GetSingleton() {
+        NS_ASSERTION(sSingleton, "not initialized");
+        return sSingleton;
+    }
+
+    virtual PIFrameEmbeddingChild* AllocPIFrameEmbedding();
+    virtual bool DeallocPIFrameEmbedding(PIFrameEmbeddingChild*);
+
+    virtual PTestShellChild* AllocPTestShell();
+    virtual bool DeallocPTestShell(PTestShellChild*);
+
+    virtual PNeckoChild* AllocPNecko();
+    virtual bool DeallocPNecko(PNeckoChild*);
+
+private:
+    NS_OVERRIDE
+    virtual void ActorDestroy(ActorDestroyReason why);
+
+    void Quit();
+
+    static ContentProcessChild* sSingleton;
+
+    nsTArray<PIFrameEmbeddingChild* > mIFrames;
+    nsTArray<nsAutoPtr<PTestShellChild> > mTestShells;
+
+    PRBool mQuit;
+
+    DISALLOW_EVIL_CONSTRUCTORS(ContentProcessChild);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessParent.cpp
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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) 2009
+ * 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 "ContentProcessParent.h"
+
+#include "mozilla/ipc/GeckoThread.h"
+
+#include "TabParent.h"
+#include "mozilla/ipc/TestShellParent.h"
+#include "mozilla/net/NeckoParent.h"
+
+#include "nsIObserverService.h"
+
+#include "nsAutoPtr.h"
+#include "nsCOMPtr.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla::ipc;
+using namespace mozilla::net;
+using mozilla::MonitorAutoEnter;
+
+namespace {
+PRBool gSingletonDied = PR_FALSE;
+}
+
+namespace mozilla {
+namespace dom {
+
+ContentProcessParent* ContentProcessParent::gSingleton;
+
+ContentProcessParent*
+ContentProcessParent::GetSingleton()
+{
+    if (!gSingleton && !gSingletonDied) {
+        nsRefPtr<ContentProcessParent> parent = new ContentProcessParent();
+        if (parent) {
+            nsCOMPtr<nsIObserverService> obs =
+                do_GetService("@mozilla.org/observer-service;1");
+            if (obs) {
+                if (NS_SUCCEEDED(obs->AddObserver(parent, "xpcom-shutdown",
+                                                  PR_FALSE))) {
+                    gSingleton = parent;
+                }
+            }
+        }
+    }
+    return gSingleton;
+}
+
+TabParent*
+ContentProcessParent::CreateTab()
+{
+  return static_cast<TabParent*>(SendPIFrameEmbeddingConstructor());
+}
+
+TestShellParent*
+ContentProcessParent::CreateTestShell()
+{
+  return static_cast<TestShellParent*>(SendPTestShellConstructor());
+}
+
+bool
+ContentProcessParent::DestroyTestShell(TestShellParent* aTestShell)
+{
+    return PTestShellParent::Send__delete__(aTestShell);
+}
+
+ContentProcessParent::ContentProcessParent()
+    : mMonitor("ContentProcessParent::mMonitor")
+{
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+    mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content);
+    mSubprocess->AsyncLaunch();
+    Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
+}
+
+ContentProcessParent::~ContentProcessParent()
+{
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+    NS_ASSERTION(gSingleton == this, "More than one singleton?!");
+    gSingletonDied = PR_TRUE;
+    gSingleton = nsnull;
+}
+
+NS_IMPL_ISUPPORTS1(ContentProcessParent, nsIObserver)
+
+namespace {
+void
+DeleteSubprocess(GeckoChildProcessHost* aSubprocess)
+{
+    delete aSubprocess;
+}
+}
+
+NS_IMETHODIMP
+ContentProcessParent::Observe(nsISupports* aSubject,
+                              const char* aTopic,
+                              const PRUnichar* aData)
+{
+    if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
+        Close();
+        XRE_GetIOMessageLoop()->PostTask(
+            FROM_HERE,
+            NewRunnableFunction(DeleteSubprocess, mSubprocess));
+        mSubprocess = nsnull;
+    }
+    return NS_OK;
+}
+
+PIFrameEmbeddingParent*
+ContentProcessParent::AllocPIFrameEmbedding()
+{
+    return new TabParent();
+}
+
+bool
+ContentProcessParent::DeallocPIFrameEmbedding(PIFrameEmbeddingParent* frame)
+{
+  delete frame;
+  return true;
+}
+
+PTestShellParent*
+ContentProcessParent::AllocPTestShell()
+{
+  return new TestShellParent();
+}
+
+bool
+ContentProcessParent::DeallocPTestShell(PTestShellParent* shell)
+{
+  delete shell;
+  return true;
+}
+
+PNeckoParent* 
+ContentProcessParent::AllocPNecko()
+{
+    return new NeckoParent();
+}
+
+bool 
+ContentProcessParent::DeallocPNecko(PNeckoParent* necko)
+{
+    delete necko;
+    return true;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessParent.h
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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) 2009
+ * 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 mozilla_dom_ContentProcessParent_h
+#define mozilla_dom_ContentProcessParent_h
+
+#include "base/waitable_event_watcher.h"
+
+#include "mozilla/dom/PContentProcessParent.h"
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+
+#include "nsIObserver.h"
+#include "mozilla/Monitor.h"
+
+namespace mozilla {
+
+namespace ipc {
+class TestShellParent;
+}
+
+namespace dom {
+
+class TabParent;
+
+class ContentProcessParent : public PContentProcessParent,
+                             public nsIObserver
+{
+private:
+    typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
+    typedef mozilla::ipc::TestShellParent TestShellParent;
+
+public:
+    static ContentProcessParent* GetSingleton();
+
+#if 0
+    // TODO: implement this somewhere!
+    static ContentProcessParent* FreeSingleton();
+#endif
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIOBSERVER
+
+    TabParent* CreateTab();
+
+    TestShellParent* CreateTestShell();
+    bool DestroyTestShell(TestShellParent* aTestShell);
+
+private:
+    static ContentProcessParent* gSingleton;
+
+    // Hide the raw constructor methods since we don't want client code
+    // using them.
+    using PContentProcessParent::SendPIFrameEmbeddingConstructor;
+    using PContentProcessParent::SendPTestShellConstructor;
+
+    ContentProcessParent();
+    virtual ~ContentProcessParent();
+
+    virtual PIFrameEmbeddingParent* AllocPIFrameEmbedding();
+    virtual bool DeallocPIFrameEmbedding(PIFrameEmbeddingParent* frame);
+
+    virtual PTestShellParent* AllocPTestShell();
+    virtual bool DeallocPTestShell(PTestShellParent* shell);
+
+    virtual PNeckoParent* AllocPNecko();
+    virtual bool DeallocPNecko(PNeckoParent* necko);
+
+    mozilla::Monitor mMonitor;
+
+    GeckoChildProcessHost* mSubprocess;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessThread.cpp
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *
+ * 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 "ContentProcessThread.h"
+
+#include "prlink.h"
+
+#include "base/command_line.h"
+#include "base/string_util.h"
+#include "chrome/common/child_process.h"
+#include "chrome/common/chrome_switches.h"
+
+using mozilla::ipc::GeckoThread;
+
+namespace mozilla {
+namespace dom {
+
+ContentProcessThread::ContentProcessThread(ProcessHandle mParentHandle) :
+    GeckoThread(mParentHandle),
+    mContentProcess()
+{
+}
+
+ContentProcessThread::~ContentProcessThread()
+{
+}
+
+void
+ContentProcessThread::Init()
+{
+    GeckoThread::Init();
+
+    // FIXME/cjones: set up channel stuff, etc.
+    
+    // FIXME owner_loop() is bad here
+    mContentProcess.Init(owner_loop(), GetParentProcessHandle(), channel());
+}
+
+void
+ContentProcessThread::CleanUp()
+{
+    GeckoThread::CleanUp();
+}
+
+} // namespace tabs
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessThread.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *
+ * 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 dom_tabs_ContentProcessThread_h
+#define dom_tabs_ContentProcessThread_h 1
+
+#include "chrome/common/child_thread.h"
+#include "base/file_path.h"
+
+#include "mozilla/ipc/GeckoThread.h"
+#include "ContentProcessChild.h"
+
+#undef _MOZ_LOG
+#define _MOZ_LOG(s)  printf("[ContentProcessThread] %s", s)
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * ContentProcessThread is a singleton on the content process which represents
+ * a background thread where tab instances live.
+ */
+class ContentProcessThread : public mozilla::ipc::GeckoThread
+{
+public:
+    ContentProcessThread(ProcessHandle mParentHandle);
+    ~ContentProcessThread();
+
+private:
+    // Thread implementation:
+    virtual void Init();
+    virtual void CleanUp();
+
+    ContentProcessChild mContentProcess;
+    IPC::Channel* mChannel;
+
+    DISALLOW_EVIL_CONSTRUCTORS(ContentProcessThread);
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // ifndef dom_tabs_ContentProcessThread_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/Makefile.in
@@ -0,0 +1,77 @@
+# ***** 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 Firefox.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# 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 *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = dom
+LIBRARY_NAME = domipc_s
+LIBXUL_LIBRARY = 1
+FORCE_STATIC_LIB = 1
+EXPORT_LIBRARY = 1
+
+EXPORTS = TabMessageUtils.h
+
+EXPORTS_NAMESPACES = mozilla mozilla/dom
+
+EXPORTS_mozilla = \
+  TabTypes.h \
+  $(NULL)
+
+EXPORTS_mozilla/dom = \
+  ContentProcessChild.h \
+  ContentProcessParent.h \
+  ContentProcessThread.h \
+  $(NULL)
+
+CPPSRCS = \
+  ContentProcessThread.cpp \
+  ContentProcessParent.cpp \
+  ContentProcessChild.cpp \
+  TabParent.cpp \
+  TabChild.cpp \
+  TabMessageUtils.cpp \
+  $(NULL)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PContentProcess.ipdl
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* ***** 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) 2009
+ * 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 protocol "PIFrameEmbedding.ipdl";
+include protocol "PTestShell.ipdl";
+include protocol "PNecko.ipdl";
+
+include "mozilla/TabTypes.h";
+
+namespace mozilla {
+namespace dom {
+
+sync protocol PContentProcess
+{
+    manages PIFrameEmbedding;
+    manages PTestShell;
+    manages PNecko;
+
+child:
+    PIFrameEmbedding();
+
+    PTestShell();
+
+parent:
+    PNecko();
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PDocumentRenderer.ipdl
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* ***** 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 Fenntrolysis.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 protocol "PIFrameEmbedding.ipdl";
+
+namespace mozilla {
+namespace ipc {
+
+protocol PDocumentRenderer
+{
+  manager PIFrameEmbedding;
+
+parent:
+    __delete__(PRUint32 w, PRUint32 h, nsCString data);
+};
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PIFrameEmbedding.ipdl
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+
+/* ***** 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) 2009
+ * 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 protocol "PContentProcess.ipdl";
+include protocol "PDocumentRenderer.ipdl";
+
+include "mozilla/TabTypes.h";
+include "TabMessageUtils.h";
+
+using MagicWindowHandle;
+using RemoteDOMEvent;
+
+namespace mozilla {
+namespace dom {
+
+async protocol PIFrameEmbedding
+{
+    manager PContentProcess;
+    manages PDocumentRenderer;
+
+child:
+    __delete__();
+
+parent:
+    /**
+     * When child sends this message, parent should move focus to
+     * the next or previous focusable element.
+     */
+    moveFocus(bool forward);
+
+    sendEvent(RemoteDOMEvent aEvent);
+child:
+    createWidget(MagicWindowHandle parentWidget);
+
+    loadURL(nsCString uri);
+
+    move(PRUint32 x,
+         PRUint32 y,
+         PRUint32 width,
+         PRUint32 height);
+
+    /**
+     * Sending an activate message moves focus to the child.
+     */
+    activate();
+
+  /**
+   * @see nsIDOMWindowUtils sendMouseEvent.
+   */
+    sendMouseEvent(nsString aType,
+                   PRInt32 aX, //XXX should be float, but ipdl doesn't seem to support that.
+                   PRInt32 aY, //XXX - " -
+                   PRInt32 aButton,
+                   PRInt32 aClickCount,
+                   PRInt32 aModifiers,
+                   bool aIgnoreRootScrollFrame);
+
+    /**
+     * Activate event forwarding from client to parent.
+     */
+    activateFrameEvent(nsString aType, bool capture);
+
+    PDocumentRenderer(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h, nsString bgcolor, PRUint32 flags, bool flush);
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabChild.cpp
@@ -0,0 +1,416 @@
+/* -*- 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) 2009
+ * 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 "TabChild.h"
+
+#include "nsIWebBrowser.h"
+#include "nsEmbedCID.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIBaseWindow.h"
+#include "nsIDOMWindow.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsThreadUtils.h"
+#include "nsIInterfaceRequestorUtils.h"
+#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"
+
+#ifdef MOZ_WIDGET_GTK2
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#endif
+
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
+
+NS_IMETHODIMP
+ContentListener::HandleEvent(nsIDOMEvent* aEvent)
+{
+  RemoteDOMEvent remoteEvent;
+  remoteEvent.mEvent = do_QueryInterface(aEvent);
+  NS_ENSURE_STATE(remoteEvent.mEvent);
+  mTabChild->SendsendEvent(remoteEvent);
+  return NS_OK;
+}
+
+TabChild::TabChild()
+{
+    printf("creating %d!\n", NS_IsMainThread());
+}
+
+nsresult
+TabChild::Init()
+{
+#ifdef MOZ_WIDGET_GTK2
+  gtk_init(NULL, NULL);
+#endif
+
+  nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
+  if (!webBrowser) {
+    NS_ERROR("Couldn't create a nsWebBrowser?");
+    return NS_ERROR_FAILURE;
+  }
+
+  webBrowser->SetContainerWindow(this);
+
+  mWebNav = do_QueryInterface(webBrowser);
+  NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
+
+  nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(mWebNav));
+  docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS5(TabChild, nsIWebBrowserChrome, nsIWebBrowserChrome2,
+                   nsIEmbeddingSiteWindow, nsIEmbeddingSiteWindow2,
+                   nsIWebBrowserChromeFocus)
+
+NS_IMETHODIMP
+TabChild::SetStatus(PRUint32 aStatusType, const PRUnichar* aStatus)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::SetWebBrowser(nsIWebBrowser* aWebBrowser)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::GetChromeFlags(PRUint32* aChromeFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::SetChromeFlags(PRUint32 aChromeFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::DestroyBrowserWindow()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::ShowAsModal()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::IsWindowModal(PRBool* aRetVal)
+{
+  *aRetVal = PR_FALSE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TabChild::ExitModalEventLoop(nsresult aStatus)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::SetStatusWithContext(PRUint32 aStatusType,
+                                    const nsAString& aStatusText,
+                                    nsISupports* aStatusContext)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::SetDimensions(PRUint32 aFlags, PRInt32 aX, PRInt32 aY,
+                             PRInt32 aCx, PRInt32 aCy)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::GetDimensions(PRUint32 aFlags, PRInt32* aX,
+                             PRInt32* aY, PRInt32* aCx, PRInt32* aCy)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::SetFocus()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::GetVisibility(PRBool* aVisibility)
+{
+  *aVisibility = PR_TRUE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TabChild::SetVisibility(PRBool aVisibility)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::GetTitle(PRUnichar** aTitle)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::SetTitle(const PRUnichar* aTitle)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::GetSiteWindow(void** aSiteWindow)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::Blur()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TabChild::FocusNextElement()
+{
+  SendmoveFocus(PR_TRUE);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TabChild::FocusPrevElement()
+{
+  SendmoveFocus(PR_FALSE);
+  return NS_OK;
+}
+
+bool
+TabChild::RecvcreateWidget(const MagicWindowHandle& parentWidget)
+{
+    nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mWebNav);
+    if (!baseWindow) {
+        NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
+        return true;
+    }
+
+#ifdef MOZ_WIDGET_GTK2
+    GtkWidget* win = gtk_plug_new((GdkNativeWindow)parentWidget);
+    gtk_widget_show(win);
+#elif defined(XP_WIN)
+    HWND win = parentWidget;
+#elif defined(XP_MACOSX)
+#  warning IMPLEMENT ME
+#else
+#error You lose!
+#endif
+
+#if !defined(XP_MACOSX)
+    baseWindow->InitWindow(win, 0, 0, 0, 0, 0);
+    baseWindow->Create();
+    baseWindow->SetVisibility(PR_TRUE);
+#endif
+
+    return true;
+}
+
+bool
+TabChild::destroyWidget()
+{
+    nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mWebNav);
+    if (baseWindow)
+        baseWindow->Destroy();
+
+    return true;
+}
+
+TabChild::~TabChild()
+{
+    destroyWidget();
+    nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(mWebNav);
+    if (webBrowser) {
+      webBrowser->SetContainerWindow(nsnull);
+    }
+}
+
+bool
+TabChild::RecvloadURL(const nsCString& uri)
+{
+    printf("loading %s, %d\n", uri.get(), NS_IsMainThread());
+
+    nsresult rv = mWebNav->LoadURI(NS_ConvertUTF8toUTF16(uri).get(),
+                                   nsIWebNavigation::LOAD_FLAGS_NONE,
+                                   NULL, NULL, NULL);
+    if (NS_FAILED(rv)) {
+        NS_WARNING("mWebNav->LoadURI failed. Eating exception, what else can I do?");
+    }
+    return true;
+}
+
+bool
+TabChild::Recvmove(const PRUint32& x,
+                     const PRUint32& y,
+                     const PRUint32& width,
+                     const PRUint32& height)
+{
+    printf("[TabChild] MOVE to (x,y)=(%ud, %ud), (w,h)= (%ud, %ud)\n",
+           x, y, width, height);
+
+    nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mWebNav);
+    baseWin->SetPositionAndSize(x, y, width, height, PR_TRUE);
+    return true;
+}
+
+bool
+TabChild::Recvactivate()
+{
+  nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(mWebNav);
+  browser->Activate();
+  return true;
+}
+
+bool
+TabChild::RecvsendMouseEvent(const nsString& aType,
+                             const PRInt32&  aX,
+                             const PRInt32&  aY,
+                             const PRInt32&  aButton,
+                             const PRInt32&  aClickCount,
+                             const PRInt32&  aModifiers,
+                             const bool&     aIgnoreRootScrollFrame)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
+  nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
+  NS_ENSURE_TRUE(utils, true);
+  utils->SendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers,
+                        aIgnoreRootScrollFrame);
+  return true;
+}
+
+mozilla::ipc::PDocumentRendererChild*
+TabChild::AllocPDocumentRenderer(
+        const PRInt32& x,
+        const PRInt32& y,
+        const PRInt32& w,
+        const PRInt32& h,
+        const nsString& bgcolor,
+        const PRUint32& flags,
+        const bool& flush)
+{
+    return new mozilla::ipc::DocumentRendererChild();
+}
+
+bool
+TabChild::DeallocPDocumentRenderer(PDocumentRendererChild* actor)
+{
+    delete actor;
+    return true;
+}
+
+bool
+TabChild::RecvPDocumentRendererConstructor(
+        mozilla::ipc::PDocumentRendererChild *__a,
+        const PRInt32& aX,
+        const PRInt32& aY,
+        const PRInt32& aW,
+        const PRInt32& aH,
+        const nsString& bgcolor,
+        const PRUint32& flags,
+        const bool& flush)
+{
+    mozilla::ipc::DocumentRendererChild *render = 
+        static_cast<mozilla::ipc::DocumentRendererChild *>(__a);
+
+    nsCOMPtr<nsIWebBrowser> browser = do_QueryInterface(mWebNav);
+    if (!browser)
+        return true; // silently ignore
+    nsCOMPtr<nsIDOMWindow> window;
+    if (NS_FAILED(browser->GetContentDOMWindow(getter_AddRefs(window))) ||
+        !window)
+    {
+        return true; // silently ignore
+    }
+
+    PRUint32 width, height;
+    nsCString data;
+    bool ret = render->RenderDocument(window, aX, aY, aW, aH, bgcolor, flags, flush,
+                                      width, height, data);
+    if (!ret)
+        return true; // silently ignore
+
+    return PDocumentRendererChild::Send__delete__(__a, width, height, data);
+}
+
+bool
+TabChild::RecvactivateFrameEvent(const nsString& aType, const bool& capture)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
+  NS_ENSURE_TRUE(window, true);
+  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;
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabChild.h
@@ -0,0 +1,128 @@
+/* -*- 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) 2009
+ * 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 mozilla_tabs_TabChild_h
+#define mozilla_tabs_TabChild_h
+
+#include "mozilla/dom/PIFrameEmbeddingChild.h"
+#include "nsIWebNavigation.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsIWebBrowserChrome2.h"
+#include "nsIEmbeddingSiteWindow2.h"
+#include "nsIWebBrowserChromeFocus.h"
+#include "nsIDOMEventListener.h"
+#include "nsIDOMEventTarget.h"
+
+namespace mozilla {
+namespace dom {
+
+class TabChild;
+
+class ContentListener : public nsIDOMEventListener
+{
+public:
+  ContentListener(TabChild* aTabChild) : mTabChild(aTabChild) {}
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMEVENTLISTENER
+protected:
+  TabChild* mTabChild;
+};
+
+class TabChild : public PIFrameEmbeddingChild,
+                 public nsIWebBrowserChrome2,
+                 public nsIEmbeddingSiteWindow2,
+                 public nsIWebBrowserChromeFocus
+{
+public:
+    TabChild();
+    virtual ~TabChild();
+    bool destroyWidget();
+    nsresult Init();
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIWEBBROWSERCHROME
+    NS_DECL_NSIWEBBROWSERCHROME2
+    NS_DECL_NSIEMBEDDINGSITEWINDOW
+    NS_DECL_NSIEMBEDDINGSITEWINDOW2
+    NS_DECL_NSIWEBBROWSERCHROMEFOCUS
+
+    virtual bool RecvcreateWidget(const MagicWindowHandle& parentWidget);
+    virtual bool RecvloadURL(const nsCString& uri);
+    virtual bool Recvmove(const PRUint32& x,
+                          const PRUint32& y,
+                          const PRUint32& width,
+                          const PRUint32& height);
+    virtual bool Recvactivate();
+    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 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);
+    virtual bool DeallocPDocumentRenderer(PDocumentRendererChild* actor);
+    virtual bool RecvPDocumentRendererConstructor(
+            mozilla::ipc::PDocumentRendererChild *__a,
+            const PRInt32& x,
+            const PRInt32& y,
+            const PRInt32& w,
+            const PRInt32& h,
+            const nsString& bgcolor,
+            const PRUint32& flags,
+            const bool& flush);
+
+private:
+    nsCOMPtr<nsIWebNavigation> mWebNav;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TabChild);
+};
+
+}
+}
+
+#endif // mozilla_tabs_TabChild_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabMessageUtils.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; 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) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Olli Pettay <Olli.Pettay@helsinki.fi>
+ *
+ * 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 "TabMessageUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMEvent.h"
+
+#ifdef CreateEvent
+#undef CreateEvent
+#endif
+
+#include "nsEventDispatcher.h"
+
+namespace mozilla {
+namespace dom {
+
+bool
+ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
+                RemoteDOMEvent* aResult)
+{
+  aResult->mEvent = nsnull;
+  nsString type;
+  NS_ENSURE_TRUE(ReadParam(aMsg, aIter, &type), false);
+
+  nsCOMPtr<nsIDOMEvent> event;
+  nsEventDispatcher::CreateEvent(nsnull, nsnull, type, getter_AddRefs(event));
+  aResult->mEvent = do_QueryInterface(event);
+  NS_ENSURE_TRUE(aResult->mEvent, false);
+
+  return aResult->mEvent->Deserialize(aMsg, aIter);
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabMessageUtils.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; 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) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Olli Pettay <Olli.Pettay@helsinki.fi>
+ *
+ * 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 TABMESSAGE_UTILS_H
+#define TABMESSAGE_UTILS_H
+
+#include "IPC/IPCMessageUtils.h"
+#include "nsIPrivateDOMEvent.h"
+#include "nsCOMPtr.h"
+
+namespace mozilla {
+namespace dom {
+struct RemoteDOMEvent
+{
+  nsCOMPtr<nsIPrivateDOMEvent> mEvent;
+};
+
+bool ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
+                     mozilla::dom::RemoteDOMEvent* aResult);
+
+}
+}
+
+namespace IPC {
+
+template<>
+struct ParamTraits<mozilla::dom::RemoteDOMEvent>
+{
+  typedef mozilla::dom::RemoteDOMEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    aParam.mEvent->Serialize(aMsg, PR_TRUE);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return mozilla::dom::ReadRemoteEvent(aMsg, aIter, aResult);
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+  }
+};
+
+
+}
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabParent.cpp
@@ -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) 2009
+ * 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 "TabParent.h"
+
+#include "mozilla/ipc/GeckoThread.h"
+#include "mozilla/ipc/DocumentRendererParent.h"
+
+#include "nsIURI.h"
+#include "nsFocusManager.h"
+#include "nsCOMPtr.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIDOMElement.h"
+#include "nsEventDispatcher.h"
+#include "nsIDOMEventTarget.h"
+#include "nsIDOMEvent.h"
+#include "nsIPrivateDOMEvent.h"
+
+using mozilla::ipc::BrowserProcessSubThread;
+using mozilla::ipc::DocumentRendererParent;
+
+namespace mozilla {
+namespace dom {
+
+TabParent::TabParent()
+{
+}
+
+TabParent::~TabParent()
+{
+}
+
+bool
+TabParent::RecvmoveFocus(const bool& aForward)
+{
+  nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
+  if (fm) {
+    nsCOMPtr<nsIDOMElement> dummy;
+    PRUint32 type = aForward ? nsIFocusManager::MOVEFOCUS_FORWARD
+                             : nsIFocusManager::MOVEFOCUS_BACKWARD;
+    fm->MoveFocus(nsnull, mFrameElement, type, nsIFocusManager::FLAG_BYKEY, 
+                  getter_AddRefs(dummy));
+  }
+  return true;
+}
+
+bool
+TabParent::RecvsendEvent(const RemoteDOMEvent& aEvent)
+{
+  nsCOMPtr<nsIDOMEvent> event = do_QueryInterface(aEvent.mEvent);
+  NS_ENSURE_TRUE(event, true);
+
+  nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mFrameElement);
+  NS_ENSURE_TRUE(target, true);
+
+  PRBool dummy;
+  target->DispatchEvent(event, &dummy);
+  return true;
+}
+
+void
+TabParent::LoadURL(nsIURI* aURI)
+{
+    nsCString spec;
+    aURI->GetSpec(spec);
+
+    SendloadURL(spec);
+}
+
+void
+TabParent::Move(PRUint32 x, PRUint32 y, PRUint32 width, PRUint32 height)
+{
+    Sendmove(x, y, width, height);
+}
+
+void
+TabParent::Activate()
+{
+    Sendactivate();
+}
+
+mozilla::ipc::PDocumentRendererParent*
+TabParent::AllocPDocumentRenderer(const PRInt32& x,
+        const PRInt32& y, const PRInt32& w, const PRInt32& h, const nsString& bgcolor,
+        const PRUint32& flags, const bool& flush)
+{
+    return new DocumentRendererParent();
+}
+
+bool
+TabParent::DeallocPDocumentRenderer(PDocumentRendererParent* actor)
+{
+    delete actor;
+    return true;
+}
+
+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);
+}
+
+} // namespace tabs
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabParent.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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) 2009
+ * 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 mozilla_tabs_TabParent_h
+#define mozilla_tabs_TabParent_h
+
+#include "mozilla/dom/PIFrameEmbeddingParent.h"
+
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+
+class nsIURI;
+class nsIDOMElement;
+
+namespace mozilla {
+namespace dom {
+
+class TabParent : public PIFrameEmbeddingParent
+{
+public:
+    TabParent();
+    virtual ~TabParent();
+    void SetOwnerElement(nsIDOMElement* aElement) { mFrameElement = aElement; }
+
+    virtual bool RecvmoveFocus(const bool& aForward);
+    virtual bool RecvsendEvent(const RemoteDOMEvent& aEvent);
+
+    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);
+
+    virtual mozilla::ipc::PDocumentRendererParent* AllocPDocumentRenderer(
+            const PRInt32& x,
+            const PRInt32& y,
+            const PRInt32& w,
+            const PRInt32& h,
+            const nsString& bgcolor,
+            const PRUint32& flags,
+            const bool& flush);
+    virtual bool DeallocPDocumentRenderer(PDocumentRendererParent* actor);
+protected:
+    nsIDOMElement* mFrameElement;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabTypes.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+
+#ifndef mozilla_tabs_TabTypes_h
+#define mozilla_tabs_TabTypes_h
+
+#include "base/basictypes.h"
+
+#ifdef XP_WIN
+#include <windows.h>
+
+typedef HWND MagicWindowHandle;
+#elif defined(MOZ_WIDGET_GTK2)
+#include <X11/X.h>
+
+typedef XID MagicWindowHandle;
+
+#elif defined(XP_MACOSX)
+#  warning This is a placeholder
+typedef long MagicWindowHandle;
+
+#else
+#error Not implemented, stooge
+#endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ipdl.mk
@@ -0,0 +1,41 @@
+# ***** 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) 2009
+# 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 *****
+
+IPDLSRCS = \
+  PContentProcess.ipdl \
+  PIFrameEmbedding.ipdl \
+  PDocumentRenderer.ipdl \
+  $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/ipc/jar.mn
@@ -0,0 +1,2 @@
+toolkit.jar:
+        content/global/test-ipc.xul (test.xul)
new file mode 100644
--- /dev/null
+++ b/dom/ipc/test.xul
@@ -0,0 +1,94 @@
+<?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">
+  <script>
+
+    function dumpClientRect(r) {
+      dump(r.left + "," + r.top + "," + r.right + "," +
+           r.bottom + "," + r.width + "," + r.height + "\n");
+    }
+
+    function handleMozAfterPaint(e) {
+      return;
+      dump(e.type + "\n")
+      var rects = e.clientRects;
+      var i;
+      dump("\tclientRects:\n");
+      for (i = 0; i &lt; rects.length; ++i) {
+        var r = rects.item(i);
+        dump("\t\t");
+        dumpClientRect(rects.item(i));
+      }
+
+      dump("\tboundingClientRect\n\t\t");
+      dumpClientRect(e.boundingClientRect);
+
+      var paintRequests = e.paintRequests;
+      dump("\tpaintRequests\n");
+      for (i = 0; i &lt; paintRequests.length; ++i) {
+        var pr = paintRequests.item(i);
+        dump("\t\t");
+        dumpClientRect(pr.clientRect);
+        if (pr.reason)
+          dump("\t\t" + pr.reason + "\n");
+      }
+    }
+
+    function handleMozScrolledAreaChanged(e) {
+      return;
+      dump(e.type + "\n");
+      dump("\t" + e.x + "," + e.y + "," + e.width + "," + e.height + "\n");
+    }
+
+    function restart() {
+      var y = document.getElementById('page');
+      var p = y.parentNode;
+      p.removeChild(y);
+      p.appendChild(y);
+
+      var fl = y.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
+      fl.activateFrameEvent("MozAfterPaint", true);
+      fl.activateFrameEvent("MozScrolledAreaChanged", true);
+      y.addEventListener("MozAfterPaint", handleMozAfterPaint, true);
+      y.addEventListener("MozScrolledAreaChanged", handleMozScrolledAreaChanged, true);
+    }
+    
+    function loadURL(url) {
+      document.getElementById('page').setAttribute('src', url);
+    }
+
+    function randomClick() {
+       // First focus the remote frame, then dispatch click. This way remote frame gets focus before
+       // mouse event.
+       document.getElementById('page').QueryInterface(Components.interfaces.nsIFrameLoaderOwner)
+                                      .frameLoader.activateRemoteFrame();
+       var frameLoader = document.getElementById('page').QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
+       var x = parseInt(Math.random() * 100);
+       var y = parseInt(Math.random() * 100);
+       frameLoader.sendCrossProcessMouseEvent("mousedown", x, y, 0, 1, 0, false);
+       frameLoader.sendCrossProcessMouseEvent("mouseup", x, y, 0, 1, 0, false);
+     }
+
+    function openWindow() {
+      window.open('chrome://global/content/test-ipc.xul', '_blank', 'chrome,resizable,width=800,height=800');
+    }
+    
+    function closeWindow() {
+      window.close();
+    }
+  </script>
+
+  <toolbar id="controls">
+    <toolbarbutton label="Back"/>
+    <toolbarbutton label="Forward"/>
+    <textbox onchange="loadURL(this.value)" flex="1" id="URL"/>
+    <toolbarbutton onclick="restart()" label="Recover"/>
+    <toolbarbutton onclick="randomClick()" label="random click"/>
+    <toolbarbutton onclick="openWindow()" label="open new window"/>
+    <toolbarbutton onclick="closeWindow()" label="close this window"/>
+  </toolbar>
+
+  <browser type="content" src="http://www.google.com/" flex="1" id="page" remote="true"
+           onfocus="this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.activateRemoteFrame();"/>
+</window>
--- a/ipc/Makefile.in
+++ b/ipc/Makefile.in
@@ -39,13 +39,13 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 # NB: chromium/ and glue/ are in tier_xpcom
 
 # tier_gecko:
-DIRS += ipdl
+DIRS += ipdl testshell
 
 TOOL_DIRS = app
 
 include $(topsrcdir)/config/rules.mk
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -50,17 +50,21 @@ FORCE_STATIC_LIB = 1
 LIBXUL_LIBRARY = 1
 EXPORT_LIBRARY = 1
 
 ##-----------------------------------------------------------------------------
 ## When you add IPDL files to a source directory, list the directory here.
 ##
 IPDLDIRS =  \
   dom/plugins  \
+  dom/ipc  \
+  netwerk/ipc  \
+  netwerk/protocol/http/src  \
   ipc/ipdl/test/cxx  \
+  ipc/testshell  \
   $(NULL)
 ##-----------------------------------------------------------------------------
 
 ifdef MOZ_IPDL_TESTS
 DIRS += test
 endif
 
 vpath %.ipdl $(topsrcdir)
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/Makefile.in
@@ -0,0 +1,74 @@
+# ***** 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 IPCShell.
+#
+# The Initial Developer of the Original Code is
+#   Ben Turner <bent.mozilla@gmail.com>.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# 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 *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcshell
+LIBRARY_NAME = ipcshell_s
+FORCE_STATIC_LIB = 1
+LIBXUL_LIBRARY = 1
+EXPORT_LIBRARY = 1
+
+EXPORTS_NAMESPACES = mozilla/ipc
+
+EXPORTS_mozilla/ipc = \
+  TestShellChild.h \
+  TestShellParent.h \
+  XPCShellEnvironment.h \
+  $(NULL)
+
+CPPSRCS += \
+  TestShellChild.cpp \
+  TestShellParent.cpp \
+  XPCShellEnvironment.cpp \
+  $(NULL)
+
+# For xpcshell error messages and nsDependentJSString
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/js/src/xpconnect/shell \
+  -I$(topsrcdir)/dom/base \
+  $(NULL)
+
+XPCSHELL_TESTS = tests
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/PTestShell.ipdl
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* ***** 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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 protocol "PContentProcess.ipdl";
+include protocol "PTestShellCommand.ipdl";
+
+namespace mozilla {
+namespace ipc {
+
+protocol PTestShell
+{
+  manager PContentProcess;
+
+  manages PTestShellCommand;
+
+child:
+  __delete__();
+
+  ExecuteCommand(nsString aCommand);
+
+  PTestShellCommand(nsString aCommand);
+};
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/PTestShellCommand.ipdl
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* ***** 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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 protocol "PTestShell.ipdl";
+
+namespace mozilla {
+namespace ipc {
+
+protocol PTestShellCommand
+{
+  manager PTestShell;
+
+parent:
+  __delete__(nsString aResponse);
+};
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/TestShellChild.cpp
@@ -0,0 +1,87 @@
+/* ***** 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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 "TestShellChild.h"
+
+using mozilla::ipc::TestShellChild;
+using mozilla::ipc::PTestShellCommandChild;
+using mozilla::ipc::XPCShellEnvironment;
+
+TestShellChild::TestShellChild()
+: mXPCShell(XPCShellEnvironment::CreateEnvironment())
+{
+}
+
+bool
+TestShellChild::RecvExecuteCommand(const nsString& aCommand)
+{
+  if (mXPCShell->IsQuitting()) {
+    NS_WARNING("Commands sent after quit command issued!");
+    return false;
+  }
+
+  return mXPCShell->EvaluateString(aCommand);
+}
+
+PTestShellCommandChild*
+TestShellChild::AllocPTestShellCommand(const nsString& aCommand)
+{
+  return new PTestShellCommandChild();
+}
+
+bool
+TestShellChild::DeallocPTestShellCommand(PTestShellCommandChild* aCommand)
+{
+  delete aCommand;
+  return true;
+}
+
+bool
+TestShellChild::RecvPTestShellCommandConstructor(PTestShellCommandChild* aActor,
+                                                 const nsString& aCommand)
+{
+  if (mXPCShell->IsQuitting()) {
+    NS_WARNING("Commands sent after quit command issued!");
+    return false;
+  }
+
+  nsString response;
+  if (!mXPCShell->EvaluateString(aCommand, &response)) {
+    return false;
+  }
+
+  return PTestShellCommandChild::Send__delete__(aActor, response);
+}
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/TestShellChild.h
@@ -0,0 +1,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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 ipc_testshell_TestShellChild_h
+#define ipc_testshell_TestShellChild_h 1
+
+#include "mozilla/ipc/PTestShellChild.h"
+#include "mozilla/ipc/PTestShellCommandChild.h"
+#include "mozilla/ipc/XPCShellEnvironment.h"
+
+#include "nsAutoPtr.h"
+
+namespace mozilla {
+namespace ipc {
+
+class XPCShellEnvironment;
+
+class TestShellChild : public PTestShellChild
+{
+public:
+  TestShellChild();
+
+  bool
+  RecvExecuteCommand(const nsString& aCommand);
+
+  PTestShellCommandChild*
+  AllocPTestShellCommand(const nsString& aCommand);
+
+  bool
+  RecvPTestShellCommandConstructor(PTestShellCommandChild* aActor,
+                                   const nsString& aCommand);
+
+  bool
+  DeallocPTestShellCommand(PTestShellCommandChild* aCommand);
+
+  void SetXPCShell(XPCShellEnvironment* aXPCShell) {
+    mXPCShell = aXPCShell;
+  }
+
+private:
+  nsAutoPtr<XPCShellEnvironment> mXPCShell;
+};
+
+} /* namespace ipc */
+} /* namespace mozilla */
+
+#endif /* ipc_testshell_TestShellChild_h */
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/TestShellParent.cpp
@@ -0,0 +1,110 @@
+/* ***** 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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 "TestShellParent.h"
+
+#include "nsAutoPtr.h"
+
+using mozilla::ipc::TestShellParent;
+using mozilla::ipc::TestShellCommandParent;
+using mozilla::ipc::PTestShellCommandParent;
+
+PTestShellCommandParent*
+TestShellParent::AllocPTestShellCommand(const nsString& aCommand)
+{
+  return new TestShellCommandParent();
+}
+
+bool
+TestShellParent::DeallocPTestShellCommand(PTestShellCommandParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+bool
+TestShellParent::CommandDone(TestShellCommandParent* command,
+                             const nsString& aResponse)
+{
+  // XXX what should happen if the callback fails?
+  /*JSBool ok = */command->RunCallback(aResponse);
+  command->ReleaseCallback();
+
+  return true;
+}
+
+JSBool
+TestShellCommandParent::SetCallback(JSContext* aCx,
+                                    jsval aCallback)
+{
+  if (!mCallback.Hold(aCx)) {
+    return JS_FALSE;
+  }
+
+  mCallback = aCallback;
+  mCx = aCx;
+
+  return JS_TRUE;
+}
+
+JSBool
+TestShellCommandParent::RunCallback(const nsString& aResponse)
+{
+  NS_ENSURE_TRUE(mCallback && mCx, JS_FALSE);
+
+  JSAutoRequest ar(mCx);
+
+  JSObject* global = JS_GetGlobalObject(mCx);
+  NS_ENSURE_TRUE(global, JS_FALSE);
+
+  JSString* str = JS_NewUCStringCopyN(mCx, aResponse.get(), aResponse.Length());
+  NS_ENSURE_TRUE(str, JS_FALSE);
+
+  jsval argv[] = { STRING_TO_JSVAL(str) };
+  int argc = NS_ARRAY_LENGTH(argv);
+
+  jsval rval;
+  JSBool ok = JS_CallFunctionValue(mCx, global, mCallback, argc, argv, &rval);
+  NS_ENSURE_TRUE(ok, JS_FALSE);
+
+  return JS_TRUE;
+}
+
+void
+TestShellCommandParent::ReleaseCallback()
+{
+  mCallback.Release();
+}
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/TestShellParent.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* ***** 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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 ipc_testshell_TestShellParent_h
+#define ipc_testshell_TestShellParent_h 1
+
+#include "mozilla/ipc/PTestShellParent.h"
+#include "mozilla/ipc/PTestShellCommandParent.h"
+
+#include "jsapi.h"
+#include "nsAutoJSValHolder.h"
+#include "nsStringGlue.h"
+
+namespace mozilla {
+namespace ipc {
+
+class TestShellCommandParent;
+
+
+class TestShellParent : public PTestShellParent
+{
+public:
+  PTestShellCommandParent*
+  AllocPTestShellCommand(const nsString& aCommand);
+
+  bool
+  DeallocPTestShellCommand(PTestShellCommandParent* aActor);
+
+  bool
+  CommandDone(TestShellCommandParent* aActor, const nsString& aResponse);
+};
+
+
+class TestShellCommandParent : public PTestShellCommandParent
+{
+public:
+  TestShellCommandParent() : mCx(NULL) { }
+
+  JSBool SetCallback(JSContext* aCx,
+                     jsval aCallback);
+
+  JSBool RunCallback(const nsString& aResponse);
+
+  void ReleaseCallback();
+
+protected:
+  bool Recv__delete__(const nsString& aResponse) {
+    return static_cast<TestShellParent*>(Manager())->CommandDone(
+      this, aResponse);
+  }
+
+private:
+  JSContext* mCx;
+  nsAutoJSValHolder mCallback;
+};
+
+
+} /* namespace ipc */
+} /* namespace mozilla */
+
+#endif /* ipc_testshell_TestShellParent_h */
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -0,0 +1,1258 @@
+/* ***** 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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 "XPCShellEnvironment.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_IO_H
+#include <io.h>     /* for isatty() */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for isatty() */
+#endif
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsdbgapi.h"
+#include "jsprf.h"
+
+#include "mozilla/XPCOM.h"
+
+#include "nsIChannel.h"
+#include "nsIClassInfo.h"
+#include "nsIDirectoryService.h"
+#include "nsIJSContextStack.h"
+#include "nsIJSRuntimeService.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsIURI.h"
+#include "nsIXPConnect.h"
+#include "nsIXPCScriptable.h"
+
+#include "nsJSUtils.h"
+#include "nsThreadUtils.h"
+#include "nsXULAppAPI.h"
+
+#include "TestShellChild.h"
+#include "TestShellParent.h"
+
+#define EXITCODE_RUNTIME_ERROR 3
+#define EXITCODE_FILE_NOT_FOUND 4
+
+using mozilla::ipc::XPCShellEnvironment;
+using mozilla::ipc::TestShellChild;
+using mozilla::ipc::TestShellParent;
+
+namespace {
+
+static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
+
+class FullTrustSecMan : public nsIScriptSecurityManager
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIXPCSECURITYMANAGER
+    NS_DECL_NSISCRIPTSECURITYMANAGER
+
+    FullTrustSecMan() { }
+    virtual ~FullTrustSecMan() { }
+
+    void SetSystemPrincipal(nsIPrincipal *aPrincipal) {
+        mSystemPrincipal = aPrincipal;
+    }
+
+private:
+    nsCOMPtr<nsIPrincipal> mSystemPrincipal;
+};
+
+class XPCShellDirProvider : public nsIDirectoryServiceProvider
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIDIRECTORYSERVICEPROVIDER
+
+    XPCShellDirProvider() { }
+    ~XPCShellDirProvider() { }
+
+    PRBool SetGREDir(const char *dir);
+    void ClearGREDir() { mGREDir = nsnull; }
+
+private:
+    nsCOMPtr<nsILocalFile> mGREDir;
+};
+
+inline XPCShellEnvironment*
+Environment(JSContext* cx)
+{
+    XPCShellEnvironment* env = 
+        static_cast<XPCShellEnvironment*>(JS_GetContextPrivate(cx));
+    NS_ASSERTION(env, "Should never be null!");
+    return env;
+}
+
+static void
+ScriptErrorReporter(JSContext *cx,
+                    const char *message,
+                    JSErrorReport *report)
+{
+    int i, j, k, n;
+    char *prefix = NULL, *tmp;
+    const char *ctmp;
+    JSStackFrame * fp = nsnull;
+    nsCOMPtr<nsIXPConnect> xpc;
+
+    // Don't report an exception from inner JS frames as the callers may intend
+    // to handle it.
+    while ((fp = JS_FrameIterator(cx, &fp))) {
+        if (!JS_IsNativeFrame(cx, fp)) {
+            return;
+        }
+    }
+
+    // In some cases cx->fp is null here so use XPConnect to tell us about inner
+    // frames.
+    if ((xpc = do_GetService(nsIXPConnect::GetCID()))) {
+        nsAXPCNativeCallContext *cc = nsnull;
+        xpc->GetCurrentNativeCallContext(&cc);
+        if (cc) {
+            nsAXPCNativeCallContext *prev = cc;
+            while (NS_SUCCEEDED(prev->GetPreviousCallContext(&prev)) && prev) {
+                PRUint16 lang;
+                if (NS_SUCCEEDED(prev->GetLanguage(&lang)) &&
+                    lang == nsAXPCNativeCallContext::LANG_JS) {
+                    return;
+                }
+            }
+        }
+    }
+
+    if (!report) {
+        fprintf(stderr, "%s\n", message);
+        return;
+    }
+
+    /* Conditionally ignore reported warnings. */
+    if (JSREPORT_IS_WARNING(report->flags) &&
+        !Environment(cx)->ShouldReportWarnings()) {
+        return;
+    }
+
+    if (report->filename)
+        prefix = JS_smprintf("%s:", report->filename);
+    if (report->lineno) {
+        tmp = prefix;
+        prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno);
+        JS_free(cx, tmp);
+    }
+    if (JSREPORT_IS_WARNING(report->flags)) {
+        tmp = prefix;
+        prefix = JS_smprintf("%s%swarning: ",
+                             tmp ? tmp : "",
+                             JSREPORT_IS_STRICT(report->flags) ? "strict " : "");
+        JS_free(cx, tmp);
+    }
+
+    /* embedded newlines -- argh! */
+    while ((ctmp = strchr(message, '\n')) != 0) {
+        ctmp++;
+        if (prefix) fputs(prefix, stderr);
+        fwrite(message, 1, ctmp - message, stderr);
+        message = ctmp;
+    }
+    /* If there were no filename or lineno, the prefix might be empty */
+    if (prefix)
+        fputs(prefix, stderr);
+    fputs(message, stderr);
+
+    if (!report->linebuf) {
+        fputc('\n', stderr);
+        goto out;
+    }
+
+    fprintf(stderr, ":\n%s%s\n%s", prefix, report->linebuf, prefix);
+    n = report->tokenptr - report->linebuf;
+    for (i = j = 0; i < n; i++) {
+        if (report->linebuf[i] == '\t') {
+            for (k = (j + 8) & ~7; j < k; j++) {
+                fputc('.', stderr);
+            }
+            continue;
+        }
+        fputc('.', stderr);
+        j++;
+    }
+    fputs("^\n", stderr);
+ out:
+    if (!JSREPORT_IS_WARNING(report->flags)) {
+        Environment(cx)->SetExitCode(EXITCODE_RUNTIME_ERROR);
+    }
+    JS_free(cx, prefix);
+}
+
+JSContextCallback gOldContextCallback = NULL;
+
+static JSBool
+ContextCallback(JSContext *cx,
+                uintN contextOp)
+{
+    if (gOldContextCallback && !gOldContextCallback(cx, contextOp))
+        return JS_FALSE;
+
+    if (contextOp == JSCONTEXT_NEW) {
+        JS_SetErrorReporter(cx, ScriptErrorReporter);
+        JS_SetVersion(cx, JSVERSION_LATEST);
+    }
+    return JS_TRUE;
+}
+
+static JSBool
+Print(JSContext *cx,
+      JSObject *obj,
+      uintN argc,
+      jsval *argv,
+      jsval *rval)
+{
+    uintN i, n;
+    JSString *str;
+
+    for (i = n = 0; i < argc; i++) {
+        str = JS_ValueToString(cx, argv[i]);
+        if (!str)
+            return JS_FALSE;
+        fprintf(stdout, "%s%s", i ? " " : "", JS_GetStringBytes(str));
+        fflush(stdout);
+    }
+    n++;
+    if (n)
+        fputc('\n', stdout);
+    return JS_TRUE;
+}
+
+static JSBool
+GetLine(char *bufp,
+        FILE *file,
+        const char *prompt)
+{
+    char line[256];
+    fprintf(stdout, prompt);
+    fflush(stdout);
+    if (!fgets(line, sizeof line, file))
+        return JS_FALSE;
+    strcpy(bufp, line);
+    return JS_TRUE;
+}
+
+static JSBool
+Dump(JSContext *cx,
+     JSObject *obj,
+     uintN argc,
+     jsval *argv,
+     jsval *rval)
+{
+    JSString *str;
+    if (!argc)
+        return JS_TRUE;
+
+    str = JS_ValueToString(cx, argv[0]);
+    if (!str)
+        return JS_FALSE;
+
+    fputs(JS_GetStringBytes(str), stdout);
+    fflush(stdout);
+    return JS_TRUE;
+}
+
+static JSBool
+Load(JSContext *cx,
+     JSObject *obj,
+     uintN argc,
+     jsval *argv,
+     jsval *rval)
+{
+    uintN i;
+    JSString *str;
+    const char *filename;
+    JSScript *script;
+    JSBool ok;
+    jsval result;
+    FILE *file;
+
+    for (i = 0; i < argc; i++) {
+        str = JS_ValueToString(cx, argv[i]);
+        if (!str)
+            return JS_FALSE;
+        argv[i] = STRING_TO_JSVAL(str);
+        filename = JS_GetStringBytes(str);
+        file = fopen(filename, "r");
+        if (!file) {
+            JS_ReportError(cx, "cannot open file '%s' for reading", filename);
+            return JS_FALSE;
+        }
+        script = JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
+                                                   Environment(cx)->GetPrincipal());
+        fclose(file);
+        if (!script)
+            return JS_FALSE;
+
+        ok = !Environment(cx)->ShouldCompileOnly()
+             ? JS_ExecuteScript(cx, obj, script, &result)
+             : JS_TRUE;
+        JS_DestroyScript(cx, script);
+        if (!ok)
+            return JS_FALSE;
+    }
+    return JS_TRUE;
+}
+
+static JSBool
+Version(JSContext *cx,
+        JSObject *obj,
+        uintN argc,
+        jsval *argv,
+        jsval *rval)
+{
+    if (argc > 0 && JSVAL_IS_INT(argv[0]))
+        *rval = INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(argv[0]))));
+    else
+        *rval = INT_TO_JSVAL(JS_GetVersion(cx));
+    return JS_TRUE;
+}
+
+static JSBool
+BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+    fprintf(stdout, "built on %s at %s\n", __DATE__, __TIME__);
+    return JS_TRUE;
+}
+
+static JSBool
+Quit(JSContext *cx,
+     JSObject *obj,
+     uintN argc,
+     jsval *argv,
+     jsval *rval)
+{
+    int exitCode = 0;
+    JS_ConvertArguments(cx, argc, argv, "/ i", &exitCode);
+
+    XPCShellEnvironment* env = Environment(cx);
+    env->SetExitCode(exitCode);
+    env->SetIsQuitting();
+
+    return JS_FALSE;
+}
+
+static JSBool
+DumpXPC(JSContext *cx,
+        JSObject *obj,
+        uintN argc,
+        jsval *argv,
+        jsval *rval)
+{
+    int32 depth = 2;
+
+    if (argc > 0) {
+        if (!JS_ValueToInt32(cx, argv[0], &depth))
+            return JS_FALSE;
+    }
+
+    nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
+    if(xpc)
+        xpc->DebugDump((int16)depth);
+    return JS_TRUE;
+}
+
+static JSBool
+GC(JSContext *cx,
+   JSObject *obj,
+   uintN argc,
+   jsval *argv,
+   jsval *rval)
+{
+    JSRuntime *rt;
+    uint32 preBytes;
+
+    rt = cx->runtime;
+    preBytes = rt->gcBytes;
+    JS_GC(cx);
+    fprintf(stdout, "before %lu, after %lu, break %08lx\n",
+           (unsigned long)preBytes, (unsigned long)rt->gcBytes,
+#ifdef XP_UNIX
+           (unsigned long)sbrk(0)
+#else
+           0
+#endif
+           );
+#ifdef JS_GCMETER
+    js_DumpGCStats(rt, stdout);
+#endif
+    return JS_TRUE;
+}
+
+#ifdef DEBUG
+
+static JSBool
+DumpHeap(JSContext *cx,
+         JSObject *obj,
+         uintN argc,
+         jsval *argv,
+         jsval *rval)
+{
+    char *fileName = NULL;
+    void* startThing = NULL;
+    uint32 startTraceKind = 0;
+    void *thingToFind = NULL;
+    size_t maxDepth = (size_t)-1;
+    void *thingToIgnore = NULL;
+    jsval *vp;
+    FILE *dumpFile;
+    JSBool ok;
+
+    vp = &argv[0];
+    if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
+        JSString *str;
+
+        str = JS_ValueToString(cx, *vp);
+        if (!str)
+            return JS_FALSE;
+        *vp = STRING_TO_JSVAL(str);
+        fileName = JS_GetStringBytes(str);
+    }
+
+    vp = &argv[1];
+    if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
+        if (!JSVAL_IS_TRACEABLE(*vp))
+            goto not_traceable_arg;
+        startThing = JSVAL_TO_TRACEABLE(*vp);
+        startTraceKind = JSVAL_TRACE_KIND(*vp);
+    }
+
+    vp = &argv[2];
+    if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
+        if (!JSVAL_IS_TRACEABLE(*vp))
+            goto not_traceable_arg;
+        thingToFind = JSVAL_TO_TRACEABLE(*vp);
+    }
+
+    vp = &argv[3];
+    if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
+        uint32 depth;
+
+        if (!JS_ValueToECMAUint32(cx, *vp, &depth))
+            return JS_FALSE;
+        maxDepth = depth;
+    }
+
+    vp = &argv[4];
+    if (*vp != JSVAL_NULL && *vp != JSVAL_VOID) {
+        if (!JSVAL_IS_TRACEABLE(*vp))
+            goto not_traceable_arg;
+        thingToIgnore = JSVAL_TO_TRACEABLE(*vp);
+    }
+
+    if (!fileName) {
+        dumpFile = stdout;
+    } else {
+        dumpFile = fopen(fileName, "w");
+        if (!dumpFile) {
+            fprintf(stderr, "dumpHeap: can't open %s: %s\n",
+                    fileName, strerror(errno));
+            return JS_FALSE;
+        }
+    }
+
+    ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
+                     maxDepth, thingToIgnore);
+    if (dumpFile != stdout)
+        fclose(dumpFile);
+    return ok;
+
+  not_traceable_arg:
+    fprintf(stderr,
+            "dumpHeap: argument %u is not null or a heap-allocated thing\n",
+            (unsigned)(vp - argv));
+    return JS_FALSE;
+}
+
+#endif /* DEBUG */
+
+static JSBool
+Clear(JSContext *cx,
+      JSObject *obj,
+      uintN argc,
+      jsval *argv,
+      jsval *rval)
+{
+    if (argc > 0 && !JSVAL_IS_PRIMITIVE(argv[0])) {
+        JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0]));
+    } else {
+        JS_ReportError(cx, "'clear' requires an object");
+        return JS_FALSE;
+    }
+    return JS_TRUE;
+}
+
+JSFunctionSpec gGlobalFunctions[] =
+{
+    {"print",           Print,          0,0,0},
+    {"load",            Load,           1,0,0},
+    {"quit",            Quit,           0,0,0},
+    {"version",         Version,        1,0,0},
+    {"build",           BuildDate,      0,0,0},
+    {"dumpXPC",         DumpXPC,        1,0,0},
+    {"dump",            Dump,           1,0,0},
+    {"gc",              GC,             0,0,0},
+    {"clear",           Clear,          1,0,0},
+#ifdef DEBUG
+    {"dumpHeap",        DumpHeap,       5,0,0},
+#endif
+#ifdef MOZ_SHARK
+    {"startShark",      js_StartShark,      0,0,0},
+    {"stopShark",       js_StopShark,       0,0,0},
+    {"connectShark",    js_ConnectShark,    0,0,0},
+    {"disconnectShark", js_DisconnectShark, 0,0,0},
+#endif
+#ifdef MOZ_CALLGRIND
+    {"startCallgrind",  js_StartCallgrind,  0,0,0},
+    {"stopCallgrind",   js_StopCallgrind,   0,0,0},
+    {"dumpCallgrind",   js_DumpCallgrind,   1,0,0},
+#endif
+    {nsnull,nsnull,0,0,0}
+};
+
+typedef enum JSShellErrNum
+{
+#define MSG_DEF(name, number, count, exception, format) \
+    name = number,
+#include "jsshell.msg"
+#undef MSG_DEF
+    JSShellErr_Limit
+#undef MSGDEF
+} JSShellErrNum;
+
+JSErrorFormatString gErrorFormatString[JSErr_Limit] =
+{
+#define MSG_DEF(name, number, count, exception, format) \
+    { format, count } ,
+#include "jsshell.msg"
+#undef MSG_DEF
+};
+
+static const JSErrorFormatString *
+GetErrorMessage(void *userRef,
+                const char *locale,
+                const uintN errorNumber)
+{
+    if ((errorNumber > 0) && (errorNumber < JSShellErr_Limit))
+        return &gErrorFormatString[errorNumber];
+
+    return NULL;
+}
+
+static void
+ProcessFile(JSContext *cx,
+            JSObject *obj,
+            const char *filename,
+            FILE *file,
+            JSBool forceTTY)
+{
+    XPCShellEnvironment* env = Environment(cx);
+    XPCShellEnvironment::AutoContextPusher pusher(env);
+
+    JSScript *script;
+    jsval result;
+    int lineno, startline;
+    JSBool ok, hitEOF;
+    char *bufp, buffer[4096];
+    JSString *str;
+
+    if (forceTTY) {
+        file = stdin;
+    }
+    else
+#ifdef HAVE_ISATTY
+    if (!isatty(fileno(file)))
+#endif
+    {
+        /*
+         * It's not interactive - just execute it.
+         *
+         * Support the UNIX #! shell hack; gobble the first line if it starts
+         * with '#'.  TODO - this isn't quite compatible with sharp variables,
+         * as a legal js program (using sharp variables) might start with '#'.
+         * But that would require multi-character lookahead.
+         */
+        int ch = fgetc(file);
+        if (ch == '#') {
+            while((ch = fgetc(file)) != EOF) {
+                if(ch == '\n' || ch == '\r')
+                    break;
+            }
+        }
+        ungetc(ch, file);
+
+        JSAutoRequest ar(cx);
+
+        JSScript* script =
+            JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
+                                              env->GetPrincipal());
+        if (script) {
+            if (!env->ShouldCompileOnly())
+                (void)JS_ExecuteScript(cx, obj, script, &result);
+            JS_DestroyScript(cx, script);
+        }
+
+        return;
+    }
+
+    /* It's an interactive filehandle; drop into read-eval-print loop. */
+    lineno = 1;
+    hitEOF = JS_FALSE;
+    do {
+        bufp = buffer;
+        *bufp = '\0';
+
+        JSAutoRequest ar(cx);
+
+        /*
+         * Accumulate lines until we get a 'compilable unit' - one that either
+         * generates an error (before running out of source) or that compiles
+         * cleanly.  This should be whenever we get a complete statement that
+         * coincides with the end of a line.
+         */
+        startline = lineno;
+        do {
+            if (!GetLine(bufp, file, startline == lineno ? "js> " : "")) {
+                hitEOF = JS_TRUE;
+                break;
+            }
+            bufp += strlen(bufp);
+            lineno++;
+        } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
+
+        /* Clear any pending exception from previous failed compiles.  */
+        JS_ClearPendingException(cx);
+        script =
+            JS_CompileScriptForPrincipals(cx, obj, env->GetPrincipal(), buffer,
+                                          strlen(buffer), "typein", startline);
+        if (script) {
+            JSErrorReporter older;
+
+            if (!env->ShouldCompileOnly()) {
+                ok = JS_ExecuteScript(cx, obj, script, &result);
+                if (ok && result != JSVAL_VOID) {
+                    /* Suppress error reports from JS_ValueToString(). */
+                    older = JS_SetErrorReporter(cx, NULL);
+                    str = JS_ValueToString(cx, result);
+                    JS_SetErrorReporter(cx, older);
+
+                    if (str)
+                        fprintf(stdout, "%s\n", JS_GetStringBytes(str));
+                    else
+                        ok = JS_FALSE;
+                }
+            }
+            JS_DestroyScript(cx, script);
+        }
+    } while (!hitEOF && !env->IsQuitting());
+
+    fprintf(stdout, "\n");
+}
+
+} /* anonymous namespace */
+
+NS_INTERFACE_MAP_BEGIN(FullTrustSecMan)
+    NS_INTERFACE_MAP_ENTRY(nsIXPCSecurityManager)
+    NS_INTERFACE_MAP_ENTRY(nsIScriptSecurityManager)
+    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCSecurityManager)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(FullTrustSecMan)
+NS_IMPL_RELEASE(FullTrustSecMan)
+
+NS_IMETHODIMP
+FullTrustSecMan::CanCreateWrapper(JSContext * aJSContext,
+                                  const nsIID & aIID,
+                                  nsISupports *aObj,
+                                  nsIClassInfo *aClassInfo,
+                                  void * *aPolicy)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CanCreateInstance(JSContext * aJSContext,
+                                   const nsCID & aCID)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CanGetService(JSContext * aJSContext,
+                               const nsCID & aCID)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CanAccess(PRUint32 aAction,
+                           nsAXPCNativeCallContext *aCallContext,
+                           JSContext * aJSContext,
+                           JSObject * aJSObject,
+                           nsISupports *aObj,
+                           nsIClassInfo *aClassInfo,
+                           jsval aName,
+                           void * *aPolicy)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
+                                     JSObject * aJSObject,
+                                     const char *aClassName,
+                                     jsval aProperty,
+                                     PRUint32 aAction)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckConnect(JSContext * aJSContext,
+                              nsIURI *aTargetURI,
+                              const char *aClassName,
+                              const char *aProperty)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx,
+                                        nsIURI *uri)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckLoadURIWithPrincipal(nsIPrincipal *aPrincipal,
+                                           nsIURI *uri,
+                                           PRUint32 flags)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckLoadURI(nsIURI *from,
+                              nsIURI *uri,
+                              PRUint32 flags)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckLoadURIStrWithPrincipal(nsIPrincipal *aPrincipal,
+                                              const nsACString & uri,
+                                              PRUint32 flags)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckLoadURIStr(const nsACString & from,
+                                 const nsACString & uri,
+                                 PRUint32 flags)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckFunctionAccess(JSContext * cx,
+                                     void * funObj,
+                                     void * targetObj)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CanExecuteScripts(JSContext * cx,
+                                   nsIPrincipal *principal,
+                                   PRBool *_retval)
+{
+    *_retval = PR_TRUE;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
+{
+    NS_IF_ADDREF(*_retval = mSystemPrincipal);
+    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
+{
+    NS_IF_ADDREF(*_retval = mSystemPrincipal);
+    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::GetCertificatePrincipal(const nsACString & aCertFingerprint,
+                                         const nsACString & aSubjectName,
+                                         const nsACString & aPrettyName,
+                                         nsISupports *aCert,
+                                         nsIURI *aURI,
+                                         nsIPrincipal **_retval)
+{
+    NS_IF_ADDREF(*_retval = mSystemPrincipal);
+    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::GetCodebasePrincipal(nsIURI *aURI,
+                                      nsIPrincipal **_retval)
+{
+    NS_IF_ADDREF(*_retval = mSystemPrincipal);
+    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::RequestCapability(nsIPrincipal *principal,
+                                   const char *capability,
+                                   PRInt16 *_retval)
+{
+    *_retval = nsIPrincipal::ENABLE_GRANTED;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::IsCapabilityEnabled(const char *capability,
+                                     PRBool *_retval)
+{
+    *_retval = PR_TRUE;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::EnableCapability(const char *capability)
+{
+    return NS_OK;;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::RevertCapability(const char *capability)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::DisableCapability(const char *capability)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::SetCanEnableCapability(const nsACString & certificateFingerprint,
+                                        const char *capability,
+                                        PRInt16 canEnable)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::GetObjectPrincipal(JSContext * cx,
+                                    JSObject * obj,
+                                    nsIPrincipal **_retval)
+{
+    NS_IF_ADDREF(*_retval = mSystemPrincipal);
+    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::SubjectPrincipalIsSystem(PRBool *_retval)
+{
+    *_retval = PR_TRUE;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckSameOrigin(JSContext * aJSContext,
+                                 nsIURI *aTargetURI)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::CheckSameOriginURI(nsIURI *aSourceURI,
+                                    nsIURI *aTargetURI,
+                                    PRBool reportError)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::GetPrincipalFromContext(JSContext * cx,
+                                         nsIPrincipal **_retval)
+{
+    NS_IF_ADDREF(*_retval = mSystemPrincipal);
+    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::GetChannelPrincipal(nsIChannel *aChannel,
+                                     nsIPrincipal **_retval)
+{
+    NS_IF_ADDREF(*_retval = mSystemPrincipal);
+    return *_retval ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::IsSystemPrincipal(nsIPrincipal *aPrincipal,
+                                   PRBool *_retval)
+{
+    *_retval = aPrincipal == mSystemPrincipal;
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(nsIPrincipal *)
+FullTrustSecMan::GetCxSubjectPrincipal(JSContext *cx)
+{
+    return mSystemPrincipal;
+}
+
+NS_IMETHODIMP_(nsIPrincipal *)
+FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx,
+                                               JSStackFrame **fp)
+{
+    *fp = nsnull;
+    return mSystemPrincipal;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::PushContextPrincipal(JSContext *cx,
+                                      JSStackFrame *fp,
+                                      nsIPrincipal *principal)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::PopContextPrincipal(JSContext *cx)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP_(nsrefcnt)
+XPCShellDirProvider::AddRef()
+{
+    return 2;
+}
+
+NS_IMETHODIMP_(nsrefcnt)
+XPCShellDirProvider::Release()
+{
+    return 1;
+}
+
+NS_IMPL_QUERY_INTERFACE1(XPCShellDirProvider, nsIDirectoryServiceProvider)
+
+PRBool
+XPCShellDirProvider::SetGREDir(const char *dir)
+{
+    nsresult rv = XRE_GetFileFromPath(dir, getter_AddRefs(mGREDir));
+    return NS_SUCCEEDED(rv);
+}
+
+NS_IMETHODIMP
+XPCShellDirProvider::GetFile(const char *prop,
+                             PRBool *persistent,
+                             nsIFile* *result)
+{
+    if (mGREDir && !strcmp(prop, NS_GRE_DIR)) {
+        *persistent = PR_TRUE;
+        NS_ADDREF(*result = mGREDir);
+        return NS_OK;
+    }
+
+    return NS_ERROR_FAILURE;
+}
+
+XPCShellEnvironment::
+AutoContextPusher::AutoContextPusher(XPCShellEnvironment* aEnv)
+{
+    NS_ASSERTION(aEnv->mCx, "Null context?!");
+
+    if (NS_SUCCEEDED(aEnv->mCxStack->Push(aEnv->mCx))) {
+        mEnv = aEnv;
+    }
+}
+
+XPCShellEnvironment::
+AutoContextPusher::~AutoContextPusher()
+{
+    if (mEnv) {
+        JSContext* cx;
+        mEnv->mCxStack->Pop(&cx);
+        NS_ASSERTION(cx == mEnv->mCx, "Wrong context on the stack!");
+    }
+}
+
+// static
+XPCShellEnvironment*
+XPCShellEnvironment::CreateEnvironment()
+{
+    XPCShellEnvironment* env = new XPCShellEnvironment();
+    if (env && !env->Init()) {
+        delete env;
+        env = nsnull;
+    }
+    return env;
+}
+
+XPCShellEnvironment::XPCShellEnvironment()
+:   mCx(NULL),
+    mJSPrincipals(NULL),
+    mExitCode(0),
+    mQuitting(JS_FALSE),
+    mReportWarnings(JS_TRUE),
+    mCompileOnly(JS_FALSE)
+{
+}
+
+XPCShellEnvironment::~XPCShellEnvironment()
+{
+    if (mCx) {
+        JS_BeginRequest(mCx);
+
+        JSObject* global = GetGlobalObject();
+        if (global) {
+            JS_ClearScope(mCx, global);
+        }
+        mGlobalHolder.Release();
+
+        JS_GC(mCx);
+
+        mCxStack = nsnull;
+
+        if (mJSPrincipals) {
+            JSPRINCIPALS_DROP(mCx, mJSPrincipals);
+        }
+
+        JSRuntime* rt = gOldContextCallback ? JS_GetRuntime(mCx) : NULL;
+
+        JS_DestroyContext(mCx);
+
+        if (gOldContextCallback) {
+            NS_ASSERTION(rt, "Should never be null!");
+            JS_SetContextCallback(rt, gOldContextCallback);
+            gOldContextCallback = NULL;
+        }
+    }
+}
+
+bool
+XPCShellEnvironment::Init()
+{
+    nsresult rv;
+
+#ifdef HAVE_SETBUF
+    // unbuffer stdout so that output is in the correct order; note that stderr
+    // is unbuffered by default
+    setbuf(stdout, 0);
+#endif
+
+    nsCOMPtr<nsIJSRuntimeService> rtsvc =
+        do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+    if (!rtsvc) {
+        NS_ERROR("failed to get nsJSRuntimeService!");
+        return false;
+    }
+
+    JSRuntime *rt;
+    if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
+        NS_ERROR("failed to get JSRuntime from nsJSRuntimeService!");
+        return false;
+    }
+
+    if (!mGlobalHolder.Hold(rt)) {
+        NS_ERROR("Can't protect global object!");
+        return false;
+    }
+
+    gOldContextCallback = JS_SetContextCallback(rt, ContextCallback);
+
+    JSContext *cx = JS_NewContext(rt, 8192);
+    if (!cx) {
+        NS_ERROR("JS_NewContext failed!");
+
+        JS_SetContextCallback(rt, gOldContextCallback);
+        gOldContextCallback = NULL;
+
+        return false;
+    }
+    mCx = cx;
+
+    JS_SetContextPrivate(cx, this);
+
+    nsCOMPtr<nsIXPConnect> xpc =
+      do_GetService(nsIXPConnect::GetCID());
+    if (!xpc) {
+        NS_ERROR("failed to get nsXPConnect service!");
+        return false;
+    }
+
+    nsRefPtr<FullTrustSecMan> secman(new FullTrustSecMan());
+    xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF);
+
+    nsCOMPtr<nsIPrincipal> principal;
+
+    nsCOMPtr<nsIScriptSecurityManager> securityManager =
+        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+    if (NS_SUCCEEDED(rv) && securityManager) {
+        rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
+        if (NS_FAILED(rv)) {
+            fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
+        } else {
+            // fetch the JS principals and stick in a global
+            rv = principal->GetJSPrincipals(cx, &mJSPrincipals);
+            if (NS_FAILED(rv)) {
+                fprintf(stderr, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
+            }
+            secman->SetSystemPrincipal(principal);
+        }
+    } else {
+        fprintf(stderr, "+++ Failed to get ScriptSecurityManager service, running without principals");
+    }
+
+    nsCOMPtr<nsIJSContextStack> cxStack =
+        do_GetService("@mozilla.org/js/xpc/ContextStack;1");
+    if (!cxStack) {
+        NS_ERROR("failed to get the nsThreadJSContextStack service!");
+        return false;
+    }
+    mCxStack = cxStack;
+
+    AutoContextPusher pusher(this);
+
+    nsCOMPtr<nsIXPCScriptable> backstagePass;
+    rv = rtsvc->GetBackstagePass(getter_AddRefs(backstagePass));
+    if (NS_FAILED(rv)) {
+        NS_ERROR("Failed to get backstage pass from rtsvc!");
+        return false;
+    }
+
+    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+    rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
+                                              NS_GET_IID(nsISupports),
+                                              nsIXPConnect::
+                                                  FLAG_SYSTEM_GLOBAL_OBJECT,
+                                              getter_AddRefs(holder));
+    if (NS_FAILED(rv)) {
+        NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
+        return false;
+    }
+
+    JSObject *globalObj;
+    rv = holder->GetJSObject(&globalObj);
+    if (NS_FAILED(rv)) {
+        NS_ERROR("Failed to get global JSObject!");
+        return false;
+    }
+
+
+    {
+        JSAutoRequest ar(cx);
+
+        if (!JS_DefineFunctions(cx, globalObj, gGlobalFunctions)) {
+            NS_ERROR("JS_DefineFunctions failed!");
+            return false;
+        }
+    }
+
+    mGlobalHolder = globalObj;
+
+    FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
+    if (runtimeScriptFile) {
+        fprintf(stdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
+        ProcessFile(cx, globalObj, kDefaultRuntimeScriptFilename,
+                    runtimeScriptFile, JS_FALSE);
+        fclose(runtimeScriptFile);
+    }
+
+    return true;
+}
+
+bool
+XPCShellEnvironment::EvaluateString(const nsString& aString,
+                                    nsString* aResult)
+{
+  JSAutoRequest ar(mCx);
+
+  JS_ClearPendingException(mCx);
+
+  JSObject* global = GetGlobalObject();
+
+  JSScript* script =
+      JS_CompileUCScriptForPrincipals(mCx, global, GetPrincipal(),
+                                      aString.get(), aString.Length(),
+                                      "typein", 0);
+  if (!script) {
+     return false;
+  }
+
+  if (!ShouldCompileOnly()) {
+      if (aResult) {
+          aResult->Truncate();
+      }
+
+      jsval result;
+      JSBool ok = JS_ExecuteScript(mCx, global, script, &result);
+      if (ok && result != JSVAL_VOID) {
+          JSErrorReporter old = JS_SetErrorReporter(mCx, NULL);
+          JSString* str = JS_ValueToString(mCx, result);
+          JS_SetErrorReporter(mCx, old);
+
+          if (str && aResult) {
+              aResult->Assign(nsDependentJSString(str));
+          }
+      }
+  }
+
+  JS_DestroyScript(mCx, script);
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/XPCShellEnvironment.h
@@ -0,0 +1,132 @@
+/* ***** 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 IPCShell.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * 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 _IPC_TESTSHELL_XPCSHELLENVIRONMENT_H_
+#define _IPC_TESTSHELL_XPCSHELLENVIRONMENT_H_
+
+#include "base/basictypes.h"
+
+#include <string>
+#include <stdio.h>
+
+#include "nsAutoJSValHolder.h"
+#include "nsCOMPtr.h"
+#include "nsDebug.h"
+#include "nsStringGlue.h"
+
+struct JSContext;
+struct JSObject;
+struct JSPrincipals;
+
+class nsIJSContextStack;
+
+namespace mozilla {
+namespace ipc {
+
+class XPCShellEnvironment
+{
+public:
+    static XPCShellEnvironment* CreateEnvironment();
+    ~XPCShellEnvironment();
+
+    bool EvaluateString(const nsString& aString,
+                        nsString* aResult = nsnull);
+
+    JSPrincipals* GetPrincipal() {
+        return mJSPrincipals;
+    }
+
+    JSObject* GetGlobalObject() {
+        return mGlobalHolder.ToJSObject();
+    }
+
+    void SetExitCode(int aExitCode) {
+        mExitCode = aExitCode;
+    }
+    int ExitCode() {
+        return mExitCode;
+    }
+
+    void SetIsQuitting() {
+        mQuitting = JS_TRUE;
+    }
+    JSBool IsQuitting() {
+        return mQuitting;
+    }
+
+    void SetShouldReportWarnings(JSBool aReportWarnings) {
+        mReportWarnings = aReportWarnings;
+    }
+    JSBool ShouldReportWarnings() {
+        return mReportWarnings;
+    }
+
+    void SetShouldCompoleOnly(JSBool aCompileOnly) {
+        mCompileOnly = aCompileOnly;
+    }
+    JSBool ShouldCompileOnly() {
+        return mCompileOnly;
+    }
+
+    class AutoContextPusher
+    {
+    public:
+        AutoContextPusher(XPCShellEnvironment* aEnv);
+        ~AutoContextPusher();
+    private:
+        XPCShellEnvironment* mEnv;
+    };
+
+protected:
+    XPCShellEnvironment();
+    bool Init();
+
+private:
+    JSContext* mCx;
+    nsAutoJSValHolder mGlobalHolder;
+    nsCOMPtr<nsIJSContextStack> mCxStack;
+    JSPrincipals* mJSPrincipals;
+
+    int mExitCode;
+    JSBool mQuitting;
+    JSBool mReportWarnings;
+    JSBool mCompileOnly;
+};
+
+} /* namespace ipc */
+} /* namespace mozilla */
+
+#endif /* _IPC_TESTSHELL_XPCSHELLENVIRONMENT_H_ */
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/ipdl.mk
@@ -0,0 +1,4 @@
+IPDLSRCS = \
+  PTestShell.ipdl \
+  PTestShellCommand.ipdl \
+  $(NULL)
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/tests/test_ipcshell.js
@@ -0,0 +1,15 @@
+function callback(result) {
+  do_check_eq(result, Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT);
+  do_test_finished();
+}
+
+function run_test() {
+  do_test_pending();
+
+  do_check_eq(runtime.processType, Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
+  
+  sendCommand("load('test_ipcshell_child.js');");
+  sendCommand("runtime.processType;", callback);
+}
+load('test_ipcshell_child.js');
+
new file mode 100644
--- /dev/null
+++ b/ipc/testshell/tests/test_ipcshell_child.js
@@ -0,0 +1,9 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+const runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
+
+if (typeof(run_test) == "undefined") {
+  run_test = function() {
+    do_check_eq(runtime.processType, Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
+  }
}
--- a/js/src/xpconnect/shell/Makefile.in
+++ b/js/src/xpconnect/shell/Makefile.in
@@ -64,16 +64,18 @@ NSDISTMODE = copy
 
 ifdef _MSC_VER
 ifdef WINCE
 WIN32_EXE_LDFLAGS += -ENTRY:mainWCRTStartup
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre/
 endif
 endif
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES		+= -DJS_THREADSAFE
 
 ifdef MOZ_SHARK
 DEFINES += -DMOZ_SHARK
 CFLAGS += -F/System/Library/PrivateFrameworks
 LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -40,16 +40,21 @@
  * 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 ***** */
 
 /* XPConnect JavaScript interactive shell. */
 
+#ifdef MOZ_IPC
+#include "mozilla/dom/ContentProcessParent.h"
+#include "mozilla/ipc/TestShellParent.h"
+#endif
+
 #include <stdio.h>
 #include "nsXULAppAPI.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsStringAPI.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptable.h"
 #include "nsIInterfaceInfo.h"
@@ -104,16 +109,21 @@
 #endif
 
 #include "nsIJSContextStack.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsICrashReporter.h"
 #endif
 
+#ifdef MOZ_IPC
+using mozilla::dom::ContentProcessParent;
+using mozilla::ipc::TestShellParent;
+#endif
+
 class XPCShellDirProvider : public nsIDirectoryServiceProvider2
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIDIRECTORYSERVICEPROVIDER
     NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
 
     XPCShellDirProvider() { }
@@ -645,16 +655,51 @@ Clear(JSContext *cx, JSObject *obj, uint
         JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0]));
     } else {
         JS_ReportError(cx, "'clear' requires an object");
         return JS_FALSE;
     }
     return JS_TRUE;
 }
 
+#ifdef MOZ_IPC
+
+static JSBool
+SendCommand(JSContext* cx,
+            JSObject* obj,
+            uintN argc,
+            jsval* argv,
+            jsval* rval)
+{
+    if (argc == 0) {
+        JS_ReportError(cx, "Function takes at least one argument!");
+        return JS_FALSE;
+    }
+
+    JSString* str = JS_ValueToString(cx, argv[0]);
+    if (!str) {
+        JS_ReportError(cx, "Could not convert argument 1 to string!");
+        return JS_FALSE;
+    }
+
+    if (argc > 1 && JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) {
+        JS_ReportError(cx, "Could not convert argument 2 to function!");
+        return JS_FALSE;
+    }
+
+    if (!XRE_SendTestShellCommand(cx, str, argc > 1 ? &argv[1] : nsnull)) {
+        JS_ReportError(cx, "Couldn't send command!");
+        return JS_FALSE;
+    }
+
+    return JS_TRUE;
+}
+
+#endif // MOZ_IPC
+
 /*
  * JSContext option name to flag map. The option names are in alphabetical
  * order for better reporting.
  */
 static const struct {
     const char  *name;
     uint32      flag;
 } js_options[] = {
@@ -758,16 +803,19 @@ static JSFunctionSpec glob_functions[] =
     {"dumpXPC",         DumpXPC,        1,0,0},
     {"dump",            Dump,           1,0,0},
     {"gc",              GC,             0,0,0},
     {"clear",           Clear,          1,0,0},
     {"options",         Options,        0,0,0},
 #ifdef DEBUG
     {"dumpHeap",        DumpHeap,       5,0,0},
 #endif
+#ifdef MOZ_IPC
+    {"sendCommand",     SendCommand,    1,0,0},
+#endif
 #ifdef MOZ_SHARK
     {"startShark",      js_StartShark,      0,0,0},
     {"stopShark",       js_StopShark,       0,0,0},
     {"connectShark",    js_ConnectShark,    0,0,0},
     {"disconnectShark", js_DisconnectShark, 0,0,0},
 #endif
 #ifdef MOZ_CALLGRIND
     {"startCallgrind",  js_StartCallgrind,  0,0,0},
@@ -1894,16 +1942,21 @@ main(int argc, char **argv)
         JSContext *oldcx;
         cxstack->Pop(&oldcx);
         NS_ASSERTION(oldcx == cx, "JS thread context push/pop mismatch");
         cxstack = nsnull;
         JS_GC(cx);
         JS_DestroyContext(cx);
     } // this scopes the nsCOMPtrs
 
+#ifdef MOZ_IPC
+    if (!XRE_ShutdownTestShell())
+        NS_ERROR("problem shutting down testshell");
+#endif
+
 #ifdef MOZ_CRASHREPORTER
     // Get the crashreporter service while XPCOM is still active.
     // This is a special exception: it will remain usable after NS_ShutdownXPCOM().
     nsCOMPtr<nsICrashReporter> crashReporter =
         do_GetService("@mozilla.org/toolkit/crash-reporter;1");
 #endif
 
     // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
--- a/layout/generic/nsFrameFrame.cpp
+++ b/layout/generic/nsFrameFrame.cpp
@@ -176,16 +176,17 @@ public:
 #ifdef ACCESSIBILITY
   NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
 #endif
 
   // nsIFrameFrame
   NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
   NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther);
   virtual void EndSwapDocShells(nsIFrame* aOther);
+  virtual nsIFrame* GetFrame() { return this; }
 
   // nsIReflowCallback
   virtual PRBool ReflowFinished();
   virtual void ReflowCallbackCanceled();
 
 protected:
   // Helper method to look up the HTML marginwidth & marginheight attributes
   nsIntSize GetMarginAttributes();
@@ -622,62 +623,26 @@ nsSubDocumentFrame::Reflow(nsPresContext
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 PRBool
 nsSubDocumentFrame::ReflowFinished()
 {
-  nsCOMPtr<nsIDocShell> docShell;
-  GetDocShell(getter_AddRefs(docShell));
-
-  nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
-
-  // resize the sub document
-  if (baseWindow) {
-    PRInt32 x = 0;
-    PRInt32 y = 0;
+  if (mFrameLoader) {
+    nsWeakFrame weakFrame(this);
 
-    nsWeakFrame weakFrame(this);
-    
-    nsPresContext* presContext = PresContext();
-    baseWindow->GetPositionAndSize(&x, &y, nsnull, nsnull);
-
-    if (!weakFrame.IsAlive()) {
-      // GetPositionAndSize() killed us
-      return PR_FALSE;
-    }
+    mFrameLoader->UpdatePositionAndSize(this);
 
-    // GetPositionAndSize might have resized us.  So now is the time to
-    // get our size.
-    mPostedReflowCallback = PR_FALSE;
-  
-    nsSize innerSize(GetSize());
-    if (IsInline()) {
-      nsMargin usedBorderPadding = GetUsedBorderAndPadding();
-
-      // Sadly, XUL smacks the frame size without changing the used
-      // border and padding, so we can't trust those.  Subtracting
-      // them might make things negative.
-      innerSize.width  -= usedBorderPadding.LeftRight();
-      innerSize.width = NS_MAX(innerSize.width, 0);
-      
-      innerSize.height -= usedBorderPadding.TopBottom();
-      innerSize.height = NS_MAX(innerSize.height, 0);
-    }  
-
-    PRInt32 cx = presContext->AppUnitsToDevPixels(innerSize.width);
-    PRInt32 cy = presContext->AppUnitsToDevPixels(innerSize.height);
-    baseWindow->SetPositionAndSize(x, y, cx, cy, PR_FALSE);
-  } else {
-    // Make sure that we can post a reflow callback in the future.
-    mPostedReflowCallback = PR_FALSE;
+    if (weakFrame.IsAlive()) {
+      // Make sure that we can post a reflow callback in the future.
+      mPostedReflowCallback = PR_FALSE;
+    }
   }
-
   return PR_FALSE;
 }
 
 void
 nsSubDocumentFrame::ReflowCallbackCanceled()
 {
   mPostedReflowCallback = PR_FALSE;
 }
--- a/layout/generic/nsIFrameFrame.h
+++ b/layout/generic/nsIFrameFrame.h
@@ -60,11 +60,13 @@ public:
    */
   NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther) = 0;
   virtual void EndSwapDocShells(nsIFrame* aOther) = 0;
 
   /**
    * The frameloader informs us what kind of widget to create during Show()
    */
   virtual nsIView* CreateViewAndWidget(nsContentType aContentType) = 0;
+
+  virtual nsIFrame* GetFrame() = 0;
 };
 
 #endif
--- a/netwerk/Makefile.in
+++ b/netwerk/Makefile.in
@@ -51,16 +51,22 @@ DIRS		= \
 		socket \
 		mime \
 		streamconv \
 		cache \
 		protocol \
 		system \
         $(NULL)
 
+ifdef MOZ_IPC
+DIRS 		+= \
+	        ipc  \
+	        $(NULL)
+endif
+
 ifdef NECKO_WIFI
 DIRS 		+= wifi
 endif
 
 DIRS		+= \
 		build \
 		locales \
 		$(NULL)
--- a/netwerk/build.mk
+++ b/netwerk/build.mk
@@ -40,20 +40,17 @@
 ifndef tier_nspr_dirs
 include $(topsrcdir)/config/nspr/build.mk
 endif
 
 ifndef tier_xpcom_dirs
 include $(topsrcdir)/xpcom/build.mk
 endif
 
-TIERS += zlib \
-	necko \
-	$(NULL)
-
+TIERS += zlib
 
 ifndef MOZ_NATIVE_ZLIB
 tier_zlib_dirs	+= modules/zlib
 endif
 
 #
 # tier "necko" - the networking library and its dependencies
 #
--- a/netwerk/build/Makefile.in
+++ b/netwerk/build/Makefile.in
@@ -58,16 +58,23 @@ SHARED_LIBRARY_LIBS = \
 		../base/src/$(LIB_PREFIX)neckobase_s.$(LIB_SUFFIX) \
 		../dns/src/$(LIB_PREFIX)neckodns_s.$(LIB_SUFFIX) \
 		../socket/base/$(LIB_PREFIX)neckosocket_s.$(LIB_SUFFIX) \
 		../streamconv/src/$(LIB_PREFIX)nkconv_s.$(LIB_SUFFIX) \
 		../streamconv/converters/$(LIB_PREFIX)nkcnvts_s.$(LIB_SUFFIX) \
 		../mime/src/$(LIB_PREFIX)nkmime_s.$(LIB_SUFFIX) \
 		../cache/src/$(LIB_PREFIX)nkcache_s.$(LIB_SUFFIX) \
 		../protocol/about/src/$(LIB_PREFIX)nkabout_s.$(LIB_SUFFIX) \
+		$(NULL)
+
+ifdef MOZ_IPC
+SHARED_LIBRARY_LIBS += ../ipc/$(LIB_PREFIX)neckoipc_s.$(LIB_SUFFIX)
+endif
+
+SHARED_LIBRARY_LIBS += \
 		$(foreach d,$(filter-out about,$(NECKO_PROTOCOLS)), \
 			../protocol/$(d)/src/$(LIB_PREFIX)nk$(d)_s.$(LIB_SUFFIX)) \
 		$(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
     SHARED_LIBRARY_LIBS += \
         ../system/win32/$(LIB_PREFIX)neckosystem_s.$(LIB_SUFFIX)
 endif
@@ -149,15 +156,17 @@ EXTRA_DSO_LDOPTS += \
 		$(TK_LIBS) \
 	$(NULL)
 endif
 
 ifeq ($(OS_ARCH),AIX)
 EXTRA_DSO_LDOPTS += -lodm -lcfg
 endif
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS	+= $(call EXPAND_LIBNAME,ole32 shell32)
 endif
 
 DEFINES += -DIMPL_NS_NET
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -32,16 +32,20 @@
  * 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 "necko-config.h"
 
+#ifdef MOZ_IPC
+#include "base/basictypes.h"
+#endif 
+
 #include "nsCOMPtr.h"
 #include "nsIModule.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIGenericFactory.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsICategoryManager.h"
 #include "nsSocketProviderService.h"
--- a/netwerk/dns/src/nsIDNKitInterface.h
+++ b/netwerk/dns/src/nsIDNKitInterface.h
@@ -87,16 +87,17 @@ typedef enum {
 typedef struct idn_nameprep *idn_nameprep_t;
 
 
 /*
  * The latest version of nameprep.
  */
 #define IDN_NAMEPREP_CURRENT	"nameprep-11"
 
+#undef assert
 #define assert(a)
 #define TRACE(a)
 
 
 /* race.c */
 idn_result_t	race_decode_decompress(const char *from,
 					       PRUint16 *buf,
 					       size_t buflen);
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/Makefile.in
@@ -0,0 +1,65 @@
+# ***** 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 Firefox.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):  Jason Duell
+#
+# 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 *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = necko
+
+LIBRARY_NAME = neckoipc_s
+LIBXUL_LIBRARY = 1
+FORCE_STATIC_LIB = 1
+EXPORT_LIBRARY = 1
+
+EXPORTS_NAMESPACES = mozilla/net
+
+EXPORTS_mozilla/net = \
+  NeckoParent.h       \
+  NeckoChild.h        \
+  $(NULL)
+
+CPPSRCS =               \
+  NeckoChild.cpp        \
+  NeckoParent.cpp       \
+  $(NULL)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 "mozilla/net/NeckoChild.h"
+#include "mozilla/dom/ContentProcessChild.h"
+#include "mozilla/net/HttpChannelChild.h"
+
+namespace mozilla {
+namespace net {
+
+PNeckoChild *gNeckoChild = nsnull;
+
+// C++ file contents
+NeckoChild::NeckoChild()
+{
+}
+
+NeckoChild::~NeckoChild()
+{
+}
+
+void NeckoChild::InitNeckoChild()
+{
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    mozilla::dom::ContentProcessChild * cpc = 
+      mozilla::dom::ContentProcessChild::GetSingleton();
+    NS_ASSERTION(cpc, "Content Protocol is NULL!");
+    gNeckoChild = cpc->SendPNeckoConstructor(); 
+    NS_ASSERTION(gNeckoChild, "PNecko Protocol init failed!");
+  }
+}
+
+PHttpChannelChild* 
+NeckoChild::AllocPHttpChannel()
+{
+  return new HttpChannelChild();
+}
+
+bool 
+NeckoChild::DeallocPHttpChannel(PHttpChannelChild* channel)
+{
+  delete channel;
+  return true;
+}
+
+}} // mozilla::net
+
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/NeckoChild.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 mozilla_net_NeckoChild_h
+#define mozilla_net_NeckoChild_h
+
+#include "mozilla/net/PNeckoChild.h"
+#include "mozilla/net/HttpChannelChild.h"
+#include "nsXULAppAPI.h"
+
+namespace mozilla {
+namespace net {
+
+// Header file contents
+class NeckoChild :
+  public PNeckoChild
+{
+public:
+  NeckoChild();
+  virtual ~NeckoChild();
+
+  static void InitNeckoChild();
+
+  virtual PHttpChannelChild* AllocPHttpChannel();
+  virtual bool DeallocPHttpChannel(PHttpChannelChild*);
+
+protected:
+};
+
+/**
+ * Reference to the PNecko Child protocol.
+ * Null if this is not a content process.
+ */
+extern PNeckoChild *gNeckoChild;
+
+static inline PRBool 
+IsNeckoChild() 
+{
+  return XRE_GetProcessType() == GeckoProcessType_Content;        
+}
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_NeckoChild_h
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 "mozilla/net/NeckoParent.h"
+#include "mozilla/net/HttpChannelParent.h"
+
+namespace mozilla {
+namespace net {
+
+// C++ file contents
+NeckoParent::NeckoParent()
+{
+}
+
+NeckoParent::~NeckoParent()
+{
+}
+
+PHttpChannelParent* 
+NeckoParent::AllocPHttpChannel()
+{
+  return new HttpChannelParent();
+}
+
+bool 
+NeckoParent::DeallocPHttpChannel(PHttpChannelParent* channel)
+{
+  delete channel;
+  return true;
+}
+
+
+}} // mozilla::net
+
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/NeckoParent.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 "mozilla/net/PNeckoParent.h"
+#include "mozilla/net/HttpChannelChild.h"
+
+#ifndef mozilla_net_NeckoParent_h
+#define mozilla_net_NeckoParent_h
+
+namespace mozilla {
+namespace net {
+
+// Header file contents
+class NeckoParent :
+  public PNeckoParent
+{
+public:
+  NeckoParent();
+  virtual ~NeckoParent();
+
+protected:
+  virtual PHttpChannelParent* AllocPHttpChannel();
+  virtual bool DeallocPHttpChannel(PHttpChannelParent*);
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_NeckoParent_h
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/PNecko.ipdl
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 protocol "PContentProcess.ipdl";
+include protocol "PHttpChannel.ipdl";
+
+namespace mozilla {
+namespace net {
+
+
+//-------------------------------------------------------------------
+protocol PNecko
+{
+  manager PContentProcess;
+  manages PHttpChannel;
+
+parent:
+  __delete__();
+
+  PHttpChannel();
+};
+
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/ipc/ipdl.mk
@@ -0,0 +1,40 @@
+# ***** 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 Firefox.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):  Jason Duell
+#
+# 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 *****
+
+IPDLSRCS =          \
+  PNecko.ipdl       \
+  $(NULL)
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/HttpChannelChild.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 "mozilla/net/HttpChannelChild.h"
+#include "mozilla/dom/ContentProcessChild.h"
+
+namespace mozilla {
+namespace net {
+
+// C++ file contents
+HttpChannelChild::HttpChannelChild()
+{
+}
+
+HttpChannelChild::~HttpChannelChild()
+{
+}
+
+}} // mozilla::net
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/HttpChannelChild.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 mozilla_net_HttpChannelChild_h
+#define mozilla_net_HttpChannelChild_h
+
+#include "mozilla/net/PHttpChannelChild.h"
+#include "nsXULAppAPI.h"
+
+namespace mozilla {
+namespace net {
+
+// Header file contents
+class HttpChannelChild :
+  public PHttpChannelChild
+{
+public:
+  HttpChannelChild();
+  virtual ~HttpChannelChild();
+
+protected:
+};
+
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_HttpChannelChild_h
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/HttpChannelParent.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 "mozilla/net/HttpChannelParent.h"
+
+namespace mozilla {
+namespace net {
+
+// C++ file contents
+HttpChannelParent::HttpChannelParent()
+{
+}
+
+HttpChannelParent::~HttpChannelParent()
+{
+}
+
+//-----------------------------------------------------------------------------
+// 
+bool HttpChannelParent::RecvasyncOpen(const nsCString& uri)
+{
+  puts("[HttpChannelParent] got asyncOpen msg");
+  return true;
+}
+
+}} // mozilla::net
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/HttpChannelParent.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 mozilla_net_HttpChannelParent_h
+#define mozilla_net_HttpChannelParent_h
+
+#include "mozilla/net/PHttpChannelParent.h"
+
+namespace mozilla {
+namespace net {
+
+// Header file contents
+class HttpChannelParent :
+  public PHttpChannelParent
+{
+public:
+  HttpChannelParent();
+  virtual ~HttpChannelParent();
+
+protected:
+  virtual bool RecvasyncOpen(const nsCString& uri);
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/src/Makefile.in
+++ b/netwerk/protocol/http/src/Makefile.in
@@ -41,16 +41,24 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= necko
 LIBRARY_NAME = nkhttp_s
 LIBXUL_LIBRARY  = 1
 
+ifdef MOZ_IPC
+EXPORTS_NAMESPACES = mozilla/net
+
+EXPORTS_mozilla/net = \
+  HttpChannelParent.h \
+  HttpChannelChild.h  \
+  $(NULL)
+endif
 
 CPPSRCS		= \
 		nsHttp.cpp \
 		nsHttpHeaderArray.cpp \
 		nsHttpConnectionInfo.cpp \
 		nsHttpConnection.cpp \
 		nsHttpConnectionMgr.cpp \
 		nsHttpRequestHead.cpp \
@@ -63,17 +71,26 @@ CPPSRCS		= \
 		nsHttpNTLMAuth.cpp \
 		nsHttpTransaction.cpp \
 		nsHttpHandler.cpp \
 		nsHttpChannel.cpp \
 		nsHttpPipeline.cpp \
 		nsHttpActivityDistributor.cpp \
 		$(NULL)
 
+ifdef MOZ_IPC
+CPPSRCS += \
+  HttpChannelParent.cpp \
+  HttpChannelChild.cpp \
+  $(NULL)
+endif
+
 LOCAL_INCLUDES=-I$(srcdir)/../../../base/src -I$(topsrcdir)/xpcom/ds
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/PHttpChannel.ipdl
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jason Duell <jduell.mcbugs@gmail.com>
+ *
+ * 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 protocol "PNecko.ipdl";
+
+namespace mozilla {
+namespace net {
+
+
+//-------------------------------------------------------------------
+protocol PHttpChannel
+{
+  manager PNecko;
+
+parent:
+  __delete__();
+
+  asyncOpen(nsCString uri);
+};
+
+
+} // namespace net
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/src/ipdl.mk
@@ -0,0 +1,40 @@
+# ***** 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 Firefox.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):  Jason Duell
+#
+# 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 *****
+
+IPDLSRCS =          \
+  PHttpChannel.ipdl \
+  $(NULL)
+
--- a/netwerk/protocol/http/src/nsHttp.h
+++ b/netwerk/protocol/http/src/nsHttp.h
@@ -39,16 +39,20 @@
 
 #ifndef nsHttp_h__
 #define nsHttp_h__
 
 #if defined(MOZ_LOGGING)
 #define FORCE_PR_LOG
 #endif
 
+#ifdef MOZ_IPC
+#include "mozilla/net/NeckoChild.h"
+#endif 
+
 #include "plstr.h"
 #include "prlog.h"
 #include "prtime.h"
 #include "nsISupportsUtils.h"
 #include "nsPromiseFlatString.h"
 #include "nsURLHelper.h"
 #include "netCore.h"
 
@@ -62,16 +66,17 @@
 //    set NSPR_LOG_FILE=http.log
 //
 // this enables PR_LOG_ALWAYS level information and places all output in
 // the file http.log
 //
 extern PRLogModuleInfo *gHttpLog;
 #endif
 
+#undef LOG
 // http logging
 #define LOG1(args) PR_LOG(gHttpLog, 1, args)
 #define LOG2(args) PR_LOG(gHttpLog, 2, args)
 #define LOG3(args) PR_LOG(gHttpLog, 3, args)
 #define LOG4(args) PR_LOG(gHttpLog, 4, args)
 #define LOG(args) LOG4(args)
 
 #define LOG1_ENABLED() PR_LOG_TEST(gHttpLog, 1)
--- a/netwerk/protocol/http/src/nsHttpChunkedDecoder.h
+++ b/netwerk/protocol/http/src/nsHttpChunkedDecoder.h
@@ -34,16 +34,17 @@
  * 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 nsHttpChunkedDecoder_h__
 #define nsHttpChunkedDecoder_h__
 
+#include "nsHttp.h"
 #include "nsError.h"
 #include "nsString.h"
 #include "nsHttpHeaderArray.h"
 
 class nsHttpChunkedDecoder
 {
 public:
     nsHttpChunkedDecoder() : mTrailers(nsnull)
--- a/netwerk/protocol/http/src/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/src/nsHttpHandler.cpp
@@ -89,16 +89,21 @@
 #include <Carbon/Carbon.h>
 #endif
 
 #if defined(XP_OS2)
 #define INCL_DOSMISC
 #include <os2.h>
 #endif
 
+//-----------------------------------------------------------------------------
+#ifdef MOZ_IPC
+using namespace mozilla::net;
+#endif 
+
 #ifdef DEBUG
 // defined by the socket transport service while active
 extern PRThread *gSocketThread;
 #endif
 
 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
 static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
 static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID);
@@ -220,16 +225,21 @@ nsHttpHandler::Init()
         return rv;
 
     mIOService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
     if (NS_FAILED(rv)) {
         NS_WARNING("unable to continue without io service");
         return rv;
     }
 
+#ifdef MOZ_IPC
+    if (IsNeckoChild() && !gNeckoChild)
+        NeckoChild::InitNeckoChild();
+#endif // MOZ_IPC
+
     InitUserAgentComponents();
 
     // monitor some preference changes
     nsCOMPtr<nsIPrefBranch2> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefBranch) {
         prefBranch->AddObserver(HTTP_PREF_PREFIX, this, PR_TRUE);
         prefBranch->AddObserver(UA_PREF_PREFIX, this, PR_TRUE);
         prefBranch->AddObserver(INTL_ACCEPT_LANGUAGES, this, PR_TRUE); 
--- a/netwerk/protocol/http/src/nsHttpHeaderArray.h
+++ b/netwerk/protocol/http/src/nsHttpHeaderArray.h
@@ -34,22 +34,22 @@
  * 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 nsHttpHeaderArray_h__
 #define nsHttpHeaderArray_h__
 
+#include "nsHttp.h"
 #include "nsTArray.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
-#include "nsHttp.h"
 
 class nsHttpHeaderArray
 {
 public:
     nsHttpHeaderArray() {}
    ~nsHttpHeaderArray() { Clear(); }
 
     const char *PeekHeader(nsHttpAtom header);
--- a/netwerk/protocol/http/src/nsHttpRequestHead.h
+++ b/netwerk/protocol/http/src/nsHttpRequestHead.h
@@ -34,18 +34,18 @@
  * 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 nsHttpRequestHead_h__
 #define nsHttpRequestHead_h__
 
+#include "nsHttp.h"
 #include "nsHttpHeaderArray.h"
-#include "nsHttp.h"
 #include "nsString.h"
 #include "nsCRT.h"
 
 //-----------------------------------------------------------------------------
 // nsHttpRequestHead represents the request line and headers from an HTTP
 // request.
 //-----------------------------------------------------------------------------
 
--- a/security/manager/ssl/src/nsSmartCardEvent.cpp
+++ b/security/manager/ssl/src/nsSmartCardEvent.cpp
@@ -123,16 +123,30 @@ NS_IMETHODIMP_(nsEvent*) nsSmartCardEven
 }
 
 NS_IMETHODIMP nsSmartCardEvent::SetTrusted(PRBool aResult)
 {
   NS_ASSERTION(mPrivate, "SmartCardEvent called without Init");
   return mPrivate->SetTrusted(aResult);
 }
 
+void
+nsSmartCardEvent::Serialize(IPC::Message* aMsg,
+                            PRBool aSerializeInterfaceType)
+{
+  NS_ASSERTION(mPrivate, "SmartCardEvent called without Init");
+  mPrivate->Serialize(aMsg, aSerializeInterfaceType);
+}
+
+PRBool
+nsSmartCardEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
+{
+  NS_ASSERTION(mPrivate, "SmartCardEvent called without Init");
+  return mPrivate->Deserialize(aMsg, aIter);
+}
 
 // IDOMNSEvent maps
 NS_IMETHODIMP nsSmartCardEvent::GetOriginalTarget(nsIDOMEventTarget * *aOriginalTarget)
 {
   NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init");
   return mNSEvent->GetOriginalTarget(aOriginalTarget);
 }
 
--- a/security/manager/ssl/src/nsSmartCardEvent.h
+++ b/security/manager/ssl/src/nsSmartCardEvent.h
@@ -61,16 +61,19 @@ public:
   NS_DECL_NSIDOMNSEVENT
 
   //NS_DECL_NSIPRIVATEDOMEEVENT
   NS_IMETHOD DuplicatePrivateData();
   NS_IMETHOD SetTarget(nsIDOMEventTarget *aTarget);
   NS_IMETHOD_(nsEvent*) GetInternalNSEvent();
   NS_IMETHOD_(PRBool ) IsDispatchStopped();
   NS_IMETHOD SetTrusted(PRBool aResult);
+  virtual void Serialize(IPC::Message* aMsg,
+                         PRBool aSerializeInterfaceType);
+  virtual PRBool Deserialize(const IPC::Message* aMsg, void** aIter);
 
   NS_DECL_NSIDOMEVENT
 
 protected:
   nsCOMPtr<nsIDOMEvent> mInner;
   nsCOMPtr<nsIPrivateDOMEvent> mPrivate;
   nsCOMPtr<nsIDOMNSEvent> mNSEvent;
   nsString mTokenName;
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/fennec-tile-testapp/application.ini
@@ -0,0 +1,11 @@
+[App]
+Vendor=venderr
+Name=tile
+Version=1.0
+BuildID=20060101
+Copyright=Copyright (c) 2006 Mark Finkle
+ID=xulapp@starkravingfinkle.org
+
+[Gecko]
+MinVersion=1.8
+MaxVersion=2.0
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/fennec-tile-testapp/chrome/chrome.manifest
@@ -0,0 +1,1 @@
+content	tile	file:content/
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js
@@ -0,0 +1,728 @@
+// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
+/*
+ * ***** 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 Mobile Browser.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Roy Frostig <rfrostig@mozilla.com>
+ *
+ * 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 ***** */
+
+let Ci = Components.interfaces;
+
+// --- REMOVE ---
+let noop = function() {};
+let endl = '\n';
+// --------------
+
+function BrowserView(container, visibleRect) {
+  bindAll(this);
+  this.init(container, visibleRect);
+}
+
+/**
+ * A BrowserView maintains state of the viewport (browser, zoom level,
+ * dimensions) and the visible rectangle into the viewport, for every
+ * browser it is given (cf setBrowser()).  In updates to the viewport state,
+ * a BrowserView (using its TileManager) renders parts of the page quasi-
+ * intelligently, with guarantees of having rendered and appended all of the
+ * visible browser content (aka the "critical rectangle").
+ *
+ * State is characterized in large part by two rectangles (and an implicit third):
+ * - Viewport: Always rooted at the origin, ie with (left, top) at (0, 0).  The
+ *     width and height (right and bottom) of this rectangle are that of the
+ *     current viewport, which corresponds more or less to the transformed
+ *     browser content (scaled by zoom level).
+ * - Visible: Corresponds to the client's viewing rectangle in viewport
+ *     coordinates.  Has (top, left) corresponding to position, and width & height
+ *     corresponding to the clients viewing dimensions.  Take note that the top
+ *     and left of the visible rect are per-browser state, but that the width
+ *     and height persist across setBrowser() calls.  This is best explained by
+ *     a simple example: user views browser A, pans to position (x0, y0), switches
+ *     to browser B, where she finds herself at position (x1, y1), tilts her
+ *     device so that visible rectangle's width and height change, and switches
+ *     back to browser A.  She expects to come back to position (x0, y0), but her
+ *     device remains tilted.
+ * - Critical (the implicit one): The critical rectangle is the (possibly null)
+ *     intersection of the visible and viewport rectangles.  That is, it is that
+ *     region of the viewport which is visible to the user.  We care about this
+ *     because it tells us which region must be rendered as soon as it is dirtied.
+ *     The critical rectangle is mostly state that we do not keep in BrowserView
+ *     but that our TileManager maintains.
+ *
+ * Example rectangle state configurations:
+ *
+ *
+ *        +-------------------------------+
+ *        |A                              |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *        |        +----------------+     |
+ *        |        |B,C             |     |
+ *        |        |                |     |
+ *        |        |                |     |
+ *        |        |                |     |
+ *        |        +----------------+     |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *        +-------------------------------+
+ *
+ *
+ * A = viewport ; at (0, 0)
+ * B = visible  ; at (x, y) where x > 0, y > 0
+ * C = critical ; at (x, y)
+ *
+ *
+ *
+ *        +-------------------------------+
+ *        |A                              |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *   +----+-----------+                   |
+ *   |B   .C          |                   |
+ *   |    .           |                   |
+ *   |    .           |                   |
+ *   |    .           |                   |
+ *   +----+-----------+                   |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *        |                               |
+ *        +-------------------------------+
+ *
+ *
+ * A = viewport ; at (0, 0)
+ * B = visible  ; at (x, y) where x < 0, y > 0
+ * C = critical ; at (0, y)
+ *
+ *
+ * Maintaining per-browser state is a little bit of a hack involving attaching
+ * an object as the obfuscated dynamic JS property of the browser object, that
+ * hopefully no one but us will touch.  See getViewportStateFromBrowser() for
+ * the property name.
+ */
+BrowserView.prototype = (
+function() {
+
+  // -----------------------------------------------------------
+  // Privates
+  //
+
+  const kZoomLevelMin = 0.2;
+  const kZoomLevelMax = 4.0;
+  const kZoomLevelPrecision = 10000;
+
+  function visibleRectToCriticalRect(visibleRect, browserViewportState) {
+    return visibleRect.intersect(browserViewportState.viewportRect);
+  }
+
+  function clampZoomLevel(zl) {
+    let bounded = Math.min(Math.max(kZoomLevelMin, zl), kZoomLevelMax);
+    return Math.round(bounded * kZoomLevelPrecision) / kZoomLevelPrecision;
+  }
+
+  function pageZoomLevel(visibleRect, browserW, browserH) {
+    return clampZoomLevel(visibleRect.width / browserW);
+  }
+
+  function seenBrowser(browser) {
+    return !!(browser.__BrowserView__vps);
+  }
+
+  function initBrowserState(browser, visibleRect) {
+    let [browserW, browserH] = getBrowserDimensions(browser);
+
+    let zoomLevel = pageZoomLevel(visibleRect, browserW, browserH);
+    let viewportRect = (new wsRect(0, 0, browserW, browserH)).scale(zoomLevel, zoomLevel);
+
+    dump('--- initing browser to ---' + endl);
+    browser.__BrowserView__vps = new BrowserView.BrowserViewportState(viewportRect,
+                                                                      visibleRect.x,
+                                                                      visibleRect.y,
+                                                                      zoomLevel);
+    dump(browser.__BrowserView__vps.toString() + endl);
+    dump('--------------------------' + endl);
+  }
+
+  function getViewportStateFromBrowser(browser) {
+    return browser.__BrowserView__vps;
+  }
+
+  function getBrowserDimensions(browser) {
+    return [browser.scrollWidth, browser.scrollHeight];
+  }
+
+  function getContentScrollValues(browser) {
+    let cwu = getBrowserDOMWindowUtils(browser);
+    let scrollX = {};
+    let scrollY = {};
+    cwu.getScrollXY(false, scrollX, scrollY);
+
+    return [scrollX.value, scrollY.value];
+  }
+
+  function getBrowserDOMWindowUtils(browser) {
+    return browser.contentWindow
+      .QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDOMWindowUtils);
+  }
+
+  function getNewBatchOperationState() {
+    return {
+      viewportSizeChanged: false,
+      dirtyAll: false
+    };
+  }
+
+  function clampViewportWH(width, height, visibleRect) {
+    let minW = visibleRect.width;
+    let minH = visibleRect.height;
+    return [Math.max(width, minW), Math.max(height, minH)];
+  }
+
+  function initContainer(container, visibleRect) {
+    container.style.width    = visibleRect.width  + 'px';
+    container.style.height   = visibleRect.height + 'px';
+    container.style.overflow = '-moz-hidden-unscrollable';
+  }
+
+  function resizeContainerToViewport(container, viewportRect) {
+    container.style.width  = viewportRect.width  + 'px';
+    container.style.height = viewportRect.height + 'px';
+  }
+
+  // !!! --- RESIZE HACK BEGIN -----
+  function simulateMozAfterSizeChange(browser, width, height) {
+    let ev = document.createElement("MouseEvents");
+    ev.initEvent("FakeMozAfterSizeChange", false, false, window, 0, width, height);
+    browser.dispatchEvent(ev);
+  }
+  // !!! --- RESIZE HACK END -------
+
+  // --- Change of coordinates functions --- //
+
+
+  // The following returned object becomes BrowserView.prototype
+  return {
+
+    // -----------------------------------------------------------
+    // Public instance methods
+    //
+
+    init: function init(container, visibleRect) {
+      this._batchOps = [];
+      this._container = container;
+      this._browserViewportState = null;
+      this._renderMode = 0;
+      this._tileManager = new TileManager(this._appendTile, this._removeTile, this);
+      this.setVisibleRect(visibleRect);
+
+      // !!! --- RESIZE HACK BEGIN -----
+      // remove this eventually
+      this._resizeHack = {
+        maxSeenW: 0,
+        maxSeenH: 0
+      };
+      // !!! --- RESIZE HACK END -------
+    },
+
+    setVisibleRect: function setVisibleRect(r) {
+      let bvs = this._browserViewportState;
+      let vr  = this._visibleRect;
+
+      if (!vr)
+        this._visibleRect = vr = r.clone();
+      else
+        vr.copyFrom(r);
+
+      if (bvs) {
+        bvs.visibleX = vr.left;
+        bvs.visibleY = vr.top;
+
+        // reclamp minimally to the new visible rect
+        //this.setViewportDimensions(bvs.viewportRect.right, bvs.viewportRect.bottom);
+      } else
+        this._viewportChanged(false, false);
+    },
+
+    getVisibleRect: function getVisibleRect() {
+      return this._visibleRect.clone();
+    },
+
+    getVisibleRectX: function getVisibleRectX() { return this._visibleRect.x; },
+    getVisibleRectY: function getVisibleRectY() { return this._visibleRect.y; },
+    getVisibleRectWidth: function getVisibleRectWidth() { return this._visibleRect.width; },
+    getVisibleRectHeight: function getVisibleRectHeight() { return this._visibleRect.height; },
+
+    setViewportDimensions: function setViewportDimensions(width, height, causedByZoom) {
+      let bvs = this._browserViewportState;
+      let vis = this._visibleRect;
+
+      if (!bvs)
+        return;
+
+      //[width, height] = clampViewportWH(width, height, vis);
+      bvs.viewportRect.right  = width;
+      bvs.viewportRect.bottom = height;
+
+      // XXX we might not want the user's page to disappear from under them
+      // at this point, which could happen if the container gets resized such
+      // that visible rect becomes entirely outside of viewport rect.  might
+      // be wise to define what UX should be in this case, like a move occurs.
+      // then again, we could also argue this is the responsibility of the
+      // caller who would do such a thing...
+
+      this._viewportChanged(true, !!causedByZoom);
+    },
+
+    setZoomLevel: function setZoomLevel(zl) {
+      let bvs = this._browserViewportState;
+
+      if (!bvs)
+        return;
+
+      let newZL = clampZoomLevel(zl);
+
+      if (newZL != bvs.zoomLevel) {
+        let browserW = this.viewportToBrowser(bvs.viewportRect.right);
+        let browserH = this.viewportToBrowser(bvs.viewportRect.bottom);
+        bvs.zoomLevel = newZL; // side-effect: now scale factor in transformations is newZL
+        this.setViewportDimensions(this.browserToViewport(browserW),
+                                   this.browserToViewport(browserH));
+      }
+    },
+
+    getZoomLevel: function getZoomLevel() {
+      let bvs = this._browserViewportState;
+      if (!bvs)
+        return undefined;
+
+      return bvs.zoomLevel;
+    },
+
+    beginBatchOperation: function beginBatchOperation() {
+      this._batchOps.push(getNewBatchOperationState());
+      this.pauseRendering();
+    },
+
+    commitBatchOperation: function commitBatchOperation() {
+      let bops = this._batchOps;
+
+      if (bops.length == 0)
+        return;
+
+      let opState = bops.pop();
+      this._viewportChanged(opState.viewportSizeChanged, opState.dirtyAll);
+      this.resumeRendering();
+    },
+
+    discardBatchOperation: function discardBatchOperation() {
+      let bops = this._batchOps;
+      bops.pop();
+      this.resumeRendering();
+    },
+
+    discardAllBatchOperations: function discardAllBatchOperations() {
+      let bops = this._batchOps;
+      while (bops.length > 0)
+        this.discardBatchOperation();
+    },
+
+    moveVisibleBy: function moveVisibleBy(dx, dy) {
+      let vr = this._visibleRect;
+      let vs = this._browserViewportState;
+
+      this.onBeforeVisibleMove(dx, dy);
+      this.onAfterVisibleMove(dx, dy);
+    },
+
+    moveVisibleTo: function moveVisibleTo(x, y) {
+      let visibleRect = this._visibleRect;
+      let dx = x - visibleRect.x;
+      let dy = y - visibleRect.y;
+      this.moveBy(dx, dy);
+    },
+
+    /**
+     * Calls to this function need to be one-to-one with calls to
+     * resumeRendering()
+     */
+    pauseRendering: function pauseRendering() {
+      this._renderMode++;
+    },
+
+    /**
+     * Calls to this function need to be one-to-one with calls to
+     * pauseRendering()
+     */
+    resumeRendering: function resumeRendering(renderNow) {
+      if (this._renderMode > 0)
+        this._renderMode--;
+
+      if (renderNow || this._renderMode == 0)
+        this._tileManager.criticalRectPaint();
+    },
+
+    isRendering: function isRendering() {
+      return (this._renderMode == 0);
+    },
+
+    /**
+     * @param dx Guess delta to destination x coordinate
+     * @param dy Guess delta to destination y coordinate
+     */
+    onBeforeVisibleMove: function onBeforeVisibleMove(dx, dy) {
+      let vs = this._browserViewportState;
+      let vr = this._visibleRect;
+
+      let destCR = visibleRectToCriticalRect(vr.clone().translate(dx, dy), vs);
+
+      this._tileManager.beginCriticalMove(destCR);
+    },
+
+    /**
+     * @param dx Actual delta to destination x coordinate
+     * @param dy Actual delta to destination y coordinate
+     */
+    onAfterVisibleMove: function onAfterVisibleMove(dx, dy) {
+      let vs = this._browserViewportState;
+      let vr = this._visibleRect;
+
+      vr.translate(dx, dy);
+      vs.visibleX = vr.left;
+      vs.visibleY = vr.top;
+
+      let cr = visibleRectToCriticalRect(vr, vs);
+
+      this._tileManager.endCriticalMove(cr, this.isRendering());
+    },
+
+    setBrowser: function setBrowser(browser, skipZoom) {
+      let currentBrowser = this._browser;
+
+      let browserChanged = (currentBrowser !== browser);
+
+      if (currentBrowser) {
+        currentBrowser.removeEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
+
+        // !!! --- RESIZE HACK BEGIN -----
+        // change to the real event type and perhaps refactor the handler function name
+        currentBrowser.removeEventListener("FakeMozAfterSizeChange", this.handleMozAfterSizeChange, false);
+        // !!! --- RESIZE HACK END -------
+
+        this.discardAllBatchOperations();
+
+        currentBrowser.setAttribute("type", "content");
+        currentBrowser.docShell.isOffScreenBrowser = false;
+      }
+
+      this._restoreBrowser(browser);
+
+      browser.setAttribute("type", "content-primary");
+
+      this.beginBatchOperation();
+
+      browser.addEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
+
+      // !!! --- RESIZE HACK BEGIN -----
+      // change to the real event type and perhaps refactor the handler function name
+      browser.addEventListener("FakeMozAfterSizeChange", this.handleMozAfterSizeChange, false);
+      // !!! --- RESIZE HACK END -------
+
+      if (!skipZoom) {
+        browser.docShell.isOffScreenBrowser = true;
+        this.zoomToPage();
+      }
+
+      this._viewportChanged(browserChanged, browserChanged);
+
+      this.commitBatchOperation();
+    },
+
+    handleMozAfterPaint: function handleMozAfterPaint(ev) {
+      let browser = this._browser;
+      let tm = this._tileManager;
+      let vs = this._browserViewportState;
+
+      let [scrollX, scrollY] = getContentScrollValues(browser);
+      let clientRects = ev.clientRects;
+
+      // !!! --- RESIZE HACK BEGIN -----
+      // remove this, cf explanation in loop below
+      let hack = this._resizeHack;
+      let hackSizeChanged = false;
+      // !!! --- RESIZE HACK END -------
+
+      let rects = [];
+      // loop backwards to avoid xpconnect penalty for .length
+      for (let i = clientRects.length - 1; i >= 0; --i) {
+        let e = clientRects.item(i);
+        let r = new wsRect(e.left + scrollX,
+                           e.top + scrollY,
+                           e.width, e.height);
+
+        this.browserToViewportRect(r);
+        r.round();
+
+        if (r.right < 0 || r.bottom < 0)
+          continue;
+
+        // !!! --- RESIZE HACK BEGIN -----
+        // remove this.  this is where we make 'lazy' calculations
+        // that hint at a browser size change and fake the size change
+        // event dispach
+        if (r.right > hack.maxW) {
+          hack.maxW = rect.right;
+          hackSizeChanged = true;
+        }
+        if (r.bottom > hack.maxH) {
+          hack.maxH = rect.bottom;
+          hackSizeChanged = true;
+        }
+        // !!! --- RESIZE HACK END -------
+
+        r.restrictTo(vs.viewportRect);
+        rects.push(r);
+      }
+
+      // !!! --- RESIZE HACK BEGIN -----
+      // remove this, cf explanation in loop above
+      if (hackSizeChanged)
+        simulateMozAfterSizeChange(browser, hack.maxW, hack.maxH);
+      // !!! --- RESIZE HACK END -------
+
+      tm.dirtyRects(rects, this.isRendering());
+    },
+
+    handleMozAfterSizeChange: function handleMozAfterPaint(ev) {
+      // !!! --- RESIZE HACK BEGIN -----
+      // get the correct properties off of the event, these are wrong because
+      // we're using a MouseEvent since it has an X and Y prop of some sort and
+      // we piggyback on that.
+      let w = ev.screenX;
+      let h = ev.screenY;
+      // !!! --- RESIZE HACK END -------
+
+      this.setViewportDimensions(w, h);
+    },
+
+    zoomToPage: function zoomToPage() {
+      let browser = this._browser;
+
+      if (!browser)
+        return;
+
+      let [w, h] = getBrowserDimensions(browser);
+      this.setZoomLevel(pageZoomLevel(this._visibleRect, w, h));
+    },
+
+    zoom: function zoom(aDirection) {
+      if (aDirection == 0)
+        return;
+
+      var zoomDelta = 0.05; // 1/20
+      if (aDirection >= 0)
+        zoomDelta *= -1;
+
+      this.zoomLevel = this._zoomLevel + zoomDelta;
+    },
+
+    viewportToBrowser: function viewportToBrowser(x) {
+      let bvs = this._browserViewportState;
+
+      if (!bvs)
+        throw "No browser is set";
+
+      return x / bvs.zoomLevel;
+    },
+
+    browserToViewport: function browserToViewport(x) {
+      let bvs = this._browserViewportState;
+
+      if (!bvs)
+        throw "No browser is set";
+
+      return x * bvs.zoomLevel;
+    },
+
+    viewportToBrowserRect: function viewportToBrowserRect(rect) {
+      let f = this.viewportToBrowser(1.0);
+      return rect.scale(f, f);
+    },
+
+    browserToViewportRect: function browserToViewportRect(rect) {
+      let f = this.browserToViewport(1.0);
+      return rect.scale(f, f);
+    },
+
+    browserToViewportCanvasContext: function browserToViewportCanvasContext(ctx) {
+      let f = this.browserToViewport(1.0);
+      ctx.scale(f, f);
+    },
+
+
+    // -----------------------------------------------------------
+    // Private instance methods
+    //
+
+    _restoreBrowser: function _restoreBrowser(browser) {
+      let vr = this._visibleRect;
+
+      if (!seenBrowser(browser))
+        initBrowserState(browser, vr);
+
+      let bvs = getViewportStateFromBrowser(browser);
+
+      this._contentWindow = browser.contentWindow;
+      this._browser = browser;
+      this._browserViewportState = bvs;
+      vr.left = bvs.visibleX;
+      vr.top  = bvs.visibleY;
+      this._tileManager.setBrowser(browser);
+    },
+
+    _viewportChanged: function _viewportChanged(viewportSizeChanged, dirtyAll) {
+      let bops = this._batchOps;
+
+      if (bops.length > 0) {
+        let opState = bops[bops.length - 1];
+
+        if (viewportSizeChanged)
+          opState.viewportSizeChanged = viewportSizeChanged;
+
+        if (dirtyAll)
+          opState.dirtyAll = dirtyAll;
+
+        return;
+      }
+
+      let bvs = this._browserViewportState;
+      let vis = this._visibleRect;
+
+      // !!! --- RESIZE HACK BEGIN -----
+      // We want to uncomment this for perf, but we can't with the hack in place
+      // because the mozAfterPaint gives us rects that we use to create the
+      // fake mozAfterResize event, so we can't just clear things.
+      /*
+      if (dirtyAll) {
+        // We're about to mark the entire viewport dirty, so we can clear any
+        // queued afterPaint events that will cause redundant draws
+        getBrowserDOMWindowUtils(this._browser).clearMozAfterPaintEvents();
+      }
+      */
+      // !!! --- RESIZE HACK END -------
+
+      if (bvs) {
+        resizeContainerToViewport(this._container, bvs.viewportRect);
+
+        this._tileManager.viewportChangeHandler(bvs.viewportRect,
+                                                visibleRectToCriticalRect(vis, bvs),
+                                                viewportSizeChanged,
+                                                dirtyAll);
+      }
+    },
+
+    _appendTile: function _appendTile(tile) {
+      let canvas = tile.getContentImage();
+
+      /*
+      canvas.style.position = "absolute";
+      canvas.style.left = tile.x + "px";
+      canvas.style.top  = tile.y + "px";
+      */
+
+      canvas.setAttribute("style", "position: absolute; left: " + tile.boundRect.left + "px; " + "top: " + tile.boundRect.top + "px;");
+
+      this._container.appendChild(canvas);
+
+      //dump('++ ' + tile.toString(true) + endl);
+    },
+
+    _removeTile: function _removeTile(tile) {
+      let canvas = tile.getContentImage();
+
+      this._container.removeChild(canvas);
+
+      //dump('-- ' + tile.toString(true) + endl);
+    }
+
+  };
+
+}
+)();
+
+
+// -----------------------------------------------------------
+// Helper structures
+//
+
+BrowserView.BrowserViewportState = function(viewportRect,
+                                            visibleX,
+                                            visibleY,
+                                            zoomLevel) {
+
+  this.init(viewportRect, visibleX, visibleY, zoomLevel);
+};
+
+BrowserView.BrowserViewportState.prototype = {
+
+  init: function init(viewportRect, visibleX, visibleY, zoomLevel) {
+    this.viewportRect = viewportRect;
+    this.visibleX     = visibleX;
+    this.visibleY     = visibleY;
+    this.zoomLevel    = zoomLevel;
+  },
+
+  clone: function clone() {
+    return new BrowserView.BrowserViewportState(this.viewportRect,
+                                                this.visibleX,
+                                                this.visibleY,
+						                                    this.zoomLevel);
+  },
+
+  toString: function toString() {
+    let props = ['\tviewportRect=' + this.viewportRect.toString(),
+                 '\tvisibleX='     + this.visibleX,
+                 '\tvisibleY='     + this.visibleY,
+                 '\tzoomLevel='    + this.zoomLevel];
+
+    return '[BrowserViewportState] {\n' + props.join(',\n') + '\n}';
+  }
+
+};
+
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js
@@ -0,0 +1,359 @@
+let noop = function() {};
+Browser = {
+  updateViewportSize: noop
+    /*************************************************************
+  function
+    let browser = document.getElementById("googlenews");
+    let cdoc = browser.contentDocument;
+
+    // These might not exist yet depending on page load state
+    var body = cdoc.body || {};
+    var html = cdoc.documentElement || {};
+
+    var w = Math.max(body.scrollWidth || 0, html.scrollWidth);
+    var h = Math.max(body.scrollHeight || 0, html.scrollHeight);
+
+    window.tileManager.viewportHandler(new wsRect(0, 0, w, h),
+                                       window.innerWidth,
+                                       new wsRect(0, 0, window.innerWidth, window.innerHeight),
+                                       false);
+  *************************************************************/
+};
+let ws = {
+  beginUpdateBatch: noop,
+  panTo: noop,
+  endUpdateBatch: noop
+};
+let Ci = Components.interfaces;
+let bv = null;
+let endl = "\n";
+
+
+function BrowserView() {
+  this.init();
+  bindAll(this);
+}
+
+BrowserView.prototype = {
+
+  // --- PROPERTIES ---
+  // public:
+  //   init()
+  //   getViewportInnerBoundsRect(dx, dy)
+  //   tileManager
+  //   scrollbox
+  //
+  // private:
+  //   _scrollbox
+  //   _leftbar
+  //   _rightbar
+  //   _topbar
+  //   _browser
+  //   _tileManager
+  //   _viewportRect
+  //   _viewportInnerBoundsRect
+  //
+
+  get tileManager() { return this._tileManager; },
+  get scrollbox() { return this._scrollbox; },
+
+  init: function init() {
+    let scrollbox = document.getElementById("scrollbox")
+			.boxObject
+			.QueryInterface(Components.interfaces.nsIScrollBoxObject);
+    this._scrollbox = scrollbox;
+
+    let leftbar  = document.getElementById("left_sidebar");
+    let rightbar = document.getElementById("right_sidebar");
+    let topbar   = document.getElementById("top_urlbar");
+    this._leftbar = leftbar;
+    this._rightbar = rightbar;
+    this._topbar = topbar;
+
+    scrollbox.scrollTo(Math.round(leftbar.getBoundingClientRect().right), 0);
+
+    let tileContainer = document.getElementById("tile_container");
+    tileContainer.addEventListener("mousedown", onMouseDown, true);
+    tileContainer.addEventListener("mouseup",   onMouseUp,   true);
+    tileContainer.addEventListener("mousemove", onMouseMove, true);
+    this._tileContainer = tileContainer;
+
+    let tileManager = new TileManager(this.appendTile, this.removeTile, window.innerWidth);
+    this._tileManager = tileManager;
+
+    let browser = document.getElementById("googlenews");
+    this.setCurrentBrowser(browser, false);    // sets this._browser
+
+    let cdoc = browser.contentDocument;
+
+    // These might not exist yet depending on page load state
+    let body = cdoc.body || {};
+    let html = cdoc.documentElement || {};
+
+    let w = Math.max(body.scrollWidth || 0, html.scrollWidth);
+    let h = Math.max(body.scrollHeight || 0, html.scrollHeight);
+
+    let viewportRect = new wsRect(0, 0, w, h);
+    this._viewportRect = viewportRect;
+
+    let viewportInnerBoundsRect = this.getViewportInnerBoundsRect();
+    this._viewportInnerBoundsRect = viewportInnerBoundsRect;
+
+    tileManager.viewportHandler(viewportRect,
+				window.innerWidth,
+				viewportInnerBoundsRect,
+				true);
+  },
+
+  resizeTileContainer: function resizeTileContainer() {
+
+  },
+
+  scrollboxToViewportRect: function scrollboxToViewportRect(rect, clip) {
+    let leftbar  = this._leftbar.getBoundingClientRect();
+    let rightbar = this._rightbar.getBoundingClientRect();
+    let topbar   = this._topbar.getBoundingClientRect();
+
+    let xtrans = -leftbar.width;
+    let ytrans = -topbar.height;
+    let x = rect.x + xtrans;
+    let y = rect.y + ytrans;
+
+    // XXX we're cheating --- this is not really a clip, but its the only
+    // way this function is used
+    rect.x = (clip) ? Math.max(x, 0) : x;
+    rect.y = (clip) ? Math.max(y, 0) : y;
+
+    return rect;
+  },
+
+  getScrollboxPosition: function getScrollboxPosition() {
+    let x = {};
+    let y = {};
+    this._scrollbox.getPosition(x, y);
+    return [x.value, y.value];
+  },
+
+  getViewportInnerBoundsRect: function getViewportInnerBoundsRect(dx, dy) {
+    if (!dx) dx = 0;
+    if (!dy) dy = 0;
+
+    let w = window.innerWidth;
+    let h = window.innerHeight;
+
+    let leftbar  = this._leftbar.getBoundingClientRect();
+    let rightbar = this._rightbar.getBoundingClientRect();
+    let topbar   = this._topbar.getBoundingClientRect();
+
+    let leftinner  = Math.max(leftbar.right - dx, 0);
+    let rightinner = Math.min(rightbar.left - dx, w);
+    let topinner   = Math.max(topbar.bottom - dy, 0);
+
+    let [x, y] = this.getScrollboxPosition();
+
+    return this.scrollboxToViewportRect(new wsRect(x + dx, y + dy, rightinner - leftinner, h - topinner),
+				        true);
+  },
+
+  appendTile: function appendTile(tile) {
+    let canvas = tile.contentImage;
+
+    canvas.style.position = "absolute";
+    canvas.style.left = tile.x + "px";
+    canvas.style.top  = tile.y + "px";
+
+    let tileContainer = document.getElementById("tile_container");
+    tileContainer.appendChild(canvas);
+
+    dump('++ ' + tile.toString() + endl);
+  },
+
+  removeTile: function removeTile(tile) {
+    let canvas = tile.contentImage;
+
+    let tileContainer = document.getElementById("tile_container");
+    tileContainer.removeChild(canvas);
+
+    dump('-- ' + tile.toString() + endl);
+  },
+
+  scrollBy: function scrollBy(dx, dy) {
+    // TODO
+    this.onBeforeScroll();
+    this.onAfterScroll();
+  },
+
+  // x: current x
+  // y: current y
+  // dx: delta to get to x from current x
+  // dy: delta to get to y from current y
+  onBeforeScroll: function onBeforeScroll(x, y, dx, dy) {
+    this.tileManager.onBeforeScroll(this.getViewportInnerBoundsRect(dx, dy));
+
+    // shouldn't update margin if it doesn't need to be changed
+    let sidebars = document.getElementsByClassName("sidebar");
+    for (let i = 0; i < sidebars.length; i++) {
+      let sidebar = sidebars[i];
+      sidebar.style.margin = (y + dy) + "px 0px 0px 0px";
+    }
+
+    let urlbar = document.getElementById("top_urlbar");
+    urlbar.style.margin = "0px 0px 0px " + (x + dx) + "px";
+  },
+
+  onAfterScroll: function onAfterScroll(x, y, dx, dy) {
+    this.tileManager.onAfterScroll(this.getViewportInnerBoundsRect());
+  },
+
+  setCurrentBrowser: function setCurrentBrowser(browser, skipZoom) {
+    let currentBrowser = this._browser;
+    if (currentBrowser) {
+      // backup state
+      currentBrowser.mZoomLevel = this.zoomLevel;
+      currentBrowser.mPanX = ws._viewingRect.x;
+      currentBrowser.mPanY = ws._viewingRect.y;
+
+      // stop monitor paint events for this browser
+      currentBrowser.removeEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
+      currentBrowser.setAttribute("type", "content");
+      currentBrowser.docShell.isOffScreenBrowser = false;
+    }
+
+    browser.setAttribute("type", "content-primary");
+    if (!skipZoom)
+      browser.docShell.isOffScreenBrowser = true;
+
+    // start monitoring paint events for this browser
+    browser.addEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
+
+    this._browser = browser;
+
+    // endLoading(and startLoading in most cases) calls zoom anyway
+    if (!skipZoom) {
+      this.zoomToPage();
+    }
+
+    if ("mZoomLevel" in browser) {
+      // restore last state
+      ws.beginUpdateBatch();
+      ws.panTo(browser.mPanX, browser.mPanY);
+      this.zoomLevel = browser.mZoomLevel;
+      ws.endUpdateBatch(true);
+
+      // drop the cache
+      delete browser.mZoomLevel;
+      delete browser.mPanX;
+      delete browser.mPanY;
+    }
+
+    this.tileManager.browser = browser;
+  },
+
+  handleMozAfterPaint: function handleMozAfterPaint(ev) {
+    this.tileManager.handleMozAfterPaint(ev);
+  },
+
+  zoomToPage: function zoomToPage() {
+    /********************************************************
+    let needToPanToTop = this._needToPanToTop;
+    // Ensure pages are panned at the top before zooming/painting
+    // combine the initial pan + zoom into a transaction
+    if (needToPanToTop) {
+      ws.beginUpdateBatch();
+      this._needToPanToTop = false;
+      ws.panTo(0, -BrowserUI.toolbarH);
+    }
+    // Adjust the zoomLevel to fit the page contents in our window width
+    let [contentW, ] = this._contentAreaDimensions;
+    let fakeW = this._fakeWidth;
+
+    if (contentW > fakeW)
+      this.zoomLevel = fakeW / contentW;
+
+    if (needToPanToTop)
+      ws.endUpdateBatch();
+    ********************************************************/
+  }
+
+};
+
+
+function onResize(e) {
+  let browser = document.getElementById("googlenews");
+  let cdoc = browser.contentDocument;
+
+  // These might not exist yet depending on page load state
+  var body = cdoc.body || {};
+  var html = cdoc.documentElement || {};
+
+  var w = Math.max(body.scrollWidth || 0, html.scrollWidth);
+  var h = Math.max(body.scrollHeight || 0, html.scrollHeight);
+
+  if (bv)
+    bv.tileManager.viewportHandler(new wsRect(0, 0, w, h),
+				   window.innerWidth,
+				   bv.getViewportInnerBoundsRect(),
+				   true);
+}
+
+function onMouseDown(e) {
+  window._isDragging = true;
+  window._dragStart = {x: e.clientX, y: e.clientY};
+
+  bv.tileManager.startPanning();
+}
+
+function onMouseUp() {
+  window._isDragging = false;
+
+  bv.tileManager.endPanning();
+}
+
+function onMouseMove(e) {
+  if (window._isDragging) {
+    let scrollbox = bv.scrollbox;
+
+    let x = {};
+    let y = {};
+    let w = {};
+    let h = {};
+    scrollbox.getPosition(x, y);
+    scrollbox.getScrolledSize(w, h);
+
+    let dx = window._dragStart.x - e.clientX;
+    let dy = window._dragStart.y - e.clientY;
+
+    // XXX if max(x, 0) > scrollwidth we shouldn't do anything (same for y/height)
+    let newX = Math.max(x.value + dx, 0);
+    let newY = Math.max(y.value + dy, 0);
+
+    if (newX < w.value || newY < h.value) {
+      // clip dx and dy to prevent us from going below 0
+      dx = Math.max(dx, -x.value);
+      dy = Math.max(dy, -y.value);
+
+      bv.onBeforeScroll(x.value, y.value, dx, dy);
+
+      /*dump("==========scroll==========" + endl);
+      dump("delta: " + dx + "," + dy + endl);
+      let xx = {};
+      let yy = {};
+      scrollbox.getPosition(xx, yy);
+      dump(xx.value + "," + yy.value + endl);*/
+
+      scrollbox.scrollBy(dx, dy);
+
+      /*scrollbox.getPosition(xx, yy);
+      dump(xx.value + "," + yy.value + endl);
+      dump("==========================" + endl);*/
+
+      bv.onAfterScroll();
+    }
+  }
+
+  window._dragStart = {x: e.clientX, y: e.clientY};
+}
+
+function onLoad() {
+  bv = new BrowserView();
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/fennec-tile-testapp/chrome/content/TileManager.js
@@ -0,0 +1,1055 @@
+// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
+/*
+ * ***** 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 Mobile Browser.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Roy Frostig <rfrostig@mozilla.com>
+ *
+ * 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 ***** */
+
+const kXHTMLNamespaceURI  = "http://www.w3.org/1999/xhtml";
+
+// base-2 exponent for width, height of a single tile.
+const kTileExponentWidth  = 7;
+const kTileExponentHeight = 7;
+const kTileWidth  = Math.pow(2, kTileExponentWidth);   // 2^7 = 128
+const kTileHeight = Math.pow(2, kTileExponentHeight);  // 2^7 = 128
+const kLazyRoundTimeCap = 500;    // millis
+
+
+function bind(f, thisObj) {
+  return function() {
+    return f.apply(thisObj, arguments);
+  };
+}
+
+function bindSome(instance, methodNames) {
+  for each (let methodName in methodNames)
+    if (methodName in instance)
+      instance[methodName] = bind(instance[methodName], instance);
+}
+
+function bindAll(instance) {
+  for (let key in instance)
+    if (instance[key] instanceof Function)
+      instance[key] = bind(instance[key], instance);
+}
+
+
+/**
+ * The Tile Manager!
+ *
+ * @param appendTile The function the tile manager should call in order to
+ * "display" a tile (e.g. append it to the DOM).  The argument to this
+ * function is a TileManager.Tile object.
+ * @param removeTile The function the tile manager should call in order to
+ * "undisplay" a tile (e.g. remove it from the DOM).  The argument to this
+ * function is a TileManager.Tile object.
+ * @param fakeWidth The width of the widest possible visible rectangle, e.g.
+ * the width of the screen.  This is used in setting the zoomLevel.
+ */
+function TileManager(appendTile, removeTile, browserView) {
+  // backref to the BrowserView object that owns us
+  this._browserView = browserView;
+
+  // callbacks to append / remove a tile to / from the parent
+  this._appendTile = appendTile;
+  this._removeTile = removeTile;
+
+  // tile cache holds tile objects and pools them under a given capacity
+  let self = this;
+  this._tileCache = new TileManager.TileCache(function(tile) { self._removeTileSafe(tile); },
+                                              -1, -1, 110);
+
+  // Rectangle within the viewport that is visible to the user.  It is "critical"
+  // in the sense that it must be rendered as soon as it becomes dirty
+  this._criticalRect = null;
+
+  // Current <browser> DOM element, holding the content we wish to render.
+  // This is null when no browser is attached
+  this._browser = null;
+
+  // if we have an outstanding paint timeout, its value is stored here
+  // for cancelling when we end page loads
+  //this._drawTimeout = 0;
+  this._pageLoadResizerTimeout = 0;
+
+  // timeout of the non-visible-tiles-crawler to cache renders from the browser
+  this._idleTileCrawlerTimeout = 0;
+
+  // object that keeps state on our current lazyload crawl
+  this._crawler = null;
+
+  // the max right coordinate we've seen from paint events
+  // while we were loading a page.  If we see something that's bigger than
+  // our width, we'll trigger a page zoom.
+  this._pageLoadMaxRight = 0;
+  this._pageLoadMaxBottom = 0;
+
+  // Tells us to pan to top before first draw
+  this._needToPanToTop = false;
+}
+
+TileManager.prototype = {
+
+  setBrowser: function setBrowser(b) { this._browser = b; },
+
+  // This is the callback fired by our client whenever the viewport
+  // changed somehow (or didn't change but someone asked it to update).
+  viewportChangeHandler: function viewportChangeHandler(viewportRect,
+                                                        criticalRect,
+                                                        boundsSizeChanged,
+                                                        dirtyAll) {
+    // !!! --- DEBUG BEGIN -----
+    dump("***vphandler***\n");
+    dump(viewportRect.toString() + "\n");
+    dump(criticalRect.toString() + "\n");
+    dump(boundsSizeChanged + "\n");
+    dump(dirtyAll + "\n***************\n");
+    // !!! --- DEBUG END -------
+
+    let tc = this._tileCache;
+
+    tc.iBound = Math.ceil(viewportRect.right / kTileWidth);
+    tc.jBound = Math.ceil(viewportRect.bottom / kTileHeight);
+
+    if (!criticalRect || !criticalRect.equals(this._criticalRect)) {
+      this.beginCriticalMove(criticalRect);
+      this.endCriticalMove(criticalRect, !boundsSizeChanged);
+    }
+
+    if (boundsSizeChanged) {
+      // TODO fastpath if !dirtyAll
+      this.dirtyRects([viewportRect.clone()], true);
+    }
+  },
+
+  dirtyRects: function dirtyRects(rects, doCriticalRender) {
+    let criticalIsDirty = false;
+    let criticalRect = this._criticalRect;
+
+    for each (let rect in rects) {
+      this._tileCache.forEachIntersectingRect(rect, false, this._dirtyTile, this);
+
+      if (criticalRect && rect.intersects(criticalRect))
+        criticalIsDirty = true;
+    }
+
+    if (criticalIsDirty && doCriticalRender)
+      this.criticalRectPaint();
+  },
+
+  criticalRectPaint: function criticalRectPaint() {
+    let cr = this._criticalRect;
+
+    if (cr) {
+      let [ctrx, ctry] = cr.centerRounded();
+      this.recenterEvictionQueue(ctrx, ctry);
+      this._renderAppendHoldRect(cr);
+    }
+  },
+
+  beginCriticalMove2: function beginCriticalMove(destCriticalRect) {
+    let start = Date.now();
+    function appendNonDirtyTile(tile) {
+      if (!tile.isDirty())
+        this._appendTileSafe(tile);
+    }
+
+    if (destCriticalRect)
+      this._tileCache.forEachIntersectingRect(destCriticalRect, false, appendNonDirtyTile, this);
+    let end = Date.now();
+    dump("start: " + (end-start) + "\n")
+  },
+
+  beginCriticalMove: function beginCriticalMove(destCriticalRect) {
+  /*
+  function appendNonDirtyTile(tile) {
+    if (!tile.isDirty())
+      this._appendTileSafe(tile);
+  }
+  */
+
+    let start = Date.now();
+
+    if (destCriticalRect) {
+
+      let rect = destCriticalRect;
+
+      let create = false;
+
+      // this._tileCache.forEachIntersectingRect(destCriticalRect, false, appendNonDirtyTile, this);
+      let visited = {};
+      let evictGuard = null;
+      if (create) {
+	evictGuard = function evictGuard(tile) {
+	  return !visited[tile.toString()];
+	};
+      }
+
+      let starti = rect.left  >> kTileExponentWidth;
+      let endi   = rect.right >> kTileExponentWidth;
+
+      let startj = rect.top    >> kTileExponentHeight;
+      let endj   = rect.bottom >> kTileExponentHeight;
+
+      let tile = null;
+      let tc = this._tileCache;
+
+      for (var j = startj; j <= endj; ++j) {
+	for (var i = starti; i <= endi; ++i) {
+
+	  // 'this' for getTile needs to be tc
+
+	  //tile = this.getTile(i, j, create, evictGuard);
+	  //if (!tc.inBounds(i, j)) {
+	  if (0 <= i && 0 <= j && i <= tc.iBound && j <= tc.jBound) {
+	    //return null;
+	    break;
+	  }
+
+	  tile = null;
+
+	  //if (tc._isOccupied(i, j)) {
+	  if (!!(tc._tiles[i] && tc._tiles[i][j])) {
+	    tile = tc._tiles[i][j];
+	  } else if (create) {
+	    // NOTE: create is false here
+	    tile = tc._createTile(i, j, evictionGuard);
+	    if (tile) tile.markDirty();
+	  }
+
+	  if (tile) {
+	    visited[tile.toString()] = true;
+	    //fn.call(thisObj, tile);
+	    //function appendNonDirtyTile(tile) {
+	    //if (!tile.isDirty())
+	    if (!tile._dirtyTileCanvas) {
+	      //this._appendTileSafe(tile);
+	      if (!tile._appended) {
+		let astart = Date.now();
+		this._appendTile(tile);
+		tile._appended = true;
+		let aend = Date.now();
+		dump("append: " + (aend - astart) + "\n");
+	      }
+	    }
+	    //}
+	  }
+	}
+      }
+    }
+
+    let end = Date.now();
+    dump("start: " + (end-start) + "\n")
+  },
+
+  endCriticalMove: function endCriticalMove(destCriticalRect, doCriticalPaint) {
+    let start = Date.now();
+
+    let tc = this._tileCache;
+    let cr = this._criticalRect;
+
+    let dcr = destCriticalRect.clone();
+
+    let f = function releaseOldTile(tile) {
+      // release old tile
+      if (!tile.boundRect.intersects(dcr))
+        tc.releaseTile(tile);
+    }
+
+    if (cr)
+      tc.forEachIntersectingRect(cr, false, f, this);
+
+    this._holdRect(destCriticalRect);
+
+    if (cr)
+      cr.copyFrom(destCriticalRect);
+    else
+      this._criticalRect = cr = destCriticalRect;
+
+    let crpstart = Date.now();
+    if (doCriticalPaint)
+      this.criticalRectPaint();
+    dump(" crp: " + (Date.now() - crpstart) + "\n");
+
+    let end = Date.now();
+    dump("end: " + (end - start) + "\n");
+  },
+
+  restartLazyCrawl: function restartLazyCrawl(startRectOrQueue) {
+    if (!startRectOrQueue || startRectOrQueue instanceof Array) {
+      this._crawler = new TileManager.CrawlIterator(this._tileCache);
+
+      if (startRectOrQueue) {
+        let len = startRectOrQueue.length;
+        for (let k = 0; k < len; ++k)
+          this._crawler.enqueue(startRectOrQueue[k].i, startRectOrQueue[k].j);
+      }
+    } else {
+      this._crawler = new TileManager.CrawlIterator(this._tileCache, startRectOrQueue);
+    }
+
+    if (!this._idleTileCrawlerTimeout)
+      this._idleTileCrawlerTimeout = setTimeout(this._idleTileCrawler, 2000, this);
+  },
+
+  stopLazyCrawl: function stopLazyCrawl() {
+    this._idleTileCrawlerTimeout = 0;
+    this._crawler = null;
+
+    let cr = this._criticalRect;
+    if (cr) {
+      let [ctrx, ctry] = cr.centerRounded();
+      this.recenterEvictionQueue(ctrx, ctry);
+    }
+  },
+
+  recenterEvictionQueue: function recenterEvictionQueue(ctrx, ctry) {
+    let ctri = ctrx >> kTileExponentWidth;
+    let ctrj = ctry >> kTileExponentHeight;
+
+    function evictFarTiles(a, b) {
+      let dista = Math.max(Math.abs(a.i - ctri), Math.abs(a.j - ctrj));
+      let distb = Math.max(Math.abs(b.i - ctri), Math.abs(b.j - ctrj));
+      return dista - distb;
+    }
+
+    this._tileCache.sortEvictionQueue(evictFarTiles);
+  },
+
+  _renderTile: function _renderTile(tile) {
+    if (tile.isDirty())
+      tile.render(this._browser, this._browserView);
+  },
+
+  _appendTileSafe: function _appendTileSafe(tile) {
+    if (!tile._appended) {
+      this._appendTile(tile);
+      tile._appended = true;
+    }
+  },
+
+  _removeTileSafe: function _removeTileSafe(tile) {
+    if (tile._appended) {
+      this._removeTile(tile);
+      tile._appended = false;
+    }
+  },
+