Merge Lorentz into mozilla 1.9.2, a=beltzner
authorBenjamin Smedberg <benjamin@smedbergs.us>
Tue, 06 Apr 2010 20:34:51 -0400
changeset 34012 84ba4d805430c3dddde4fa0e55ca9588440591f7
parent 33809 54e951398337b0ef1ab7d4797cb40185aed37960 (current diff)
parent 34011 2513b0b8ef2ace959d3aa1e0484a28f964dd4333 (diff)
child 34013 ec534329e1868135a88a4b2bf643171259a6d736
push id1209
push userbsmedberg@mozilla.com
push dateWed, 07 Apr 2010 13:09:43 +0000
reviewersbeltzner
milestone1.9.2.4pre
Merge Lorentz into mozilla 1.9.2, a=beltzner
browser/base/content/browser.js
browser/config/version.txt
build/automation-build.mk
configure.in
gfx/cairo/endian.patch
js/src/xpconnect/src/nsXPConnect.cpp
layout/generic/nsObjectFrame.cpp
modules/libpref/src/init/all.js
modules/plugin/test/testplugin/Makefile.in
modules/plugin/test/testplugin/nptest_macosx.mm
toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_test.cc
toolkit/crashreporter/google-breakpad/src/client/linux/handler/linux_thread.cc
toolkit/crashreporter/google-breakpad/src/client/linux/handler/linux_thread.h
toolkit/crashreporter/google-breakpad/src/client/linux/handler/linux_thread_test.cc
toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_generator.cc
toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_generator.h
toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_test.cc
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/Makefile.in
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/bytereader-inl.h
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/bytereader.cc
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/bytereader.h
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/dwarf2enums.h
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/dwarf2reader.cc
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/dwarf2reader.h
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.cc
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.h
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/line_state_machine.h
toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/types.h
toolkit/crashreporter/google-breakpad/src/processor/stack_frame_info.h
toolkit/mozapps/plugins/content/missingPlugin.xml
toolkit/mozapps/plugins/content/missingPluginBinding.css
toolkit/themes/pinstripe/mozapps/plugins/missingPlugin.css
toolkit/themes/winstripe/mozapps/plugins/missingPlugin.css
toolkit/xre/nsAppRunner.cpp
widget/src/gtk2/nsWindow.cpp
widget/src/windows/nsWindow.cpp
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -50,17 +50,21 @@ DIRS		= profile/extensions
 PREF_JS_EXPORTS = $(srcdir)/profile/firefox.js \
 		  $(srcdir)/profile/channel-prefs.js \
 		  $(NULL)
 
 
 # hardcode en-US for the moment
 AB_CD = en-US
 
-DEFINES += -DAB_CD=$(AB_CD)
+DEFINES += \
+  -DAB_CD=$(AB_CD) \
+  -DDLL_PREFIX=$(DLL_PREFIX) \
+  -DDLL_SUFFIX=$(DLL_SUFFIX) \
+  $(NULL)
 
 APP_VERSION = $(shell cat $(srcdir)/../config/version.txt)
 DEFINES += -DAPP_VERSION="$(APP_VERSION)"
 APP_UA_NAME = $(shell echo $(MOZ_APP_DISPLAYNAME) | sed -e's/[^A-Za-z]//g')
 DEFINES += -DAPP_UA_NAME="$(APP_UA_NAME)"
 
 DIST_FILES = application.ini
 
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -904,15 +904,29 @@ pref("browser.sessionstore.interval", 60
 
 // Whether to use a panel that looks like an OS X sheet for customization
 #ifdef XP_MACOSX
 pref("toolbar.customization.usesheet", true);
 #else
 pref("toolbar.customization.usesheet", false);
 #endif
 
+// Whitelist the test plugin, Flash, Silverlight, and QuickTime
+ 
+pref("dom.ipc.plugins.enabled.@DLL_PREFIX@nptest@DLL_SUFFIX@", true);
+#ifdef XP_WIN
+pref("dom.ipc.plugins.enabled.npswf32.dll", true);
+pref("dom.ipc.plugins.enabled.npctrl.dll", true);
+pref("dom.ipc.plugins.enabled.npqtplugin.dll", true);
+#endif
+#ifdef XP_UNIX
+pref("dom.ipc.plugins.enabled.libflashplayer.so", true);
+#endif
+
+pref("dom.ipc.plugins.enabled", false);
+
 #ifdef XP_WIN
 #ifndef WINCE
 pref("browser.taskbar.previews.enable", false);
 pref("browser.taskbar.previews.max", 20);
 pref("browser.taskbar.previews.cachetime", 20);
 #endif
 #endif
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -129,17 +129,17 @@ var gEditUIVisible = true;
   delete this.PluralForm;
   return this.PluralForm = val;
 });
 
 #ifdef MOZ_CRASHREPORTER
 __defineGetter__("gCrashReporter", function() {
   delete this.gCrashReporter;
   return this.gCrashReporter = Cc["@mozilla.org/xre/app-info;1"].
-                               getService(Ci.nsICrashReporter);
+                               getService(Ci.nsICrashReporter_MOZILLA_1_9_2_BRANCH);
 });
 #endif
 
 let gInitialPages = [
   "about:blank",
   "about:privatebrowsing",
   "about:sessionrestore"
 ];
@@ -1095,24 +1095,28 @@ function HandleAppCommandEvent(evt) {
     BrowserHome();
     break;
   default:
     break;
   }
 }
 
 function prepareForStartup() {
+  var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
+
   gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver.onUpdatePageReport, false);
   // Note: we need to listen to untrusted events, because the pluginfinder XBL
   // binding can't fire trusted ones (runs with page privileges).
   gBrowser.addEventListener("PluginNotFound", gMissingPluginInstaller.newMissingPlugin, true, true);
+  gBrowser.addEventListener("PluginCrashed", gMissingPluginInstaller.pluginInstanceCrashed, true, true);
   gBrowser.addEventListener("PluginBlocklisted", gMissingPluginInstaller.newMissingPlugin, true, true);
   gBrowser.addEventListener("PluginOutdated", gMissingPluginInstaller.newMissingPlugin, true, true);
   gBrowser.addEventListener("PluginDisabled", gMissingPluginInstaller.newDisabledPlugin, true, true);
   gBrowser.addEventListener("NewPluginInstalled", gMissingPluginInstaller.refreshBrowser, false);
+  os.addObserver(gMissingPluginInstaller, "plugin-crashed", false);
   gBrowser.addEventListener("NewTab", BrowserOpenTab, false);
   window.addEventListener("AppCommand", HandleAppCommandEvent, true);
 
   var webNavigation;
   try {
     webNavigation = getWebNavigation();
     if (!webNavigation)
       throw "no XBL binding for browser";
@@ -1147,17 +1151,16 @@ function prepareForStartup() {
 
   // Manually hook up session and global history for the first browser
   // so that we don't have to load global history before bringing up a
   // window.
   // Wire up session and global history before any possible
   // progress notifications for back/forward button updating
   webNavigation.sessionHistory = Components.classes["@mozilla.org/browser/shistory;1"]
                                            .createInstance(Components.interfaces.nsISHistory);
-  var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
   os.addObserver(gBrowser.browsers[0], "browser:purge-session-history", false);
 
   // remove the disablehistory attribute so the browser cleans up, as
   // though it had done this work itself
   gBrowser.browsers[0].removeAttribute("disablehistory");
 
   // enable global history
   try {
@@ -1400,16 +1403,17 @@ function BrowserShutdown()
   catch(ex) {
     Components.utils.reportError(ex);
   }
 
   var os = Components.classes["@mozilla.org/observer-service;1"]
     .getService(Components.interfaces.nsIObserverService);
   os.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
   os.removeObserver(gXPInstallObserver, "xpinstall-install-blocked");
+  os.removeObserver(gMissingPluginInstaller, "plugin-crashed");
 
   try {
     gBrowser.removeProgressListener(window.XULBrowserWindow);
     gBrowser.removeTabsProgressListener(window.TabsProgressListener);
   } catch (ex) {
   }
 
   PlacesStarButton.uninit();
@@ -4446,17 +4450,17 @@ nsBrowserAccess.prototype =
   QueryInterface : function(aIID)
   {
     if (aIID.equals(Ci.nsIBrowserDOMWindow) ||
         aIID.equals(Ci.nsISupports))
       return this;
     throw Components.results.NS_NOINTERFACE;
   },
 
-  openURI : function(aURI, aOpener, aWhere, aContext)
+  openURI : function (aURI, aOpener, aWhere, aContext)
   {
     var newWindow = null;
     var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
 
     if (isExternal && aURI && aURI.schemeIs("chrome")) {
       dump("use -chrome command-line option to load external chrome urls\n");
       return null;
     }
@@ -4517,17 +4521,17 @@ nsBrowserAccess.prototype =
           gBrowser.loadURIWithFlags(aURI.spec, loadflags, referrer, null, null);
         }
         if (!gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground"))
           content.focus();
     }
     return newWindow;
   },
 
-  isTabContentWindow : function(aWindow)
+  isTabContentWindow : function (aWindow)
   {
     return gBrowser.browsers.some(function (browser) browser.contentWindow == aWindow);
   }
 }
 
 function onViewToolbarsPopupShowing(aEvent)
 {
   var popup = aEvent.target;
@@ -5934,216 +5938,536 @@ function getPluginInfo(pluginElement)
     if (tagMimetype == "") {
       tagMimetype = pluginElement.type;
     }
   }
 
   return {mimetype: tagMimetype, pluginsPage: pluginsPage};
 }
 
-function missingPluginInstaller(){
-}
-
-missingPluginInstaller.prototype.installSinglePlugin = function(aEvent){
-  var missingPluginsArray = {};
-
-  var pluginInfo = getPluginInfo(aEvent.target);
-  missingPluginsArray[pluginInfo.mimetype] = pluginInfo;
-
-  if (missingPluginsArray) {
-    window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
-                      "PFSWindow", "chrome,centerscreen,resizable=yes",
-                      {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
-  }
-
-  aEvent.stopPropagation();
-}
-
-missingPluginInstaller.prototype.managePlugins = function(aEvent){
-  BrowserOpenAddonsMgr("plugins");
-  aEvent.stopPropagation();
-}
-
-missingPluginInstaller.prototype.newMissingPlugin = function(aEvent){
-  // Since we are expecting also untrusted events, make sure
-  // that the target is a plugin
-  if (!(aEvent.target instanceof Components.interfaces.nsIObjectLoadingContent))
-    return;
-
-  // For broken non-object plugin tags, register a click handler so
-  // that the user can click the plugin replacement to get the new
-  // plugin. Object tags can, and often do, deal with that themselves,
-  // so don't stomp on the page developers toes.
-
-  if (aEvent.type != "PluginBlocklisted" &&
-      aEvent.type != "PluginOutdated" &&
-      !(aEvent.target instanceof HTMLObjectElement)) {
-    aEvent.target.addEventListener("click",
-                                   gMissingPluginInstaller.installSinglePlugin,
-                                   true);
-  }
-
-  let hideBarPrefName = aEvent.type == "PluginOutdated" ?
-                  "plugins.hide_infobar_for_outdated_plugin" :
-                  "plugins.hide_infobar_for_missing_plugin";
-  try {
-    if (gPrefService.getBoolPref(hideBarPrefName))
+var gMissingPluginInstaller = {
+
+  get CrashSubmit() {
+    delete this.CrashSubmit;
+    Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
+    return this.CrashSubmit;
+  },
+
+  get crashReportHelpURL() {
+    delete this.crashReportHelpURL;
+    let url = formatURL("app.support.baseURL", true);
+    url += "plugin-crashed";
+    this.crashReportHelpURL = url;
+    return this.crashReportHelpURL;
+  },
+
+  addLinkClickCallback: function (linkNode, callbackName /*callbackArgs...*/) {
+    // XXX just doing (callback)(arg) was giving a same-origin error. bug?
+    let self = this;
+    let callbackArgs = Array.prototype.slice.call(arguments).slice(2);
+    linkNode.addEventListener("click",
+                              function(evt) {
+                                if (!evt.isTrusted)
+                                  return;
+                                evt.preventDefault();
+                                if (callbackArgs.length == 0)
+                                  callbackArgs = [ evt ];
+                                (self[callbackName]).apply(self, callbackArgs);
+                              },
+                              true);
+
+    linkNode.addEventListener("keydown",
+                              function(evt) {
+                                if (!evt.isTrusted)
+                                  return;
+                                if (evt.keyCode == evt.DOM_VK_RETURN) {
+                                  evt.preventDefault();
+                                  if (callbackArgs.length == 0)
+                                    callbackArgs = [ evt ];
+                                  evt.preventDefault();
+                                  (self[callbackName]).apply(self, callbackArgs);
+                                }
+                              },
+                              true);
+  },
+
+  // Callback for user clicking on a missing (unsupported) plugin.
+  installSinglePlugin: function (aEvent) {
+    var missingPluginsArray = {};
+
+    var pluginInfo = getPluginInfo(aEvent.target);
+    missingPluginsArray[pluginInfo.mimetype] = pluginInfo;
+
+    openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
+               "PFSWindow", "chrome,centerscreen,resizable=yes",
+               {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
+  },
+
+  // Callback for user clicking on a disabled plugin
+  managePlugins: function (aEvent) {
+    BrowserOpenAddonsMgr("plugins");
+  },
+
+  // Callback for user clicking "submit a report" link
+  submitReport : function(pluginDumpID, browserDumpID) {
+    // The crash reporter wants a DOM element it can append an IFRAME to,
+    // which it uses to submit a form. Let's just give it gBrowser.
+    this.CrashSubmit.submit(pluginDumpID, gBrowser, null, null);
+    if (browserDumpID)
+      this.CrashSubmit.submit(browserDumpID, gBrowser, null, null);
+  },
+
+  // Callback for user clicking a "reload page" link
+  reloadPage: function (browser) {
+    browser.reload();
+  },
+
+  // Callback for user clicking the help icon
+  openHelpPage: function () {
+    openHelpLink("plugin-crashed", false);
+  },
+
+
+
+  // event listener for missing/blocklisted/outdated plugins.
+  newMissingPlugin: function (aEvent) {
+    // Since we are expecting also untrusted events, make sure
+    // that the target is a plugin
+    if (!(aEvent.target instanceof Ci.nsIObjectLoadingContent))
       return;
-  } catch (ex) {} // if the pref is missing, treat it as false, which shows the infobar
-
-  var browser = gBrowser.getBrowserForDocument(aEvent.target.ownerDocument
-                                                     .defaultView.top.document);
-  if (!browser.missingPlugins)
-    browser.missingPlugins = {};
-
-  var pluginInfo = getPluginInfo(aEvent.target);
-
-  browser.missingPlugins[pluginInfo.mimetype] = pluginInfo;
-
-  var notificationBox = gBrowser.getNotificationBox(browser);
-
-  // Should only display one of these warnings per page.
-  // In order of priority, they are: outdated > missing > blocklisted
-
-  // If there is already an outdated plugin notification then do nothing
-  if (notificationBox.getNotificationWithValue("outdated-plugins"))
-    return;
-  var blockedNotification = notificationBox.getNotificationWithValue("blocked-plugins");
-  var missingNotification = notificationBox.getNotificationWithValue("missing-plugins");
-  var priority = notificationBox.PRIORITY_WARNING_MEDIUM;
+
+    // For broken non-object plugin tags, register a click handler so
+    // that the user can click the plugin replacement to get the new
+    // plugin. Object tags can, and often do, deal with that themselves,
+    // so don't stomp on the page developers toes.
+
+    if (aEvent.type != "PluginBlocklisted" &&
+        aEvent.type != "PluginOutdated" &&
+        !(aEvent.target instanceof HTMLObjectElement)) {
+          gMissingPluginInstaller.addLinkClickCallback(aEvent.target, "installSinglePlugin");
+    }
+
+    let hideBarPrefName = aEvent.type == "PluginOutdated" ?
+                    "plugins.hide_infobar_for_outdated_plugin" :
+                    "plugins.hide_infobar_for_missing_plugin";
+    try {
+      if (gPrefService.getBoolPref(hideBarPrefName))
+        return;
+    } catch (ex) {} // if the pref is missing, treat it as false, which shows the infobar
+
+    var browser = gBrowser.getBrowserForDocument(aEvent.target.ownerDocument
+                                                       .defaultView.top.document);
+    if (!browser.missingPlugins)
+      browser.missingPlugins = {};
+
+    var pluginInfo = getPluginInfo(aEvent.target);
+
+    browser.missingPlugins[pluginInfo.mimetype] = pluginInfo;
+
+    var notificationBox = gBrowser.getNotificationBox(browser);
+
+    // Should only display one of these warnings per page.
+    // In order of priority, they are: outdated > missing > blocklisted
+
+    // If there is already an outdated plugin notification then do nothing
+    if (notificationBox.getNotificationWithValue("outdated-plugins"))
+      return;
+    var blockedNotification = notificationBox.getNotificationWithValue("blocked-plugins");
+    var missingNotification = notificationBox.getNotificationWithValue("missing-plugins");
+    var priority = notificationBox.PRIORITY_WARNING_MEDIUM;
+
+    function showBlocklistInfo() {
+      var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
+                      getService(Ci.nsIURLFormatter);
+      var url = formatter.formatURLPref("extensions.blocklist.detailsURL");
+      gBrowser.loadOneTab(url, {inBackground: false});
+      return true;
+    }
   
-  function showBlocklistInfo() {
-    var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
-                    getService(Ci.nsIURLFormatter);
-    var url = formatter.formatURLPref("extensions.blocklist.detailsURL");
-    gBrowser.loadOneTab(url, {inBackground: false});
-    return true;
-  }
-  
-  function showOutdatedPluginsInfo() {
-    gPrefService.setBoolPref("plugins.update.notifyUser", false);
-    var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
-                    getService(Ci.nsIURLFormatter);
-    var url = formatter.formatURLPref("plugins.update.url");
-    gBrowser.loadOneTab(url, {inBackground: false});
-    return true;
-  }
+    function showOutdatedPluginsInfo() {
+      gPrefService.setBoolPref("plugins.update.notifyUser", false);
+      var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
+                      getService(Ci.nsIURLFormatter);
+      var url = formatter.formatURLPref("plugins.update.url");
+      gBrowser.loadOneTab(url, {inBackground: false});
+      return true;
+    }
   
-  function showPluginsMissing() {
-    // get the urls of missing plugins
-    var missingPluginsArray = gBrowser.selectedBrowser.missingPlugins;
-    if (missingPluginsArray) {
-      window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
-                        "PFSWindow", "chrome,centerscreen,resizable=yes",
-                        {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
-    }
-  }
-
-  if (aEvent.type == "PluginBlocklisted") {
-    if (blockedNotification || missingNotification)
+    function showPluginsMissing() {
+      // get the urls of missing plugins
+      var missingPluginsArray = gBrowser.selectedBrowser.missingPlugins;
+      if (missingPluginsArray) {
+        window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
+                          "PFSWindow", "chrome,centerscreen,resizable=yes",
+                          {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
+      }
+    }
+
+    if (aEvent.type == "PluginBlocklisted") {
+      if (blockedNotification || missingNotification)
+        return;
+
+      let iconURL = "chrome://mozapps/skin/plugins/pluginBlocked-16.png";
+      let messageString = gNavigatorBundle.getString("blockedpluginsMessage.title");
+      let buttons = [{
+        label: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.label"),
+        accessKey: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.accesskey"),
+        popup: null,
+        callback: showBlocklistInfo
+      }, {
+        label: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.label"),
+        accessKey: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.accesskey"),
+        popup: null,
+        callback: showOutdatedPluginsInfo
+      }];
+
+      notificationBox.appendNotification(messageString, "blocked-plugins",
+                                         iconURL, priority, buttons);
+    }
+    else if (aEvent.type == "PluginOutdated") {
+      // Cancel any notification about blocklisting/missing plugins
+      if (blockedNotification)
+        blockedNotification.close();
+      if (missingNotification)
+        missingNotification.close();
+
+      let iconURL = "chrome://mozapps/skin/plugins/pluginOutdated-16.png";
+      let messageString = gNavigatorBundle.getString("outdatedpluginsMessage.title");
+      let buttons = [{
+        label: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.label"),
+        accessKey: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.accesskey"),
+        popup: null,
+        callback: showOutdatedPluginsInfo
+      }];
+
+      notificationBox.appendNotification(messageString, "outdated-plugins",
+                                         iconURL, priority, buttons);
+    }
+    else if (aEvent.type == "PluginNotFound") {
+      if (missingNotification)
+        return;
+
+      // Cancel any notification about blocklisting plugins
+      if (blockedNotification)
+        blockedNotification.close();
+
+      let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
+      let messageString = gNavigatorBundle.getString("missingpluginsMessage.title");
+      let buttons = [{
+        label: gNavigatorBundle.getString("missingpluginsMessage.button.label"),
+        accessKey: gNavigatorBundle.getString("missingpluginsMessage.button.accesskey"),
+        popup: null,
+        callback: showPluginsMissing
+      }];
+
+      notificationBox.appendNotification(messageString, "missing-plugins",
+                                         iconURL, priority, buttons);
+    }
+  },
+
+  newDisabledPlugin: function (aEvent) {
+    // Since we are expecting also untrusted events, make sure
+    // that the target is a plugin
+    if (!(aEvent.target instanceof Components.interfaces.nsIObjectLoadingContent))
+      return;
+
+    gMissingPluginInstaller.addLinkClickCallback(aEvent.target, "managePlugins");
+  },
+
+  // Crashed-plugin observer. Notified once per plugin crash, before events
+  // are dispatched to individual plugin instances.
+  observe: function(subject, topic, data) {
+    if (topic != "plugin-crashed")
+      return;
+
+    let propertyBag = subject;
+    if (!(propertyBag instanceof Ci.nsIPropertyBag2) ||
+        !(propertyBag instanceof Ci.nsIWritablePropertyBag2))
+     return;
+
+#ifdef MOZ_CRASHREPORTER
+    let pluginDumpID = propertyBag.getPropertyAsAString("pluginDumpID");
+    let browserDumpID= propertyBag.getPropertyAsAString("browserDumpID");
+    let shouldSubmit = gCrashReporter.submitReports;
+    let doPrompt     = true; // XXX followup to get via gCrashReporter
+
+    // Submit automatically when appropriate.
+    if (pluginDumpID && shouldSubmit && !doPrompt) {
+      this.submitReport(pluginDumpID, browserDumpID);
+      // Submission is async, so we can't easily show failure UI.
+      propertyBag.setPropertyAsBool("submittedCrashReport", true);
+    }
+#endif
+  },
+
+  // Crashed-plugin event listener. Called for every instance of a
+  // plugin in content.
+  pluginInstanceCrashed: function (aEvent) {
+    let self = gMissingPluginInstaller;
+
+    // Evil content could fire a fake event at us, ignore them.
+    if (!aEvent.isTrusted)
+      return;
+
+    if (!(aEvent instanceof Ci.nsIDOMDataContainerEvent))
+      return;
+
+    let submittedReport = aEvent.getData("submittedCrashReport");
+    let doPrompt        = true; // XXX followup for .getData("doPrompt");
+    let submitReports   = true; // XXX followup for .getData("submitReports");
+    let pluginName      = aEvent.getData("pluginName");
+    let pluginDumpID    = aEvent.getData("pluginDumpID");
+    let browserDumpID   = aEvent.getData("browserDumpID");
+
+    // We're expecting this to be a plugin.
+    let plugin = aEvent.target;
+    if (!(plugin instanceof Ci.nsIObjectLoadingContent))
       return;
 
-    let iconURL = "chrome://mozapps/skin/plugins/pluginBlocked-16.png";
-    let messageString = gNavigatorBundle.getString("blockedpluginsMessage.title");
-    let buttons = [{
-      label: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.label"),
-      accessKey: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.accesskey"),
-      popup: null,
-      callback: showBlocklistInfo
-    }, {
-      label: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.label"),
-      accessKey: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.accesskey"),
-      popup: null,
-      callback: showOutdatedPluginsInfo
-    }];
-
-    notificationBox.appendNotification(messageString, "blocked-plugins",
-                                       iconURL, priority, buttons);
-  }
-  else if (aEvent.type == "PluginOutdated") {
-    // Cancel any notification about blocklisting/missing plugins
-    if (blockedNotification)
-      blockedNotification.close();
-    if (missingNotification)
-      missingNotification.close();
-
-    let iconURL = "chrome://mozapps/skin/plugins/pluginOutdated-16.png";
-    let messageString = gNavigatorBundle.getString("outdatedpluginsMessage.title");
-    let buttons = [{
-      label: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.label"),
-      accessKey: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.accesskey"),
-      popup: null,
-      callback: showOutdatedPluginsInfo
-    }];
-
-    notificationBox.appendNotification(messageString, "outdated-plugins",
-                                       iconURL, priority, buttons);
-  }
-  else if (aEvent.type == "PluginNotFound") {
-    if (missingNotification)
-      return;
-
-    // Cancel any notification about blocklisting plugins
-    if (blockedNotification)
-      blockedNotification.close();
-
-    let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
-    let messageString = gNavigatorBundle.getString("missingpluginsMessage.title");
-    let buttons = [{
-      label: gNavigatorBundle.getString("missingpluginsMessage.button.label"),
-      accessKey: gNavigatorBundle.getString("missingpluginsMessage.button.accesskey"),
-      popup: null,
-      callback: showPluginsMissing
-    }];
-  
-    notificationBox.appendNotification(messageString, "missing-plugins",
-                                       iconURL, priority, buttons);
-  }
-}
-
-missingPluginInstaller.prototype.newDisabledPlugin = function(aEvent){
-  // Since we are expecting also untrusted events, make sure
-  // that the target is a plugin
-  if (!(aEvent.target instanceof Components.interfaces.nsIObjectLoadingContent))
-    return;
-
-  aEvent.target.addEventListener("click",
-                                 gMissingPluginInstaller.managePlugins,
-                                 true);
-}
-
-missingPluginInstaller.prototype.refreshBrowser = function(aEvent) {
-  // browser elements are anonymous so we can't just use target.
-  var browser = aEvent.originalTarget;
-  var notificationBox = gBrowser.getNotificationBox(browser);
-  var notification = notificationBox.getNotificationWithValue("missing-plugins");
-
-  // clear the plugin list, now that at least one plugin has been installed
-  browser.missingPlugins = null;
-  if (notification) {
-    // reset UI
-    notificationBox.removeNotification(notification);
-  }
-  // reload the browser to make the new plugin show.
-  browser.reload();
-}
-
-var gMissingPluginInstaller = new missingPluginInstaller();
+    // Force a style flush, so that we ensure our binding is attached.
+    plugin.clientTop;
+
+    let messageString;
+    try {
+      messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);
+    } catch (e) {
+      messageString = "The " + pluginName + " plugin has crashed.";
+    }
+
+    //
+    // Configure the crashed-plugin placeholder.
+    //
+    let doc = plugin.ownerDocument;
+    let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+
+    // The binding has role="link" here, since missing/disabled/blocked
+    // plugin UI has a onclick handler on the whole thing. This isn't needed
+    // for the plugin-crashed UI, because we use actual HTML links in the text.
+    overlay.removeAttribute("role");
+
+#ifdef MOZ_CRASHREPORTER
+    // Determine which message to show regarding crash reports.
+    let helpClass, showClass;
+    if (submittedReport) { // submitReports && !doPrompt, handled in observer
+      showClass = "msg msgSubmitted";
+    }
+    else if (!submitReports && !doPrompt) {
+      showClass = "msg msgNotSubmitted";
+    }
+    else { // doPrompt
+      showClass = "msg msgPleaseSubmit";
+      // XXX can we make the link target actually be blank?
+      let pleaseLink = doc.getAnonymousElementByAttribute(
+                            plugin, "class", "pleaseSubmitLink");
+      self.addLinkClickCallback(pleaseLink, "submitReport",
+                                pluginDumpID, browserDumpID);
+    }
+
+    // If we don't have a minidumpID, we can't (or didn't) submit anything.
+    // This can happen if the plugin is killed from the task manager.
+    if (!pluginDumpID) {
+        showClass = "msg msgNoCrashReport";
+    }
+
+    let textToShow = doc.getAnonymousElementByAttribute(plugin, "class", showClass);
+    textToShow.style.display = "block";
+
+    let bottomLinks = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgBottomLinks");
+    bottomLinks.style.display = "block";
+    let helpIcon = doc.getAnonymousElementByAttribute(plugin, "class", "helpIcon");
+    self.addLinkClickCallback(helpIcon, "openHelpPage");
+
+    // If we're showing the link to manually trigger report submission, we'll
+    // want to be able to update all the instances of the UI for this crash to
+    // show an updated message when a report is submitted.
+    if (doPrompt) {
+      let observer = {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                               Ci.nsISupportsWeakReference]),
+        observe : function(subject, topic, data) {
+          let propertyBag = subject;
+          if (!(propertyBag instanceof Ci.nsIPropertyBag2))
+            return;
+          // Ignore notifications for other crashes.
+          if (propertyBag.get("minidumpID") != pluginDumpID)
+            return;
+          self.updateSubmissionStatus(plugin, propertyBag, data);
+        },
+
+        handleEvent : function(event) {
+            // Not expected to be called, just here for the closure.
+        }
+      }
+
+      let obs = Cc["@mozilla.org/observer-service;1"].
+                getService(Ci.nsIObserverService);
+      // Use a weak reference, so we don't have to remove it...
+      obs.addObserver(observer, "crash-report-status", true);
+      // ...alas, now we need something to hold a strong reference to prevent
+      // it from being GC. But I don't want to manually manage the reference's
+      // lifetime (which should be no greater than the page).
+      // Clever solution? Use a closue with an event listener on the document.
+      // When the doc goes away, so do the listener references and the closure.
+      doc.addEventListener("mozCleverClosureHack", observer, false);
+    }
+#endif
+
+    let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgCrashed");
+    crashText.textContent = messageString;
+
+    let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
+
+    let link = doc.getAnonymousElementByAttribute(plugin, "class", "reloadLink");
+    self.addLinkClickCallback(link, "reloadPage", browser);
+
+    let notificationBox = gBrowser.getNotificationBox(browser);
+
+    // Is the <object>'s size too small to hold what we want to show?
+    let pluginRect = plugin.getBoundingClientRect();
+    // XXX bug 446693. The text-shadow on the submitted-report text at
+    //     the bottom causes scrollHeight to be larger than it should be.
+    let isObjectTooSmall = (overlay.scrollWidth > pluginRect.width) ||
+                           (overlay.scrollHeight - 5 > pluginRect.height);
+    if (isObjectTooSmall) {
+        // Hide the overlay's contents. Use visibility style, so that it
+        // doesn't collapse down to 0x0.
+        overlay.style.visibility = "hidden";
+        // If another plugin on the page was large enough to show our UI, we
+        // don't want to show a notification bar.
+        if (!doc.mozNoPluginCrashedNotification)
+          showNotificationBar(pluginDumpID, browserDumpID);
+    } else {
+        // If a previous plugin on the page was too small and resulted in
+        // adding a notification bar, then remove it because this plugin
+        // instance it big enough to serve as in-content notification.
+        hideNotificationBar();
+        doc.mozNoPluginCrashedNotification = true;
+    }
+
+    function hideNotificationBar() {
+      let notification = notificationBox.getNotificationWithValue("plugin-crashed");
+      if (notification)
+        notificationBox.removeNotification(notification, true);
+    }
+
+    function showNotificationBar(pluginDumpID, browserDumpID) {
+      // If there's already an existing notification bar, don't do anything.
+      let notification = notificationBox.getNotificationWithValue("plugin-crashed");
+      if (notification)
+        return;
+
+      // Configure the notification bar
+      let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
+      let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
+
+      let reloadLabel, reloadKey, submitLabel, submitKey;
+      try {
+        reloadLabel = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label");
+        reloadKey   = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey");
+        submitLabel = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.label");
+        submitKey   = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.accesskey");
+      } catch (e) {
+        reloadLabel = "Reload page";
+        reloadKey   = "R";
+        submitLabel = "Submit a crash report";
+        submitKey   = "S";
+      }
+
+      let buttons = [{
+        label: reloadLabel,
+        accessKey: reloadKey,
+        popup: null,
+        callback: function() { browser.reload(); },
+      }];
+#ifdef MOZ_CRASHREPORTER
+      let submitButton = {
+        label: submitLabel,
+        accessKey: submitKey,
+        popup: null,
+          callback: function() { gMissingPluginInstaller.submitReport(pluginDumpID, browserDumpID); },
+      };
+      if (minidumpID)
+        buttons.push(submitButton);
+#endif
+
+      let notification = notificationBox.appendNotification(messageString, "plugin-crashed",
+                                                            iconURL, priority, buttons);
+
+      // Add the "learn more" link.
+      let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+      let link = notification.ownerDocument.createElementNS(XULNS, "label");
+      link.className = "text-link";
+      let learnMore;
+      try {
+        learnMore = gNavigatorBundle.getString("crashedpluginsMessage.learnMore");
+      } catch (e) {
+        learnMore = "Learn More\u2026";
+      }
+      link.setAttribute("value", learnMore);
+      link.href = gMissingPluginInstaller.crashReportHelpURL;
+      let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
+      description.appendChild(link);
+    }
+
+  },
+
+  updateSubmissionStatus : function (plugin, propBag, status) {
+    let doc = plugin.ownerDocument;
+
+    // One of these two may already be visible, reset them to be hidden.
+    let pleaseText     = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgPleaseSubmit");
+    let submittingText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgSubmitting");
+    pleaseText.style.display = "";
+    submittingText.style.display = "";
+
+    let msgClass;
+    switch (status) {
+      case "submitting":
+        msgClass = "msg msgSubmitting";
+        break;
+      case "success":
+        msgClass = "msg msgSubmitted";
+        break;
+      case "failed":
+        msgClass = "msg msgSubmitFailed";
+        break;
+    }
+
+    let textToShow = doc.getAnonymousElementByAttribute(plugin, "class", msgClass);
+    textToShow.style.display = "block";
+  },
+
+  refreshBrowser: function (aEvent) {
+    // browser elements are anonymous so we can't just use target.
+    var browser = aEvent.originalTarget;
+    var notificationBox = gBrowser.getNotificationBox(browser);
+    var notification = notificationBox.getNotificationWithValue("missing-plugins");
+
+    // clear the plugin list, now that at least one plugin has been installed
+    browser.missingPlugins = null;
+    if (notification) {
+      // reset UI
+      notificationBox.removeNotification(notification);
+    }
+    // reload the browser to make the new plugin show.
+    browser.reload();
+  }
+};
 
 function convertFromUnicode(charset, str)
 {
   try {
     var unicodeConverter = Components
        .classes["@mozilla.org/intl/scriptableunicodeconverter"]
        .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
     unicodeConverter.charset = charset;
     str = unicodeConverter.ConvertFromUnicode(str);
     return str + unicodeConverter.Finish();
   } catch(ex) {
-    return null; 
+    return null;
   }
 }
 
 /**
  * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
  * and shows UI when they are discovered. 
  */
 var FeedHandler = {
--- a/browser/branding/unofficial/branding.nsi
+++ b/browser/branding/unofficial/branding.nsi
@@ -35,13 +35,13 @@
 # ***** END LICENSE BLOCK *****
 
 # NSIS branding defines for unofficial builds.
 # The official release build branding.nsi is located in other-license/branding/firefox/
 # The nightly build branding.nsi is located in browser/installer/windows/nsis/
 
 # BrandFullNameInternal is used for some registry and file system values
 # instead of BrandFullName and typically should not be modified.
-!define BrandFullNameInternal "Namoroka"
+!define BrandFullNameInternal "Lorentz"
 !define CompanyName           "mozilla.org"
 !define URLInfoAbout          "http://www.mozilla.org"
 !define URLUpdateInfo         "http://www.mozilla.org/projects/firefox"
 !define SurveyURL             "https://survey.mozilla.com/1/Mozilla%20Firefox/${AppVersion}/${AB_CD}/exit.html"
--- a/browser/branding/unofficial/configure.sh
+++ b/browser/branding/unofficial/configure.sh
@@ -1,1 +1,1 @@
-MOZ_APP_DISPLAYNAME="Namoroka"
+MOZ_APP_DISPLAYNAME="Lorentz"
--- a/browser/branding/unofficial/locales/browserconfig.properties
+++ b/browser/branding/unofficial/locales/browserconfig.properties
@@ -1,3 +1,3 @@
 # Do NOT localize or otherwise change these values
-browser.startup.homepage=http://www.mozilla.org/projects/namoroka/
+browser.startup.homepage=http://www.mozilla.org/projects/lorentz/
 
--- a/browser/branding/unofficial/locales/en-US/brand.dtd
+++ b/browser/branding/unofficial/locales/en-US/brand.dtd
@@ -1,7 +1,7 @@
-<!ENTITY  brandShortName        "Namoroka">
-<!ENTITY  brandFullName         "Namoroka">
+<!ENTITY  brandShortName        "Lorentz">
+<!ENTITY  brandFullName         "Lorentz">
 <!ENTITY  vendorShortName       "mozilla.org">
 <!ENTITY  logoCopyright         " ">
 
 <!-- LOCALIZATION NOTE (releaseBaseURL): The about: page appends __MOZ_APP_VERSION__.html, e.g. 2.0.html -->
-<!ENTITY  releaseBaseURL        "http://www.mozilla.org/projects/namoroka/releases/">
+<!ENTITY  releaseBaseURL        "http://www.mozilla.org/projects/lorentz/releases/">
--- a/browser/branding/unofficial/locales/en-US/brand.properties
+++ b/browser/branding/unofficial/locales/en-US/brand.properties
@@ -1,3 +1,3 @@
-brandShortName=Namoroka
-brandFullName=Namoroka
+brandShortName=Lorentz
+brandFullName=Lorentz
 vendorShortName=mozilla.org
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -61,16 +61,19 @@ var gAdvancedPane = {
     }
 
 #ifdef MOZ_UPDATER
     this.updateAppUpdateItems();
     this.updateAutoItems();
     this.updateModeItems();
 #endif
     this.updateOfflineApps();
+#ifdef MOZ_CRASHREPORTER
+    this.initSubmitCrashes();
+#endif
   },
 
   /**
    * Stores the identity of the current tab in preferences so that the selected
    * tab can be persisted between openings of the preferences window.
    */
   tabSelectionChanged: function ()
   {
@@ -134,16 +137,45 @@ var gAdvancedPane = {
    * unchanged and represents a value not strictly allowed in UI.
    */
   writeCheckSpelling: function ()
   {
     var checkbox = document.getElementById("checkSpelling");
     return checkbox.checked ? (this._storedSpellCheck == 2 ? 2 : 1) : 0;
   },
 
+  /**
+   *
+   */
+  initSubmitCrashes: function ()
+  {
+    var checkbox = document.getElementById("submitCrashesBox");
+    try {
+      var cr = Components.classes["@mozilla.org/toolkit/crash-reporter;1"].
+               getService(Components.interfaces.nsICrashReporter_MOZILLA_1_9_2_BRANCH);
+      checkbox.checked = cr.submitReports;
+    } catch (e) {
+      checkbox.style.display = "none";
+    }
+  },
+
+  /**
+   *
+   */
+  updateSubmitCrashes: function ()
+  {
+    var checkbox = document.getElementById("submitCrashesBox");
+    try {
+      var cr = Components.classes["@mozilla.org/toolkit/crash-reporter;1"].
+               getService(Components.interfaces.nsICrashReporter);
+      cr.submitReports = checkbox.checked;
+    } catch (e) { }
+  },
+
+
   // NETWORK TAB
 
   /*
    * Preferences:
    *
    * browser.cache.disk.capacity
    * - the size of the browser cache in KB
    */
--- a/browser/components/preferences/advanced.xul
+++ b/browser/components/preferences/advanced.xul
@@ -42,16 +42,18 @@
 
 <!DOCTYPE overlay [
 <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
 %brandDTD;
 <!ENTITY % advancedDTD SYSTEM "chrome://browser/locale/preferences/advanced.dtd">
 %advancedDTD;
 <!ENTITY % privacyDTD SYSTEM "chrome://browser/locale/preferences/privacy.dtd">
 %privacyDTD;
+<!ENTITY submitCrashes.label "Submit crash reports">
+<!ENTITY submitCrashes.accesskey "S">
 ]>
 
 <overlay id="AdvancedPaneOverlay"
          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <prefpane id="paneAdvanced" onpaneload="gAdvancedPane.init();">
 
     <preferences id="advancedPreferences">
@@ -179,28 +181,33 @@
                       accesskey="&checkSpelling.accesskey;"
                       onsyncfrompreference="return gAdvancedPane.readCheckSpelling();"
                       onsynctopreference="return gAdvancedPane.writeCheckSpelling();"
                       preference="layout.spellcheckDefault"/>
           </groupbox>
 
 #ifdef HAVE_SHELL_SERVICE
           <!-- System Defaults -->
-          <groupbox id="systemDefaultsGroup" orient="horizontal">
+          <groupbox id="systemDefaultsGroup" orient="vertical">
             <caption label="&systemDefaults.label;"/>
 
             <hbox id="checkDefaultBox" align="center" flex="1">      
               <checkbox id="alwaysCheckDefault" preference="browser.shell.checkDefaultBrowser"
                         label="&alwaysCheckDefault.label;" accesskey="&alwaysCheckDefault.accesskey;"
                         flex="1"/>
               <button id="checkDefaultButton"
                       label="&checkNow.label;" accesskey="&checkNow.accesskey;"
                       oncommand="gAdvancedPane.checkNow()"
                       preference="pref.general.disable_button.default_browser"/>
             </hbox>
+#ifdef MOZ_CRASHREPORTER
+            <checkbox id="submitCrashesBox" flex="1"
+                      oncommand="gAdvancedPane.updateSubmitCrashes();"
+                      label="&submitCrashes.label;" accesskey="&submitCrashes.accesskey;"/>
+#endif
           </groupbox>
 #endif
         </tabpanel>
 
         <!-- Network -->
         <tabpanel id="networkPanel" orient="vertical">
 
            <!-- Connection -->
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -49,26 +49,30 @@
 @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
 #ifdef XP_MACOSX
 @BINPATH@/XUL
 #else
 @BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
 #endif
+#ifdef MOZ_IPC
+@BINPATH@/mozilla-runtime@BIN_SUFFIX@
+#endif
 #ifdef WINCE
 @BINPATH@/mozce_shunt.dll
 #elifdef XP_WIN32
 #ifndef MOZ_MEMORY
 @BINPATH@/Microsoft.VC80.CRT.manifest
 @BINPATH@/msvcm80.dll
 @BINPATH@/msvcp80.dll
 @BINPATH@/msvcr80.dll
 #else
 @BINPATH@/mozcrt19.dll
+@BINPATH@/mozcpp19.dll
 #endif
 #endif
 
 [browser]
 ; [Base Browser Files]
 #ifdef XP_WIN32
 @BINPATH@/@MOZ_APP_NAME@.exe
 #else
@@ -345,16 +349,17 @@
 @BINPATH@/components/nsBadCertHandler.js
 @BINPATH@/components/nsFormAutoComplete.js
 #ifdef XP_MACOSX
 @BINPATH@/components/libalerts_s.dylib
 #endif
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
 #endif
+@BINPATH@/components/nsINIProcessor.js
 
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsSafebrowsingApplication.js
 @BINPATH@/components/nsUrlClassifierListManager.js
 @BINPATH@/components/nsUrlClassifierLib.js
--- a/browser/locales/filter.py
+++ b/browser/locales/filter.py
@@ -1,42 +1,30 @@
 def test(mod, path, entity = None):
   import re
   # ignore anyhting but Firefox
   if mod not in ("netwerk", "dom", "toolkit", "security/manager",
                  "browser", "extensions/reporter", "extensions/spellcheck",
                  "other-licenses/branding/firefox"):
     return False
-
-  # Ignore Lorentz strings, at least temporarily
-  if mod == "toolkit" and path == "chrome/mozapps/plugins/plugins.dtd":
-    if entity.startswith('reloadPlugin.'): return False
-    if entity.startswith('report.'): return False
-
   if mod != "browser" and mod != "extensions/spellcheck":
     # we only have exceptions for browser and extensions/spellcheck
     return True
   if not entity:
     if mod == "extensions/spellcheck":
       return False
     # browser
     return not (re.match(r"searchplugins\/.+\.xml", path) or
                 re.match(r"chrome\/help\/images\/[A-Za-z-_]+\.png", path))
   if mod == "extensions/spellcheck":
     # l10n ships en-US dictionary or something, do compare
     return True
   if path == "defines.inc":
     return entity != "MOZ_LANGPACK_CONTRIBUTORS"
 
-  # Ignore Lorentz strings, at least temporarily
-  if mod == 'browser' and path == 'chrome/browser/browser.properties':
-    if entity.startswith('crashedpluginsMessage.'): return False
-  if mod == 'browser' and path == 'chrome/browser/preferences/advanced.dtd':
-    if entity.startswith('submitCrashes'): return False
-
   if path != "chrome/browser-region/region.properties":
     # only region.properties exceptions remain, compare all others
     return True
   
   return not (re.match(r"browser\.search\.order\.[1-9]", entity) or
               re.match(r"browser\.contentHandlers\.types\.[0-5]", entity) or
               re.match(r"gecko\.handlerService\.schemes\.", entity) or
               re.match(r"gecko\.handlerService\.defaultHandlersVersion", entity))
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -94,18 +94,18 @@ libs:: bloaturls.txt
 
 # Install bloatcycle.html into dist/bin/res, for auto-cycling
 # of bloaturls.txt.  This is for browsers that can't do -f
 # autocycling of URLs.
 libs:: bloatcycle.html
 	$(INSTALL) $< $(DIST)/bin/res
 
 ifeq ($(OS_ARCH),Darwin)
-libs:: $(topsrcdir)/tools/rb/fix-macosx-stack.pl
-	$(INSTALL) $< $(DIST)/bin
+libs:: $(topsrcdir)/tools/rb/fix-macosx-stack.pl $(topsrcdir)/tools/rb/fix_macosx_stack.py
+	$(INSTALL) $^ $(DIST)/bin
 
 # Basic unit tests for some stuff in the unify script
 check::
 # build ppc/i386 binaries, and unify them
 	rm -f unify-test-ppc unify-test-i386 unify-test-universal
 	$(HOST_CC) -arch ppc $(srcdir)/unify-test.c -o unify-test-ppc
 	$(HOST_CC) -arch i386 $(srcdir)/unify-test.c -o unify-test-i386
 	@if ! $(srcdir)/macosx/universal/unify ./unify-test-ppc ./unify-test-i386 \
--- a/build/automation-build.mk
+++ b/build/automation-build.mk
@@ -1,10 +1,9 @@
-
-ifeq ($(USE_SHORT_LIBNAME), 1)
+ifneq (,$(filter OS2 WINCE WINNT,$(OS_ARCH)))
 PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX)
 else
 PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 endif
 
 TARGET_DIST = $(TARGET_DEPTH)/dist
 
 ifeq ($(MOZ_BUILD_APP),camino)
@@ -17,28 +16,26 @@ else
 browser_path = \"$(TARGET_DIST)/$(MOZ_APP_DISPLAYNAME).app/Contents/MacOS/$(PROGRAM)\"
 endif
 else
 browser_path = \"$(TARGET_DIST)/bin/$(PROGRAM)\"
 endif
 endif
 
 _PROFILE_DIR = $(TARGET_DEPTH)/_profile/pgo
-_SYMBOLS_PATH = $(TARGET_DIST)/crashreporter-symbols
 
 ABSOLUTE_TOPSRCDIR = $(call core_abspath,$(MOZILLA_DIR))
 _CERTS_SRC_DIR = $(ABSOLUTE_TOPSRCDIR)/build/pgo/certs
 
 AUTOMATION_PPARGS = 	\
 			-DBROWSER_PATH=$(browser_path) \
 			-DXPC_BIN_PATH=\"$(LIBXUL_DIST)/bin\" \
 			-DBIN_SUFFIX=\"$(BIN_SUFFIX)\" \
 			-DPROFILE_DIR=\"$(_PROFILE_DIR)\" \
 			-DCERTS_SRC_DIR=\"$(_CERTS_SRC_DIR)\" \
-			-DSYMBOLS_PATH=\"$(_SYMBOLS_PATH)\" \
 			-DPERL="\"$(PERL)\"" \
 			$(NULL)
 
 ifeq ($(OS_ARCH),Darwin)
 AUTOMATION_PPARGS += -DIS_MAC=1
 else
 AUTOMATION_PPARGS += -DIS_MAC=0
 endif
@@ -66,11 +63,19 @@ AUTOMATION_PPARGS += -DIS_TEST_BUILD=0
 endif
 
 ifeq ($(MOZ_DEBUG), 1)
 AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=1
 else
 AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=0
 endif
 
+ifdef MOZ_CRASHREPORTER
+AUTOMATION_PPARGS += -DCRASHREPORTER=1
+else
+AUTOMATION_PPARGS += -DCRASHREPORTER=0
+endif
+
 automation.py: $(MOZILLA_DIR)/build/automation.py.in $(MOZILLA_DIR)/build/automation-build.mk
 	$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \
 	$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
+
+GARBAGE += automation.py
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -33,114 +33,48 @@
 # 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 *****
 
 import codecs
-from datetime import datetime
+from datetime import datetime, timedelta
 import itertools
 import logging
 import os
 import re
+import select
 import shutil
 import signal
 import subprocess
 import sys
 import threading
-
-"""
-Runs the browser from a script, and provides useful utilities
-for setting up the browser environment.
-"""
-
-SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
-sys.path.insert(0, SCRIPT_DIR);
-from automationutils import checkForCrashes
-
-__all__ = [
-           "UNIXISH",
-           "IS_WIN32",
-           "IS_MAC",
-           "log",
-           "runApp",
-           "Process",
-           "initializeProfile",
-           "DIST_BIN",
-           "DEFAULT_APP",
-           "CERTS_SRC_DIR",
-           "environment",
-           "IS_TEST_BUILD",
-           "IS_DEBUG_BUILD",
-           "SYMBOLS_PATH",
-          ]
-
-# These are generated in mozilla/build/Makefile.in
-#expand DIST_BIN = __XPC_BIN_PATH__
-#expand IS_WIN32 = len("__WIN32__") != 0
-#expand IS_MAC = __IS_MAC__ != 0
-#expand IS_LINUX = __IS_LINUX__ != 0
-#ifdef IS_CYGWIN
-#expand IS_CYGWIN = __IS_CYGWIN__ == 1
-#else
-IS_CYGWIN = False
-#endif
-#expand IS_CAMINO = __IS_CAMINO__ != 0
-#expand BIN_SUFFIX = __BIN_SUFFIX__
-#expand PERL = __PERL__
-
-UNIXISH = not IS_WIN32 and not IS_MAC
-
-#expand DEFAULT_APP = "./" + __BROWSER_PATH__
-#expand CERTS_SRC_DIR = __CERTS_SRC_DIR__
-#expand IS_TEST_BUILD = __IS_TEST_BUILD__
-#expand IS_DEBUG_BUILD = __IS_DEBUG_BUILD__
-#expand SYMBOLS_PATH = __SYMBOLS_PATH__
-
-###########
-# LOGGING #
-###########
-
-# We use the logging system here primarily because it'll handle multiple
-# threads, which is needed to process the output of the server and application
-# processes simultaneously.
-log = logging.getLogger()
-handler = logging.StreamHandler(sys.stdout)
-log.setLevel(logging.INFO)
-log.addHandler(handler)
+import tempfile
 
 
-#################
-# SUBPROCESSING #
-#################
-
-class Process(subprocess.Popen):
-  """
-  Represents our view of a subprocess.
-  It adds a kill() method which allows it to be stopped explicitly.
-  """
+#expand _DIST_BIN = __XPC_BIN_PATH__
+#expand _IS_WIN32 = len("__WIN32__") != 0
+#expand _IS_MAC = __IS_MAC__ != 0
+#expand _IS_LINUX = __IS_LINUX__ != 0
+#ifdef IS_CYGWIN
+#expand _IS_CYGWIN = __IS_CYGWIN__ == 1
+#else
+_IS_CYGWIN = False
+#endif
+#expand _IS_CAMINO = __IS_CAMINO__ != 0
+#expand _BIN_SUFFIX = __BIN_SUFFIX__
+#expand _PERL = __PERL__
 
-  def kill(self):
-    if IS_WIN32:
-      import platform
-      pid = "%i" % self.pid
-      if platform.release() == "2000":
-        # Windows 2000 needs 'kill.exe' from the 'Windows 2000 Resource Kit tools'. (See bug 475455.)
-        try:
-          subprocess.Popen(["kill", "-f", pid]).wait()
-        except:
-          log.info("TEST-UNEXPECTED-FAIL | automation.py | Missing 'kill' utility to kill process with pid=%s. Kill it manually!", pid)
-      else:
-        # Windows XP and later.
-        subprocess.Popen(["taskkill", "/F", "/PID", pid]).wait()
-    else:
-      os.kill(self.pid, signal.SIGKILL)
-
+#expand _DEFAULT_APP = "./" + __BROWSER_PATH__
+#expand _CERTS_SRC_DIR = __CERTS_SRC_DIR__
+#expand _IS_TEST_BUILD = __IS_TEST_BUILD__
+#expand _IS_DEBUG_BUILD = __IS_DEBUG_BUILD__
+#expand _CRASHREPORTER = __CRASHREPORTER__ == 1
 
 #################
 # PROFILE SETUP #
 #################
 
 class SyntaxError(Exception):
   "Signifies a syntax error on a particular line in server-locations.txt."
 
@@ -161,104 +95,187 @@ class Location:
   "Represents a location line in server-locations.txt."
 
   def __init__(self, scheme, host, port, options):
     self.scheme = scheme
     self.host = host
     self.port = port
     self.options = options
 
-
-def readLocations(locationsPath = "server-locations.txt"):
+class Automation(object):
   """
-  Reads the locations at which the Mochitest HTTP server is available from
-  server-locations.txt.
+  Runs the browser from a script, and provides useful utilities
+  for setting up the browser environment.
   """
 
-  locationFile = codecs.open(locationsPath, "r", "UTF-8")
+  DIST_BIN = _DIST_BIN
+  IS_WIN32 = _IS_WIN32
+  IS_MAC = _IS_MAC
+  IS_LINUX = _IS_LINUX
+  IS_CYGWIN = _IS_CYGWIN
+  IS_CAMINO = _IS_CAMINO
+  BIN_SUFFIX = _BIN_SUFFIX
+  PERL = _PERL
+
+  UNIXISH = not IS_WIN32 and not IS_MAC
+
+  DEFAULT_APP = _DEFAULT_APP
+  CERTS_SRC_DIR = _CERTS_SRC_DIR
+  IS_TEST_BUILD = _IS_TEST_BUILD
+  IS_DEBUG_BUILD = _IS_DEBUG_BUILD
+  CRASHREPORTER = _CRASHREPORTER
+
+  SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
+  sys.path.insert(0, SCRIPT_DIR)
+  automationutils = __import__('automationutils')
+
+  # timeout, in seconds
+  DEFAULT_TIMEOUT = 60.0
+
+  log = logging.getLogger()
+
+  def __init__(self):
+
+    # We use the logging system here primarily because it'll handle multiple
+    # threads, which is needed to process the output of the server and application
+    # processes simultaneously.
+    handler = logging.StreamHandler(sys.stdout)
+    self.log.setLevel(logging.INFO)
+    self.log.addHandler(handler)
 
-  # Perhaps more detail than necessary, but it's the easiest way to make sure
-  # we get exactly the format we want.  See server-locations.txt for the exact
-  # format guaranteed here.
-  lineRe = re.compile(r"^(?P<scheme>[a-z][-a-z0-9+.]*)"
+  @property
+  def __all__(self):
+    return [
+           "UNIXISH",
+           "IS_WIN32",
+           "IS_MAC",
+           "log",
+           "runApp",
+           "Process",
+           "addCommonOptions",
+           "initializeProfile",
+           "DIST_BIN",
+           "DEFAULT_APP",
+           "CERTS_SRC_DIR",
+           "environment",
+           "IS_TEST_BUILD",
+           "IS_DEBUG_BUILD",
+           "DEFAULT_TIMEOUT",
+          ]
+
+  class Process(subprocess.Popen):
+    """
+    Represents our view of a subprocess.
+    It adds a kill() method which allows it to be stopped explicitly.
+    """
+
+    def kill(self):
+      if Automation().IS_WIN32:
+        import platform
+        pid = "%i" % self.pid
+        if platform.release() == "2000":
+          # Windows 2000 needs 'kill.exe' from the 
+          #'Windows 2000 Resource Kit tools'. (See bug 475455.)
+          try:
+            subprocess.Popen(["kill", "-f", pid]).wait()
+          except:
+            self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Missing 'kill' utility to kill process with pid=%s. Kill it manually!", pid)
+        else:
+          # Windows XP and later.
+          subprocess.Popen(["taskkill", "/F", "/PID", pid]).wait()
+      else:
+        os.kill(self.pid, signal.SIGKILL)
+
+  def readLocations(self, locationsPath = "server-locations.txt"):
+    """
+    Reads the locations at which the Mochitest HTTP server is available from
+    server-locations.txt.
+    """
+
+    locationFile = codecs.open(locationsPath, "r", "UTF-8")
+
+    # Perhaps more detail than necessary, but it's the easiest way to make sure
+    # we get exactly the format we want.  See server-locations.txt for the exact
+    # format guaranteed here.
+    lineRe = re.compile(r"^(?P<scheme>[a-z][-a-z0-9+.]*)"
                       r"://"
                       r"(?P<host>"
                         r"\d+\.\d+\.\d+\.\d+"
                         r"|"
                         r"(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*"
                         r"[a-z](?:[-a-z0-9]*[a-z0-9])?"
                       r")"
                       r":"
                       r"(?P<port>\d+)"
                       r"(?:"
                       r"\s+"
                       r"(?P<options>\S+(?:,\S+)*)"
                       r")?$")
-  locations = []
-  lineno = 0
-  seenPrimary = False
-  for line in locationFile:
-    lineno += 1
-    if line.startswith("#") or line == "\n":
-      continue
+    locations = []
+    lineno = 0
+    seenPrimary = False
+    for line in locationFile:
+      lineno += 1
+      if line.startswith("#") or line == "\n":
+        continue
       
-    match = lineRe.match(line)
-    if not match:
-      raise SyntaxError(lineno)
+      match = lineRe.match(line)
+      if not match:
+        raise SyntaxError(lineno)
 
-    options = match.group("options")
-    if options:
-      options = options.split(",")
-      if "primary" in options:
-        if seenPrimary:
-          raise SyntaxError(lineno, "multiple primary locations")
-        seenPrimary = True
-    else:
-      options = []
+      options = match.group("options")
+      if options:
+        options = options.split(",")
+        if "primary" in options:
+          if seenPrimary:
+            raise SyntaxError(lineno, "multiple primary locations")
+          seenPrimary = True
+      else:
+        options = []
 
-    locations.append(Location(match.group("scheme"), match.group("host"),
-                              match.group("port"), options))
+      locations.append(Location(match.group("scheme"), match.group("host"),
+                                match.group("port"), options))
 
-  if not seenPrimary:
-    raise SyntaxError(lineno + 1, "missing primary location")
+    if not seenPrimary:
+      raise SyntaxError(lineno + 1, "missing primary location")
 
-  return locations
+    return locations
 
 
-def initializeProfile(profileDir):
-  "Sets up the standard testing profile."
+  def initializeProfile(self, profileDir, extraPrefs = []):
+    "Sets up the standard testing profile."
 
-  # Start with a clean slate.
-  shutil.rmtree(profileDir, True)
-  os.mkdir(profileDir)
+    # Start with a clean slate.
+    shutil.rmtree(profileDir, True)
+    os.mkdir(profileDir)
 
-  prefs = []
+    prefs = []
 
-  part = """\
+    part = """\
 user_pref("browser.dom.window.dump.enabled", true);
 user_pref("dom.allow_scripts_to_close_windows", true);
 user_pref("dom.disable_open_during_load", false);
 user_pref("dom.max_script_run_time", 0); // no slow script dialogs
 user_pref("dom.max_chrome_script_run_time", 0);
+user_pref("dom.popup_maximum", -1);
 user_pref("signed.applets.codebase_principal_support", true);
 user_pref("security.warn_submit_insecure", false);
 user_pref("browser.shell.checkDefaultBrowser", false);
 user_pref("shell.checkDefaultClient", false);
 user_pref("browser.warnOnQuit", false);
 user_pref("accessibility.typeaheadfind.autostart", false);
 user_pref("javascript.options.showInConsole", true);
 user_pref("layout.debug.enable_data_xbl", true);
 user_pref("browser.EULA.override", true);
 user_pref("javascript.options.jit.content", true);
 user_pref("gfx.color_management.force_srgb", true);
 user_pref("network.manage-offline-status", false);
 user_pref("test.mousescroll", true);
 user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
 user_pref("network.http.prompt-temp-redirect", false);
-user_pref("svg.smil.enabled", true); // Needed for SMIL mochitests until bug 482402 lands
 user_pref("media.cache_size", 100);
 user_pref("security.warn_viewing_mixed", false);
 
 user_pref("geo.wifi.uri", "http://localhost:8888/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs");
 user_pref("geo.wifi.testing", true);
 
 user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
 
@@ -266,40 +283,40 @@ user_pref("camino.warn_when_closing", fa
 user_pref("urlclassifier.updateinterval", 172800);
 // Point the url-classifier to the local testing server for fast failures
 user_pref("browser.safebrowsing.provider.0.gethashURL", "http://localhost:8888/safebrowsing-dummy/gethash");
 user_pref("browser.safebrowsing.provider.0.keyURL", "http://localhost:8888/safebrowsing-dummy/newkey");
 user_pref("browser.safebrowsing.provider.0.lookupURL", "http://localhost:8888/safebrowsing-dummy/lookup");
 user_pref("browser.safebrowsing.provider.0.updateURL", "http://localhost:8888/safebrowsing-dummy/update");
 """
   
-  prefs.append(part)
+    prefs.append(part)
 
-  locations = readLocations()
+    locations = self.readLocations()
 
-  # Grant God-power to all the privileged servers on which tests run.
-  privileged = filter(lambda loc: "privileged" in loc.options, locations)
-  for (i, l) in itertools.izip(itertools.count(1), privileged):
-    part = """
+    # Grant God-power to all the privileged servers on which tests run.
+    privileged = filter(lambda loc: "privileged" in loc.options, locations)
+    for (i, l) in itertools.izip(itertools.count(1), privileged):
+      part = """
 user_pref("capability.principal.codebase.p%(i)d.granted",
           "UniversalXPConnect UniversalBrowserRead UniversalBrowserWrite \
            UniversalPreferencesRead UniversalPreferencesWrite \
            UniversalFileRead");
 user_pref("capability.principal.codebase.p%(i)d.id", "%(origin)s");
 user_pref("capability.principal.codebase.p%(i)d.subjectName", "");
 """  % { "i": i,
          "origin": (l.scheme + "://" + l.host + ":" + l.port) }
-    prefs.append(part)
+      prefs.append(part)
 
-  # We need to proxy every server but the primary one.
-  origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
-             for l in filter(lambda l: "primary" not in l.options, locations)]
-  origins = ", ".join(origins)
+    # We need to proxy every server but the primary one.
+    origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
+              for l in filter(lambda l: "primary" not in l.options, locations)]
+    origins = ", ".join(origins)
 
-  pacURL = """data:text/plain,
+    pacURL = """data:text/plain,
 function FindProxyForURL(url, host)
 {
   var origins = [%(origins)s];
   var regex = new RegExp('^([a-z][-a-z0-9+.]*)' +
                          '://' +
                          '(?:[^/@]*@)?' +
                          '(.*?)' +
                          '(?::(\\\\\\\\d+))?/');
@@ -318,213 +335,416 @@ function FindProxyForURL(url, host)
   if (origins.indexOf(origin) < 0)
     return 'DIRECT';
   if (isHttp)
     return 'PROXY 127.0.0.1:8888';
   if (isHttps)
     return 'PROXY 127.0.0.1:4443';
   return 'DIRECT';
 }""" % { "origins": origins }
-  pacURL = "".join(pacURL.splitlines())
+    pacURL = "".join(pacURL.splitlines())
 
-  part = """
+    part = """
 user_pref("network.proxy.type", 2);
 user_pref("network.proxy.autoconfig_url", "%(pacURL)s");
 
 user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless to others
 """ % {"pacURL": pacURL}
-  prefs.append(part)
+    prefs.append(part)
+
+    for v in extraPrefs:
+      thispref = v.split("=")
+      if len(thispref) < 2:
+        print "Error: syntax error in --setpref=" + v
+        sys.exit(1)
+      part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
+      prefs.append(part)
+
+    # write the preferences
+    prefsFile = open(profileDir + "/" + "user.js", "a")
+    prefsFile.write("".join(prefs))
+    prefsFile.close()
 
-  # write the preferences
-  prefsFile = open(profileDir + "/" + "user.js", "a")
-  prefsFile.write("".join(prefs))
-  prefsFile.close()
+  def addCommonOptions(self, parser):
+    "Adds command-line options which are common to mochitest and reftest."
+
+    parser.add_option("--setpref",
+                      action = "append", type = "string",
+                      default = [],
+                      dest = "extraPrefs", metavar = "PREF=VALUE",
+                      help = "defines an extra user preference")  
 
-def fillCertificateDB(profileDir, certPath, utilityPath, xrePath):
-  pwfilePath = os.path.join(profileDir, ".crtdbpw")
+  def fillCertificateDB(self, profileDir, certPath, utilityPath, xrePath):
+    pwfilePath = os.path.join(profileDir, ".crtdbpw")
+  
+    pwfile = open(pwfilePath, "w")
+    pwfile.write("\n")
+    pwfile.close()
+
+    # Create head of the ssltunnel configuration file
+    sslTunnelConfigPath = os.path.join(profileDir, "ssltunnel.cfg")
+    sslTunnelConfig = open(sslTunnelConfigPath, "w")
   
-  pwfile = open(pwfilePath, "w")
-  pwfile.write("\n")
-  pwfile.close()
+    sslTunnelConfig.write("httpproxy:1\n")
+    sslTunnelConfig.write("certdbdir:%s\n" % certPath)
+    sslTunnelConfig.write("forward:127.0.0.1:8888\n")
+    sslTunnelConfig.write("listen:*:4443:pgo server certificate\n")
+
+    # Configure automatic certificate and bind custom certificates, client authentication
+    locations = self.readLocations()
+    locations.pop(0)
+    for loc in locations:
+      if loc.scheme == "https" and "nocert" not in loc.options:
+        customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
+        clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
+        for option in loc.options:
+          match = customCertRE.match(option)
+          if match:
+            customcert = match.group("nickname");
+            sslTunnelConfig.write("listen:%s:%s:4443:%s\n" %
+                      (loc.host, loc.port, customcert))
+
+          match = clientAuthRE.match(option)
+          if match:
+            clientauth = match.group("clientauth");
+            sslTunnelConfig.write("clientauth:%s:%s:4443:%s\n" %
+                      (loc.host, loc.port, clientauth))
+
+    sslTunnelConfig.close()
+
+    # Pre-create the certification database for the profile
+    env = self.environment(xrePath = xrePath)
+    certutil = os.path.join(utilityPath, "certutil" + self.BIN_SUFFIX)
+    pk12util = os.path.join(utilityPath, "pk12util" + self.BIN_SUFFIX)
+
+    status = self.Process([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env = env).wait()
+    if status != 0:
+      return status
 
-  # Create head of the ssltunnel configuration file
-  sslTunnelConfigPath = os.path.join(profileDir, "ssltunnel.cfg")
-  sslTunnelConfig = open(sslTunnelConfigPath, "w")
-  
-  sslTunnelConfig.write("httpproxy:1\n")
-  sslTunnelConfig.write("certdbdir:%s\n" % certPath)
-  sslTunnelConfig.write("forward:127.0.0.1:8888\n")
-  sslTunnelConfig.write("listen:*:4443:pgo server certificate\n")
+    # Walk the cert directory and add custom CAs and client certs
+    files = os.listdir(certPath)
+    for item in files:
+      root, ext = os.path.splitext(item)
+      if ext == ".ca":
+        trustBits = "CT,,"
+        if root.endswith("-object"):
+          trustBits = "CT,,CT"
+        self.Process([certutil, "-A", "-i", os.path.join(certPath, item),
+                    "-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
+                    env = env).wait()
+      if ext == ".client":
+        self.Process([pk12util, "-i", os.path.join(certPath, item), "-w",
+                    pwfilePath, "-d", profileDir], 
+                    env = env).wait()
+
+    os.unlink(pwfilePath)
+    return 0
+
+  def environment(self, env = None, xrePath = None, crashreporter = True):
+    if xrePath == None:
+      xrePath = self.DIST_BIN
+    if env == None:
+      env = dict(os.environ)
+
+    ldLibraryPath = os.path.abspath(os.path.join(self.SCRIPT_DIR, xrePath))
+    if self.UNIXISH or self.IS_MAC:
+      envVar = "LD_LIBRARY_PATH"
+      if self.IS_MAC:
+        envVar = "DYLD_LIBRARY_PATH"
+      else: # unixish
+        env['MOZILLA_FIVE_HOME'] = xrePath
+      if envVar in env:
+        ldLibraryPath = ldLibraryPath + ":" + env[envVar]
+      env[envVar] = ldLibraryPath
+    elif self.IS_WIN32:
+      env["PATH"] = env["PATH"] + ";" + ldLibraryPath
+
+    if crashreporter:
+      env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
+      env['MOZ_CRASHREPORTER'] = '1'
+    else:
+      env['MOZ_CRASHREPORTER_DISABLE'] = '1'
+
+    env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
+    env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
+    return env
+
+  if IS_WIN32:
+    ctypes = __import__('ctypes')
+    wintypes = __import__('ctypes.wintypes')
+    time = __import__('time')
+    msvcrt = __import__('msvcrt')
+    PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe
+    GetLastError = ctypes.windll.kernel32.GetLastError
 
-  # Configure automatic certificate and bind custom certificates, client authentication
-  locations = readLocations()
-  locations.pop(0)
-  for loc in locations:
-    if loc.scheme == "https" and "nocert" not in loc.options:
-      customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
-      clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
-      for option in loc.options:
-        match = customCertRE.match(option)
-        if match:
-          customcert = match.group("nickname");
-          sslTunnelConfig.write("listen:%s:%s:4443:%s\n" %
-              (loc.host, loc.port, customcert))
+    def readWithTimeout(self, f, timeout):
+      """Try to read a line of output from the file object |f|.
+      |f| must be a  pipe, like the |stdout| member of a subprocess.Popen
+      object created with stdout=PIPE. If no output
+      is received within |timeout| seconds, return a blank line.
+      Returns a tuple (line, did_timeout), where |did_timeout| is True
+      if the read timed out, and False otherwise."""
+      if timeout is None:
+        # shortcut to allow callers to pass in "None" for no timeout.
+        return (f.readline(), False)
+      x = self.msvcrt.get_osfhandle(f.fileno())
+      l = self.ctypes.c_long()
+      done = self.time.time() + timeout
+      while self.time.time() < done:
+        if self.PeekNamedPipe(x, None, 0, None, self.ctypes.byref(l), None) == 0:
+          err = self.GetLastError()
+          if err == 38 or err == 109: # ERROR_HANDLE_EOF || ERROR_BROKEN_PIPE
+            return ('', False)
+          else:
+            log.error("readWithTimeout got error: %d", err)
+        if l.value > 0:
+          # we're assuming that the output is line-buffered,
+          # which is not unreasonable
+          return (f.readline(), False)
+        self.time.sleep(0.01)
+      return ('', True)
+
+    def isPidAlive(self, pid):
+      STILL_ACTIVE = 259
+      PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
+      pHandle = self.ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid)
+      if not pHandle:
+        return False
+      pExitCode = ctypes.wintypes.DWORD()
+      self.ctypes.windll.kernel32.GetExitCodeProcess(pHandle, self.ctypes.byref(pExitCode))
+      self.ctypes.windll.kernel32.CloseHandle(pHandle)
+      if (pExitCode.value == STILL_ACTIVE):
+        return True
+      else:
+        return False
+
+    def killPid(self, pid):
+      PROCESS_TERMINATE = 0x0001
+      pHandle = self.ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, 0, pid)
+      if not pHandle:
+        return
+      success = self.ctypes.windll.kernel32.TerminateProcess(pHandle, 1)
+      self.ctypes.windll.kernel32.CloseHandle(pHandle)
+
+  else:
+    errno = __import__('errno')
+
+    def readWithTimeout(self, f, timeout):
+      """Try to read a line of output from the file object |f|. If no output
+      is received within |timeout| seconds, return a blank line.
+      Returns a tuple (line, did_timeout), where |did_timeout| is True
+      if the read timed out, and False otherwise."""
+      (r, w, e) = select.select([f], [], [], timeout)
+      if len(r) == 0:
+        return ('', True)
+      return (f.readline(), False)
+
+    def isPidAlive(self, pid):
+      try:
+        # kill(pid, 0) checks for a valid PID without actually sending a signal
+        # The method throws OSError if the PID is invalid, which we catch below.
+        os.kill(pid, 0)
+
+        # Wait on it to see if it's a zombie. This can throw OSError.ECHILD if
+        # the process terminates before we get to this point.
+        wpid, wstatus = os.waitpid(pid, os.WNOHANG)
+        if wpid == 0:
+          return True
 
-        match = clientAuthRE.match(option)
-        if match:
-          clientauth = match.group("clientauth");
-          sslTunnelConfig.write("clientauth:%s:%s:4443:%s\n" %
-              (loc.host, loc.port, clientauth))
+        return False
+      except OSError, err:
+        # Catch the errors we might expect from os.kill/os.waitpid, 
+        # and re-raise any others
+        if err.errno == self.errno.ESRCH or err.errno == self.errno.ECHILD:
+          return False
+        raise
+
+    def killPid(self, pid):
+      os.kill(pid, signal.SIGKILL)
 
-  sslTunnelConfig.close()
+  def triggerBreakpad(self, proc, utilityPath):
+    """Attempt to kill this process in a way that triggers Breakpad crash
+    reporting, if we know how for this platform. Otherwise just .kill() it."""
+    if self.CRASHREPORTER:
+      if self.UNIXISH:
+        # ABRT will get picked up by Breakpad's signal handler
+        os.kill(proc.pid, signal.SIGABRT)
+        return
+      elif self.IS_WIN32:
+        # We should have a "crashinject" program in our utility path
+        crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
+        if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(proc.pid)]).wait() == 0:
+          return
+    #TODO: kill the process such that it triggers Breakpad on OS X (bug 525296)
+    self.log.info("Can't trigger Breakpad, just killing process")
+    proc.kill()
 
-  # Pre-create the certification database for the profile
-  env = environment(xrePath = xrePath)
-  certutil = os.path.join(utilityPath, "certutil" + BIN_SUFFIX)
-  pk12util = os.path.join(utilityPath, "pk12util" + BIN_SUFFIX)
+  def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime):
+    """ Look for timeout or crashes and return the status after the process terminates """
+    stackFixerProcess = None
+    stackFixerModule = None
+    didTimeout = False
+    if proc.stdout is None:
+      self.log.info("TEST-INFO: Not logging stdout or stderr due to debugger connection")
+    else:
+      logsource = proc.stdout
+      if self.IS_DEBUG_BUILD and self.IS_LINUX:
+        # Run logsource through fix-linux-stack.pl
+        stackFixerProcess = self.Process([self.PERL, os.path.join(utilityPath, "fix-linux-stack.pl")],
+                                         stdin=logsource,
+                                         stdout=subprocess.PIPE)
+        logsource = stackFixerProcess.stdout
+
+      if self.IS_DEBUG_BUILD and self.IS_MAC:
+        # Import fix_macosx_stack.py from utilityPath
+        sys.path.insert(0, utilityPath)
+        import fix_macosx_stack as stackFixerModule
+        del sys.path[0]
 
-  status = Process([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env = env).wait()
-  if status != 0:
+      (line, didTimeout) = self.readWithTimeout(logsource, timeout)
+      hitMaxTime = False
+      while line != "" and not didTimeout:
+        if stackFixerModule:
+          line = stackFixerModule.fixSymbols(line)
+        self.log.info(line.rstrip())
+        (line, didTimeout) = self.readWithTimeout(logsource, timeout)
+        if not hitMaxTime and maxTime and datetime.now() - startTime > timedelta(seconds = maxTime):
+          # Kill the application, but continue reading from stack fixer so as not to deadlock on stackFixerProcess.wait().
+          hitMaxTime = True
+          self.log.info("TEST-UNEXPECTED-FAIL | automation.py | application ran for longer than allowed maximum time of %d seconds", int(maxTime))
+          self.triggerBreakpad(proc, utilityPath)
+      if didTimeout:
+        self.log.info("TEST-UNEXPECTED-FAIL | automation.py | application timed out after %d seconds with no output", int(timeout))
+        self.triggerBreakpad(proc, utilityPath)
+
+    status = proc.wait()
+    if status != 0 and not didTimeout and not hitMaxTime:
+      self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Exited with code %d during test run", status)
+    if stackFixerProcess is not None:
+      fixerStatus = stackFixerProcess.wait()
+      if fixerStatus != 0 and not didTimeout and not hitMaxTime:
+        self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Stack fixer process exited with code %d during test run", fixerStatus)
     return status
 
-  # Walk the cert directory and add custom CAs and client certs
-  files = os.listdir(certPath)
-  for item in files:
-    root, ext = os.path.splitext(item)
-    if ext == ".ca":
-      trustBits = "CT,,"
-      if root.endswith("-object"):
-        trustBits = "CT,,CT"
-      Process([certutil, "-A", "-i", os.path.join(certPath, item),
-        "-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
-        env = env).wait()
-    if ext == ".client":
-      Process([pk12util, "-i", os.path.join(certPath, item), "-w",
-        pwfilePath, "-d", profileDir], 
-        env = env).wait()
+  def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
+    """ build the application command line """
+
+    cmd = app
+    if self.IS_MAC and not self.IS_CAMINO and not cmd.endswith("-bin"):
+      cmd += "-bin"
+    cmd = os.path.abspath(cmd)
+
+    args = []
 
-  os.unlink(pwfilePath)
-  return 0
+    if debuggerInfo:
+      args.extend(debuggerInfo["args"])
+      args.append(cmd)
+      cmd = os.path.abspath(debuggerInfo["path"])
 
-def environment(env = None, xrePath = DIST_BIN, crashreporter = True):
-  if env == None:
-    env = dict(os.environ)
+    if self.IS_MAC:
+      args.append("-foreground")
+
+    if self.IS_CYGWIN:
+      profileDirectory = commands.getoutput("cygpath -w \"" + profileDir + "/\"")
+    else:
+      profileDirectory = profileDir + "/"
 
-  ldLibraryPath = os.path.abspath(os.path.join(SCRIPT_DIR, xrePath))
-  if UNIXISH or IS_MAC:
-    envVar = "LD_LIBRARY_PATH"
-    if IS_MAC:
-      envVar = "DYLD_LIBRARY_PATH"
-    if envVar in env:
-      ldLibraryPath = ldLibraryPath + ":" + env[envVar]
-    env[envVar] = ldLibraryPath
-  elif IS_WIN32:
-    env["PATH"] = env["PATH"] + ";" + ldLibraryPath
+    args.extend(("-no-remote", "-profile", profileDirectory))
+    if testURL is not None:
+      if self.IS_CAMINO:
+        args.extend(("-url", testURL))
+      else:
+        args.append((testURL))
+    args.extend(extraArgs)
+    return cmd, args
 
-  if crashreporter:
-    env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
-    env['MOZ_CRASHREPORTER'] = '1'
-
-  return env
-
-
-###############
-# RUN THE APP #
-###############
-
-def runApp(testURL, env, app, profileDir, extraArgs,
-           runSSLTunnel = False, utilityPath = DIST_BIN,
-           xrePath = DIST_BIN, certPath = CERTS_SRC_DIR,
-           debuggerInfo = None, symbolsPath = SYMBOLS_PATH):
-  "Run the app, log the duration it took to execute, return the status code."
+  def checkForZombies(self, processLog):
+    """ Look for hung processes """
+    if not os.path.exists(processLog):
+      self.log.info('INFO | automation.py | PID log not found: %s', processLog)
+    else:
+      self.log.info('INFO | automation.py | Reading PID log: %s', processLog)
+      processList = []
+      pidRE = re.compile(r'launched child process (\d+)$')
+      processLogFD = open(processLog)
+      for line in processLogFD:
+        self.log.info(line.rstrip())
+        m = pidRE.search(line)
+        if m:
+          processList.append(int(m.group(1)))
+      processLogFD.close()
 
-  if IS_TEST_BUILD and runSSLTunnel:
-    # create certificate database for the profile
-    certificateStatus = fillCertificateDB(profileDir, certPath, utilityPath, xrePath)
-    if certificateStatus != 0:
-      log.info("TEST-UNEXPECTED FAIL | automation.py | Certificate integration failed")
-      return certificateStatus
-
-    # start ssltunnel to provide https:// URLs capability
-    ssltunnel = os.path.join(utilityPath, "ssltunnel" + BIN_SUFFIX)
-    ssltunnelProcess = Process([ssltunnel, os.path.join(profileDir, "ssltunnel.cfg")], env = environment(xrePath = xrePath))
-    log.info("INFO | automation.py | SSL tunnel pid: %d", ssltunnelProcess.pid)
+      for processPID in processList:
+        self.log.info("INFO | automation.py | Checking for orphan process with PID: %d", processPID)
+        if self.isPidAlive(processPID):
+          self.log.info("TEST-UNEXPECTED-FAIL | automation.py | child process %d still alive after shutdown", processPID)
+          self.killPid(processPID)
 
-  # now run with the profile we created
-  cmd = app
-  if IS_MAC and not IS_CAMINO and not cmd.endswith("-bin"):
-    cmd += "-bin"
-  cmd = os.path.abspath(cmd)
+  def runApp(self, testURL, env, app, profileDir, extraArgs,
+             runSSLTunnel = False, utilityPath = None,
+             xrePath = None, certPath = None,
+             debuggerInfo = None, symbolsPath = None,
+             timeout = -1, maxTime = None):
+    """
+    Run the app, log the duration it took to execute, return the status code.
+    Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
+    """
 
-  args = []
-
-  if debuggerInfo:
-    args.extend(debuggerInfo["args"])
-    args.append(cmd)
-    cmd = os.path.abspath(debuggerInfo["path"])
+    if utilityPath == None:
+      utilityPath = self.DIST_BIN
+    if xrePath == None:
+      xrePath = self.DIST_BIN
+    if certPath == None:
+      certPath = self.CERTS_SRC_DIR
+    if timeout == -1:
+      timeout = self.DEFAULT_TIMEOUT
 
-  if IS_MAC:
-    args.append("-foreground")
+    # copy env so we don't munge the caller's environment
+    env = dict(env);
+    env["NO_EM_RESTART"] = "1"
+    tmpfd, processLog = tempfile.mkstemp(suffix='pidlog')
+    os.close(tmpfd)
+    env["MOZ_PROCESS_LOG"] = processLog
+
+    if self.IS_TEST_BUILD and runSSLTunnel:
+      # create certificate database for the profile
+      certificateStatus = self.fillCertificateDB(profileDir, certPath, utilityPath, xrePath)
+      if certificateStatus != 0:
+        self.log.info("TEST-UNEXPECTED FAIL | automation.py | Certificate integration failed")
+        return certificateStatus
 
-  if IS_CYGWIN:
-    profileDirectory = commands.getoutput("cygpath -w \"" + profileDir + "/\"")
-  else:
-    profileDirectory = profileDir + "/"
+      # start ssltunnel to provide https:// URLs capability
+      ssltunnel = os.path.join(utilityPath, "ssltunnel" + self.BIN_SUFFIX)
+      ssltunnelProcess = self.Process([ssltunnel, 
+                               os.path.join(profileDir, "ssltunnel.cfg")], 
+                               env = self.environment(xrePath = xrePath))
+      self.log.info("INFO | automation.py | SSL tunnel pid: %d", ssltunnelProcess.pid)
 
-  args.extend(("-no-remote", "-profile", profileDirectory))
-  if testURL is not None:
-    if IS_CAMINO:
-      args.extend(("-url", testURL))
+    cmd, args = self.buildCommandLine(app, debuggerInfo, profileDir, testURL, extraArgs)
+    startTime = datetime.now()
+
+    # Don't redirect stdout and stderr if an interactive debugger is attached
+    if debuggerInfo and debuggerInfo["interactive"]:
+      outputPipe = None
     else:
-      args.append((testURL))
-  args.extend(extraArgs)
-
-  startTime = datetime.now()
+      outputPipe = subprocess.PIPE
 
-  # Don't redirect stdout and stderr if an interactive debugger is attached
-  if debuggerInfo and debuggerInfo["interactive"]:
-    outputPipe = None
-  else:
-    outputPipe = subprocess.PIPE
-
-  proc = Process([cmd] + args,
-                 env = environment(env, xrePath = xrePath,
+    proc = self.Process([cmd] + args,
+                 env = self.environment(env, xrePath = xrePath,
                                    crashreporter = not debuggerInfo),
                  stdout = outputPipe,
                  stderr = subprocess.STDOUT)
-  log.info("INFO | automation.py | Application pid: %d", proc.pid)
+    self.log.info("INFO | automation.py | Application pid: %d", proc.pid)
 
-  stackFixerProcess = None
-  if outputPipe is None:
-    log.info("TEST-INFO: Not logging stdout or stderr due to debugger connection")
-  else:
-    logsource = proc.stdout
-    if IS_DEBUG_BUILD:
-      stackFixerCommand = None
-      if IS_MAC:
-        stackFixerCommand = "fix-macosx-stack.pl"
-      elif IS_LINUX:
-        stackFixerCommand = "fix-linux-stack.pl"
-      if stackFixerCommand is not None:
-        stackFixerProcess = Process([PERL, os.path.join(utilityPath, stackFixerCommand)], stdin=logsource, stdout=subprocess.PIPE)
-        logsource = stackFixerProcess.stdout
+    status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime)
+    self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))
 
-    line = logsource.readline()
-    while line != "":
-      log.info(line.rstrip())
-      line = logsource.readline()
+    # Do a final check for zombie child processes.
+    self.checkForZombies(processLog)
+    self.automationutils.checkForCrashes(os.path.join(profileDir, "minidumps"), symbolsPath)
 
-  status = proc.wait()
-  if status != 0:
-    log.info("TEST-UNEXPECTED-FAIL | automation.py | Exited with code %d during test run", status)
-  if stackFixerProcess is not None:
-    status = stackFixerProcess.wait()
-    if status != 0:
-      log.info("TEST-UNEXPECTED-FAIL | automation.py | Stack fixer process exited with code %d during test run", status)
-  log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))
+    if os.path.exists(processLog):
+      os.unlink(processLog)
 
-  if checkForCrashes(os.path.join(profileDir, "minidumps"), symbolsPath):
-    status = -1
+    if self.IS_TEST_BUILD and runSSLTunnel:
+      ssltunnelProcess.kill()
 
-  if IS_TEST_BUILD and runSSLTunnel:
-    ssltunnelProcess.kill()
-
-  return status
+    return status
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -31,74 +31,162 @@
 # 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 ***** */
 
-import glob, logging, os, subprocess, sys
+import glob, logging, os, shutil, subprocess, sys
 import re
 
 __all__ = [
   "addCommonOptions",
   "checkForCrashes",
   "dumpLeakLog",
   "processLeakLog",
+  "getDebuggerInfo",
+  "DEBUGGER_INFO",
   ]
 
+# Map of debugging programs to information about them, like default arguments
+# and whether or not they are interactive.
+DEBUGGER_INFO = {
+  # gdb requires that you supply the '--args' flag in order to pass arguments
+  # after the executable name to the executable.
+  "gdb": {
+    "interactive": True,
+    "args": "-q --args"
+  },
+
+  # valgrind doesn't explain much about leaks unless you set the
+  # '--leak-check=full' flag.
+  "valgrind": {
+    "interactive": False,
+    "args": "--leak-check=full"
+  }
+}
+
 log = logging.getLogger()
 
 def addCommonOptions(parser, defaults={}):
   parser.add_option("--xre-path",
                     action = "store", type = "string", dest = "xrePath",
                     # individual scripts will set a sane default
                     default = None,
                     help = "absolute path to directory containing XRE (probably xulrunner)")
   if 'SYMBOLS_PATH' not in defaults:
     defaults['SYMBOLS_PATH'] = None
   parser.add_option("--symbols-path",
                     action = "store", type = "string", dest = "symbolsPath",
                     default = defaults['SYMBOLS_PATH'],
                     help = "absolute path to directory containing breakpad symbols")
+  parser.add_option("--debugger",
+                    action = "store", dest = "debugger",
+                    help = "use the given debugger to launch the application")
+  parser.add_option("--debugger-args",
+                    action = "store", dest = "debuggerArgs",
+                    help = "pass the given args to the debugger _before_ "
+                           "the application on the command line")
+  parser.add_option("--debugger-interactive",
+                    action = "store_true", dest = "debuggerInteractive",
+                    help = "prevents the test harness from redirecting "
+                        "stdout and stderr for interactive debuggers")
 
 def checkForCrashes(dumpDir, symbolsPath, testName=None):
   stackwalkPath = os.environ.get('MINIDUMP_STACKWALK', None)
   # try to get the caller's filename if no test name is given
   if testName is None:
     try:
       testName = os.path.basename(sys._getframe(1).f_code.co_filename)
     except:
       testName = "unknown"
 
   foundCrash = False
   dumps = glob.glob(os.path.join(dumpDir, '*.dmp'))
   for d in dumps:
-    log.info("TEST-UNEXPECTED-FAIL | %s | application crashed (minidump found)", testName)
+    log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName)
     if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath):
       nullfd = open(os.devnull, 'w')
       # eat minidump_stackwalk errors
       subprocess.call([stackwalkPath, d, symbolsPath], stderr=nullfd)
       nullfd.close()
     else:
       if not symbolsPath:
         print "No symbols path given, can't process dump."
       if not stackwalkPath:
         print "MINIDUMP_STACKWALK not set, can't process dump."
       else:
         if not os.path.exists(stackwalkPath):
           print "MINIDUMP_STACKWALK binary not found: %s" % stackwalkPath
-    os.remove(d)
+    dumpSavePath = os.environ.get('MINIDUMP_SAVE_PATH', None)
+    if dumpSavePath:
+      shutil.move(d, dumpSavePath)
+      print "Saved dump as %s" % os.path.join(dumpSavePath,
+                                              os.path.basename(d))
+    else:
+      os.remove(d)
     extra = os.path.splitext(d)[0] + ".extra"
     if os.path.exists(extra):
       os.remove(extra)
     foundCrash = True
 
   return foundCrash
+  
+def getFullPath(directory, path):
+  "Get an absolute path relative to 'directory'."
+  return os.path.normpath(os.path.join(directory, os.path.expanduser(path)))
+
+def searchPath(directory, path):
+  "Go one step beyond getFullPath and try the various folders in PATH"
+  # Try looking in the current working directory first.
+  newpath = getFullPath(directory, path)
+  if os.path.isfile(newpath):
+    return newpath
+
+  # At this point we have to fail if a directory was given (to prevent cases
+  # like './gdb' from matching '/usr/bin/./gdb').
+  if not os.path.dirname(path):
+    for dir in os.environ['PATH'].split(os.pathsep):
+      newpath = os.path.join(dir, path)
+      if os.path.isfile(newpath):
+        return newpath
+  return None
+
+def getDebuggerInfo(directory, debugger, debuggerArgs, debuggerInteractive = False):
+
+  debuggerInfo = None
+
+  if debugger:
+    debuggerPath = searchPath(directory, debugger)
+    if not debuggerPath:
+      print "Error: Path %s doesn't exist." % debugger
+      sys.exit(1)
+
+    debuggerName = os.path.basename(debuggerPath).lower()
+
+    def getDebuggerInfo(type, default):
+      if debuggerName in DEBUGGER_INFO and type in DEBUGGER_INFO[debuggerName]:
+        return DEBUGGER_INFO[debuggerName][type]
+      return default
+
+    debuggerInfo = {
+      "path": debuggerPath,
+      "interactive" : getDebuggerInfo("interactive", False),
+      "args": getDebuggerInfo("args", "").split()
+    }
+
+    if debuggerArgs:
+      debuggerInfo["args"] = debuggerArgs.split()
+    if debuggerInteractive:
+      debuggerInfo["interactive"] = debuggerInteractive
+  
+  return debuggerInfo
+
 
 def dumpLeakLog(leakLogFile, filter = False):
   """Process the leak log, without parsing it.
 
   Use this function if you want the raw log only.
   Use it preferably with the |XPCOM_MEM_LEAK_LOG| environment variable.
   """
 
@@ -113,87 +201,125 @@ def dumpLeakLog(leakLogFile, filter = Fa
   # Only |XPCOM_MEM_LEAK_LOG| reports can be actually filtered out.
   # Only check whether an actual leak was reported.
   if filter and not "0 TOTAL " in leakReport:
     return
 
   # Simply copy the log.
   log.info(leakReport.rstrip("\n"))
 
-def processLeakLog(leakLogFile, leakThreshold = 0):
-  """Process the leak log, parsing it.
-
-  Use this function if you want an additional PASS/FAIL summary.
-  It must be used with the |XPCOM_MEM_BLOAT_LOG| environment variable.
+def processSingleLeakFile(leakLogFileName, PID, processType, leakThreshold):
+  """Process a single leak log, corresponding to the specified
+  process PID and type.
   """
 
-  if not os.path.exists(leakLogFile):
-    log.info("WARNING | automationutils.processLeakLog() | refcount logging is off, so leaks can't be detected!")
-    return
-
   #                  Per-Inst  Leaked      Total  Rem ...
   #   0 TOTAL              17     192  419115886    2 ...
   # 833 nsTimerImpl        60     120      24726    2 ...
   lineRe = re.compile(r"^\s*\d+\s+(?P<name>\S+)\s+"
                       r"(?P<size>-?\d+)\s+(?P<bytesLeaked>-?\d+)\s+"
                       r"-?\d+\s+(?P<numLeaked>-?\d+)")
 
-  leaks = open(leakLogFile, "r")
+  processString = ""
+  if PID and processType:
+    processString = "| %s process %s " % (processType, PID)
+  leaks = open(leakLogFileName, "r")
   for line in leaks:
     matches = lineRe.match(line)
     if (matches and
         int(matches.group("numLeaked")) == 0 and
         matches.group("name") != "TOTAL"):
       continue
     log.info(line.rstrip())
   leaks.close()
 
-  leaks = open(leakLogFile, "r")
+  leaks = open(leakLogFileName, "r")
   seenTotal = False
+  crashedOnPurpose = False
   prefix = "TEST-PASS"
   for line in leaks:
+    if line.find("purposefully crash") > -1:
+      crashedOnPurpose = True
     matches = lineRe.match(line)
     if not matches:
       continue
     name = matches.group("name")
     size = int(matches.group("size"))
     bytesLeaked = int(matches.group("bytesLeaked"))
     numLeaked = int(matches.group("numLeaked"))
     if size < 0 or bytesLeaked < 0 or numLeaked < 0:
-      log.info("TEST-UNEXPECTED-FAIL | automationutils.processLeakLog() | negative leaks caught!")
+      log.info("TEST-UNEXPECTED-FAIL %s| automationutils.processLeakLog() | negative leaks caught!" %
+               processString)
       if name == "TOTAL":
         seenTotal = True
     elif name == "TOTAL":
       seenTotal = True
       # Check for leaks.
       if bytesLeaked < 0 or bytesLeaked > leakThreshold:
         prefix = "TEST-UNEXPECTED-FAIL"
-        leakLog = "TEST-UNEXPECTED-FAIL | automationutils.processLeakLog() | leaked" \
-                  " %d bytes during test execution" % bytesLeaked
+        leakLog = "TEST-UNEXPECTED-FAIL %s| automationutils.processLeakLog() | leaked" \
+                  " %d bytes during test execution" % (processString, bytesLeaked)
       elif bytesLeaked > 0:
-        leakLog = "TEST-PASS | automationutils.processLeakLog() | WARNING leaked" \
-                  " %d bytes during test execution" % bytesLeaked
+        leakLog = "TEST-PASS %s| automationutils.processLeakLog() | WARNING leaked" \
+                  " %d bytes during test execution" % (processString, bytesLeaked)
       else:
-        leakLog = "TEST-PASS | automationutils.processLeakLog() | no leaks detected!"
+        leakLog = "TEST-PASS %s| automationutils.processLeakLog() | no leaks detected!" \
+                  % processString
       # Remind the threshold if it is not 0, which is the default/goal.
       if leakThreshold != 0:
         leakLog += " (threshold set at %d bytes)" % leakThreshold
       # Log the information.
       log.info(leakLog)
     else:
       if numLeaked != 0:
         if numLeaked > 1:
           instance = "instances"
           rest = " each (%s bytes total)" % matches.group("bytesLeaked")
         else:
           instance = "instance"
           rest = ""
-        log.info("%(prefix)s | automationutils.processLeakLog() | leaked %(numLeaked)d %(instance)s of %(name)s "
+        log.info("%(prefix)s %(process)s| automationutils.processLeakLog() | leaked %(numLeaked)d %(instance)s of %(name)s "
                  "with size %(size)s bytes%(rest)s" %
                  { "prefix": prefix,
+                   "process": processString,
                    "numLeaked": numLeaked,
                    "instance": instance,
                    "name": name,
                    "size": matches.group("size"),
                    "rest": rest })
   if not seenTotal:
-    log.info("TEST-UNEXPECTED-FAIL | automationutils.processLeakLog() | missing output line for total leaks!")
+    if crashedOnPurpose:
+      log.info("INFO | automationutils.processLeakLog() | process %s was " \
+               "deliberately crashed and thus has no leak log" % PID)
+    else:
+      log.info("TEST-UNEXPECTED-FAIL %s| automationutils.processLeakLog() | missing output line for total leaks!" %
+             processString)
   leaks.close()
+
+
+def processLeakLog(leakLogFile, leakThreshold = 0):
+  """Process the leak log, including separate leak logs created
+  by child processes.
+
+  Use this function if you want an additional PASS/FAIL summary.
+  It must be used with the |XPCOM_MEM_BLOAT_LOG| environment variable.
+  """
+
+  if not os.path.exists(leakLogFile):
+    log.info("WARNING | automationutils.processLeakLog() | refcount logging is off, so leaks can't be detected!")
+    return
+
+  (leakLogFileDir, leakFileBase) = os.path.split(leakLogFile)
+  pidRegExp = re.compile(r".*?_([a-z]*)_pid(\d*)$")
+  if leakFileBase[-4:] == ".log":
+    leakFileBase = leakFileBase[:-4]
+    pidRegExp = re.compile(r".*?_([a-z]*)_pid(\d*).log$")
+
+  for fileName in os.listdir(leakLogFileDir):
+    if fileName.find(leakFileBase) != -1:
+      thisFile = os.path.join(leakLogFileDir, fileName)
+      processPID = 0
+      processType = None
+      m = pidRegExp.search(fileName)
+      if m:
+        processType = m.group(1)
+        processPID = m.group(2)
+      processSingleLeakFile(thisFile, processPID, processType, leakThreshold)
--- a/build/leaktest.py.in
+++ b/build/leaktest.py.in
@@ -41,49 +41,46 @@
 
 import SimpleHTTPServer
 import SocketServer
 import threading
 import os
 import sys
 import logging
 from getopt import getopt
-import automation
+from automation import Automation
 
 PORT = 8888
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./leakprofile"))
-DIST_BIN = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
 os.chdir(SCRIPT_DIR)
 
 class EasyServer(SocketServer.TCPServer):
     allow_reuse_address = True
 
 if __name__ == '__main__':
+    automation = Automation()
+    DIST_BIN = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
     opts, extraArgs = getopt(sys.argv[1:], 'l:')
     if len(opts) > 0:
         try:
             automation.log.addHandler(logging.FileHandler(opts[0][1], "w"))
         except:
             automation.log.info("Unable to open logfile " + opts[0][1] + \
                                 "ONLY logging to stdout.")
 
     httpd = EasyServer(("", PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
     t = threading.Thread(target=httpd.serve_forever)
     t.setDaemon(True)
     t.start()
 
     automation.initializeProfile(PROFILE_DIRECTORY)
-    browserEnv = dict(os.environ)
+    browserEnv = automation.environment()
 
-    browserEnv["NO_EM_RESTART"] = "1"
     if not "XPCOM_DEBUG_BREAK" in browserEnv:
         browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
-    if automation.UNIXISH:
-        browserEnv["LD_LIBRARY_PATH"] = os.path.join(SCRIPT_DIR, DIST_BIN)
-        browserEnv["MOZILLA_FIVE_HOME"] = os.path.join(SCRIPT_DIR, DIST_BIN)
-        browserEnv["GNOME_DISABLE_CRASH_DIALOG"] = "1"
-
     url = "http://localhost:%d/bloatcycle.html" % PORT
     appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
     status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY,
-                               extraArgs)
+                               # leaktest builds are slow, give up and
+                               # don't use a timeout.
+                               extraArgs, timeout=None)
     sys.exit(status)
--- a/build/pgo/genpgocert.py.in
+++ b/build/pgo/genpgocert.py.in
@@ -31,27 +31,29 @@
 # 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 *****
 
-import automation
+from automation import Automation
 import os
 import re
 import shutil
 import sys
 
 #expand DIST_BIN = __XPC_BIN_PATH__
 #expand BIN_SUFFIX = __BIN_SUFFIX__
 #expand PROFILE_DIR = __PROFILE_DIR__
 #expand CERTS_SRC_DIR = __CERTS_SRC_DIR__
 
+automation = Automation()
+
 dbFiles = [
   re.compile("^cert[0-9]+\.db$"),
   re.compile("^key[0-9]+\.db$"),
   re.compile("^secmod\.db$")
 ]
 
 def unlinkDbFiles(path):
   for root, dirs, files in os.walk(path):
--- a/build/pgo/profileserver.py.in
+++ b/build/pgo/profileserver.py.in
@@ -41,39 +41,36 @@
 import SimpleHTTPServer
 import SocketServer
 import socket
 import threading
 import os
 import sys
 import shutil
 from datetime import datetime
-import automation
+from automation import Automation
 
 PORT = 8888
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./pgoprofile"))
 os.chdir(SCRIPT_DIR)
 
 class EasyServer(SocketServer.TCPServer):
   allow_reuse_address = True
 
 if __name__ == '__main__':
+  automation = Automation()
   httpd = EasyServer(("", PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
   t = threading.Thread(target=httpd.serve_forever)
   t.setDaemon(True) # don't hang on exit
   t.start()
 
   automation.initializeProfile(PROFILE_DIRECTORY)
-  browserEnv = dict(os.environ)
-
-  # These variables are necessary for correct application startup; change
-  # via the commandline at your own risk.
-  browserEnv["NO_EM_RESTART"] = "1"
+  browserEnv = automation.environment()
   browserEnv["XPCOM_DEBUG_BREAK"] = "warn"
-  if automation.UNIXISH:
-    browserEnv["LD_LIBRARY_PATH"] = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
-    browserEnv["MOZILLA_FIVE_HOME"] = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
 
   url = "http://localhost:%d/index.html" % PORT
   appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
-  status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY, {})
+  status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY, {},
+                             # the profiling HTML doesn't output anything,
+                             # so let's just run this without a timeout
+                             timeout = None)
   sys.exit(status)
--- a/build/win32/Makefile.in
+++ b/build/win32/Makefile.in
@@ -37,16 +37,25 @@
 
 DEPTH = ../..
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+ifdef ENABLE_TESTS
+DIRS += crashinjectdll
+
+PROGRAM = crashinject$(BIN_SUFFIX)
+USE_STATIC_LIBS = 1
+CPPSRCS = crashinject.cpp
+
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 ifdef WIN32_REDIST_DIR
 
 ifeq (1400,$(_MSC_VER))
 REDIST_FILES = \
 	Microsoft.VC80.CRT.manifest \
 	msvcm80.dll \
@@ -59,18 +68,23 @@ ifeq (1500,$(_MSC_VER))
 REDIST_FILES = \
 	Microsoft.VC90.CRT.manifest \
 	msvcm90.dll \
 	msvcp90.dll \
 	msvcr90.dll \
 	$(NULL)
 endif
 
+ifeq (1600,$(_MSC_VER))
+REDIST_FILES = \
+	msvcp100.dll \
+	msvcr100.dll \
+	$(NULL)
+endif
+
 endif
 
 ifdef REDIST_FILES
 libs::
 	mkdir -p $(FINAL_TARGET)
-	for file in $(REDIST_FILES) ; do \
-	  install --preserve-timestamps "$(WIN32_REDIST_DIR)"/$$file $(FINAL_TARGET) ; \
-	done
+	install --preserve-timestamps $(foreach f,$(REDIST_FILES),"$(WIN32_REDIST_DIR)"/$(f)) $(FINAL_TARGET)
 endif
 
new file mode 100644
--- /dev/null
+++ b/build/win32/crashinject.cpp
@@ -0,0 +1,128 @@
+/* ***** 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 Crash Injection Utility
+ *
+ * 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):
+ *   Ted Mielczarek <ted.mielczarek@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 ***** */
+
+/*
+ * Given a PID, this program attempts to inject a DLL into the process
+ * with that PID. The DLL it attempts to inject, "crashinjectdll.dll",
+ * must exist alongside this exe. The DLL will then crash the process.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+int main(int argc, char** argv)
+{
+  if (argc != 2) {
+    fprintf(stderr, "Usage: crashinject <PID>\n");
+    return 1;
+  }
+
+  int pid = atoi(argv[1]);
+  if (pid <= 0) {
+    fprintf(stderr, "Usage: crashinject <PID>\n");
+    return 1;
+  }
+
+  // find our DLL to inject
+  wchar_t filename[_MAX_PATH];
+  if (GetModuleFileNameW(NULL, filename, sizeof(filename) / sizeof(wchar_t)) == 0)
+    return 1;
+
+  wchar_t* slash = wcsrchr(filename, L'\\');
+  if (slash == NULL)
+    return 1;
+
+  slash++;
+  wcscpy(slash, L"crashinjectdll.dll");
+
+  // now find our target process
+  HANDLE targetProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD,
+                                  FALSE,
+                                  pid);
+  if (targetProc == NULL) {
+    fprintf(stderr, "Error %d opening target process\n", GetLastError());
+    return 1;
+  }
+
+  /*
+   * This is sort of insane, but we're implementing a technique described here:
+   * http://www.codeproject.com/KB/threads/winspy.aspx#section_2
+   *
+   * The gist is to use CreateRemoteThread to create a thread in the other
+   * process, but cheat and make the thread function kernel32!LoadLibrary,
+   * so that the only remote data we have to pass to the other process
+   * is the path to the library we want to load. The library we're loading
+   * will then do its dirty work inside the other process.
+   */
+  HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
+  // allocate some memory to hold the path in the remote process
+  void*   pLibRemote = VirtualAllocEx(targetProc, NULL, sizeof(filename),
+                                      MEM_COMMIT, PAGE_READWRITE);
+  if (pLibRemote == NULL) {
+    fprintf(stderr, "Error %d in VirtualAllocEx\n", GetLastError());
+    CloseHandle(targetProc);
+    return 1;
+  }
+
+  if (!WriteProcessMemory(targetProc, pLibRemote, (void*)filename,
+                          sizeof(filename), NULL)) {
+    fprintf(stderr, "Error %d in WriteProcessMemory\n", GetLastError());
+    VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+    CloseHandle(targetProc);
+    return 1;
+  }
+  // Now create a thread in the target process that will load our DLL
+  HANDLE hThread = CreateRemoteThread(
+                     targetProc, NULL, 0,
+                     (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32,
+                                                            "LoadLibraryW"),
+                     pLibRemote, 0, NULL);
+  if (hThread == NULL) {
+    fprintf(stderr, "Error %d in CreateRemoteThread\n", GetLastError());
+    VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+    CloseHandle(targetProc);
+    return 1;
+  }
+  WaitForSingleObject(hThread, INFINITE);
+  // Cleanup, not that it's going to matter at this point
+  CloseHandle(hThread);
+  VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+  CloseHandle(targetProc);
+
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/build/win32/crashinjectdll/Makefile.in
@@ -0,0 +1,53 @@
+# ***** 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 core build scripts.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation
+#
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Mozilla Foundation <http://www.mozilla.org/>. All Rights Reserved.
+#
+# Contributor(s):
+#   Ted Mielczarek <ted.mielczarek@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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME = crashinjectdll
+DEFFILE = $(srcdir)/crashinjectdll.def
+FORCE_SHARED_LIB = 1
+USE_STATIC_LIBS = 1
+
+CPPSRCS = crashinjectdll.cpp
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/build/win32/crashinjectdll/crashinjectdll.cpp
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <windows.h>
+
+// make sure we only ever spawn one thread
+DWORD tid = -1;
+
+DWORD WINAPI CrashingThread(
+  LPVOID lpParameter
+)
+{
+  // not a very friendly DLL
+  volatile int* x = (int *)0x0;
+  *x = 1;
+  return 0;
+}
+
+BOOL WINAPI DllMain(
+  HANDLE hinstDLL,
+  DWORD dwReason,
+  LPVOID lpvReserved
+)
+{
+  if (tid == -1)
+    // we have to crash on another thread because LoadLibrary() will
+    // catch memory access errors and return failure to the calling process
+    CreateThread(
+                 NULL,                   // default security attributes
+                 0,                      // use default stack size
+                 CrashingThread  ,       // thread function name
+                 NULL,                   // argument to thread function
+                 0,                      // use default creation flags
+                 &tid);                  // returns the thread identifier
+  return TRUE;
+}
new file mode 100644
--- /dev/null
+++ b/build/win32/crashinjectdll/crashinjectdll.def
@@ -0,0 +1,3 @@
+LIBRARY crashinjectdll
+EXPORTS
+     DllMain
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -101,16 +101,18 @@ MOZ_DEBUG_ENABLE_DEFS		= @MOZ_DEBUG_ENAB
 MOZ_DEBUG_DISABLE_DEFS	= @MOZ_DEBUG_DISABLE_DEFS@
 MOZ_DEBUG_FLAGS	= @MOZ_DEBUG_FLAGS@
 MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@
 MOZ_DBGRINFO_MODULES	= @MOZ_DBGRINFO_MODULES@
 MOZ_EXTENSIONS  = @MOZ_EXTENSIONS@
 MOZ_IMG_DECODERS= @MOZ_IMG_DECODERS@
 MOZ_IMG_ENCODERS= @MOZ_IMG_ENCODERS@
 MOZ_JSDEBUGGER  = @MOZ_JSDEBUGGER@
+MOZ_IPC         = @MOZ_IPC@
+MOZ_IPDL_TESTS  = @MOZ_IPDL_TESTS@
 MOZ_PERF_METRICS = @MOZ_PERF_METRICS@
 MOZ_LEAKY	= @MOZ_LEAKY@
 MOZ_MEMORY      = @MOZ_MEMORY@
 MOZ_JPROF       = @MOZ_JPROF@
 MOZ_SHARK       = @MOZ_SHARK@
 MOZ_CALLGRIND   = @MOZ_CALLGRIND@
 MOZ_VTUNE       = @MOZ_VTUNE@
 MOZ_TRACEVIS    = @MOZ_TRACEVIS@
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -968,29 +968,34 @@ alltags:
 	rm -f TAGS
 	find $(topsrcdir) -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' -o -name '*.idl' \) -print | $(TAG_PROGRAM)
 
 #
 # PROGRAM = Foo
 # creates OBJS, links with LIBS to create Foo
 #
 $(PROGRAM): $(PROGOBJS) $(LIBS_DEPS) $(EXTRA_DEPS) $(EXE_DEF_FILE) $(RESFILE) $(GLOBAL_DEPS)
+	@rm -f $@.manifest
 ifeq (WINCE,$(OS_ARCH))
 	$(LD) -NOLOGO -OUT:$@ $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(PROGOBJS) $(RESFILE) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 else
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 	$(LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(PROGOBJS) $(RESFILE) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		if test -f "$(srcdir)/$@.manifest"; then \
+			echo "Embedding manifest from $(srcdir)/$@.manifest and $@.manifest"; \
 			mt.exe -NOLOGO -MANIFEST "$(win_srcdir)/$@.manifest" $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		else \
+			echo "Embedding manifest from $@.manifest"; \
 			mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		fi; \
-		rm -f $@.manifest; \
+	elif test -f "$(srcdir)/$@.manifest"; then \
+		echo "Embedding manifest from $(srcdir)/$@.manifest"; \
+		mt.exe -NOLOGO -MANIFEST "$(win_srcdir)/$@.manifest" -OUTPUTRESOURCE:$@\;1; \
 	fi
 endif	# MSVC with manifest tool
 else
 ifeq ($(CPP_PROG_LINK),1)
 	$(CCC) -o $@ $(CXXFLAGS) $(WRAP_MALLOC_CFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(SOLARIS_JEMALLOC_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(BIN_FLAGS) $(WRAP_MALLOC_LIB) $(PROFILER_LIBS) $(EXE_DEF_FILE)
 else # ! CPP_PROG_LINK
 	$(CC) -o $@ $(CFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(SOLARIS_JEMALLOC_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE)
 endif # CPP_PROG_LINK
--- a/config/static-checking-config.mk
+++ b/config/static-checking-config.mk
@@ -1,15 +1,17 @@
 # The entire tree should be subject to static analysis using the XPCOM
 # script. Additional scripts may be added by specific subdirectories.
 
 DEHYDRA_SCRIPT = $(topsrcdir)/config/static-checking.js
 
 DEHYDRA_MODULES = \
   $(topsrcdir)/xpcom/analysis/final.js \
+  $(topsrcdir)/xpcom/analysis/override.js \
+  $(topsrcdir)/xpcom/analysis/must-override.js \
   $(NULL)
 
 TREEHYDRA_MODULES = \
   $(topsrcdir)/xpcom/analysis/outparams.js \
   $(topsrcdir)/xpcom/analysis/stack.js \
   $(topsrcdir)/xpcom/analysis/flow.js \
   $(topsrcdir)/js/src/jsstack.js \
   $(topsrcdir)/layout/generic/frame-verify.js \
--- a/config/static-checking.js
+++ b/config/static-checking.js
@@ -52,16 +52,41 @@ function hasAttribute(c, attrname)
 
   for each (attr in c.attributes)
     if (attr.name == 'user' && attr.value[0] == attrname)
       return true;
 
   return false;
 }
 
+// This is useful for detecting method overrides
+function signaturesMatch(m1, m2)
+{
+  if (m1.shortName != m2.shortName)
+    return false;
+
+  if (m1.isVirtual != m2.isVirtual)
+    return false;
+  
+  if (m1.isStatic != m2.isStatic)
+    return false;
+  
+  let p1 = m1.type.parameters;
+  let p2 = m2.type.parameters;
+  
+  if (p1.length != p2.length)
+    return false;
+  
+  for (let i = 0; i < p1.length; ++i)
+    if (p1[i] !== p2[i])
+      return false;
+  
+  return true;
+}
+
 const forward_functions = [
   'process_type',
   'process_tree_type',
   'process_decl',
   'process_tree_decl',
   'process_function',
   'process_tree',
   'process_cp_pre_genericize',
--- a/config/system-headers
+++ b/config/system-headers
@@ -71,16 +71,17 @@ Button.h
 byteswap.h
 #if MOZ_ENABLE_LIBXUL!=1
 #define WRAP_CAIRO_HEADERS
 #endif
 #if MOZ_TREE_CAIRO!=1
 #define WRAP_CAIRO_HEADERS
 #endif
 #ifdef WRAP_CAIRO_HEADERS
+pixman.h
 cairo.h
 cairo-atsui.h
 cairo-beos.h
 cairo-ft.h
 cairo-glitz.h
 cairo-os2.h
 cairo-pdf.h
 cairo-ps.h
--- a/configure.in
+++ b/configure.in
@@ -456,21 +456,17 @@ fi
 
 dnl Special win32 checks
 dnl ========================================================
 case "$target" in
 *-wince)
     WINVER=500
     ;;
 *)
-    if test -n "$GNU_CC"; then  
-        WINVER=501
-    else    
-        WINVER=500
-    fi
+    WINVER=502
     ;;
 esac
 
 dnl Target the Windows 7 SDK by default
 WINSDK_TARGETVER=601
 
 MOZ_ARG_WITH_STRING(windows-version,
 [  --with-windows-version=WINSDK_TARGETVER
@@ -1125,16 +1121,19 @@ HOST_OS_ARCH=`echo $host_os | sed -e 's|
 # OS_RELEASE
 # OS_MINOR_RELEASE
 #
 
 case "$HOST_OS_ARCH" in
 cygwin*|mingw*|mks*|msvc*)
     HOST_OS_ARCH=WINNT
     ;;
+darwin*)
+    HOST_OS_ARCH=Darwin
+    ;;
 linux*)
     HOST_OS_ARCH=Linux
     ;;
 solaris*)
     HOST_OS_ARCH=SunOS
     SOLARIS_SUNPRO_CC=
     SOLARIS_SUNPRO_CXX=
     if test -z "$GNU_CC"; then
@@ -4174,17 +4173,17 @@ dnl are defined in build/autoconf/altopt
 
 dnl ========================================================
 dnl =
 dnl = Check for external package dependencies
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(External Packages)
 
-MOZ_ENABLE_LIBXUL=
+MOZ_ENABLE_LIBXUL=1
 
 MOZ_ARG_WITH_STRING(libxul-sdk,
 [  --with-libxul-sdk=PFX   Use the libXUL SDK at <PFX>],
   LIBXUL_SDK_DIR=$withval)
 
 if test "$LIBXUL_SDK_DIR" = "yes"; then
     AC_MSG_ERROR([--with-libxul-sdk must specify a path])
 elif test -n "$LIBXUL_SDK_DIR" -a "$LIBXUL_SDK_DIR" != "no"; then
@@ -4503,16 +4502,17 @@ MOZ_ACTIVEX_SCRIPTING_SUPPORT=
 MOZ_BRANDING_DIRECTORY=
 MOZ_OFFICIAL_BRANDING=
 MOZ_DBGRINFO_MODULES=
 MOZ_ENABLE_CANVAS=1
 MOZ_ENABLE_CANVAS3D=
 MOZ_FEEDS=1
 MOZ_IMG_DECODERS_DEFAULT="png gif jpeg bmp icon"
 MOZ_IMG_ENCODERS_DEFAULT="png jpeg"
+MOZ_IPC=1
 MOZ_JAVAXPCOM=
 MOZ_JSDEBUGGER=1
 MOZ_JSLOADER=1
 MOZ_MATHML=1
 MOZ_MORK=1
 MOZ_MORKREADER=
 MOZ_AUTH_EXTENSION=1
 MOZ_NO_ACTIVEX_SUPPORT=1
@@ -5339,16 +5339,59 @@ dnl = JS Debugger XPCOM component (js/js
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(jsd,
 [  --disable-jsd           Disable JavaScript debug library],
     MOZ_JSDEBUGGER=,
     MOZ_JSDEBUGGER=1)
 
 
 dnl ========================================================
+dnl = Disable IPC support for tabs and plugins
+dnl ========================================================
+case "${target}" in
+*-apple-darwin*)
+    MOZ_IPC=
+    ;;
+*-wince*)
+    MOZ_IPC=
+    ;;
+esac
+
+MOZ_ARG_DISABLE_BOOL(ipc,
+[  --disable-ipc           Disable IPC supports for tabs and plugins],
+    MOZ_IPC=,
+    MOZ_IPC=1)
+
+if test -n "$MOZ_IPC"; then
+    AC_DEFINE(MOZ_IPC)
+fi
+
+AC_SUBST(MOZ_IPC)
+
+dnl ========================================================
+dnl = Enable IPDL's "expensive" unit tests
+dnl ========================================================
+MOZ_IPDL_TESTS=
+
+MOZ_ARG_ENABLE_BOOL(ipdl-tests,
+[  --enable-ipdl-tests     Enable expensive IPDL tests],
+    MOZ_IPDL_TESTS=1,
+    MOZ_IPDL_TESTS=)
+
+if test -z "$MOZ_IPC" -a -n "$MOZ_IPDL_TESTS"; then
+    AC_MSG_ERROR([--enable-ipdl-tests requires --enable-ipc])
+fi
+
+if test -n "$MOZ_IPDL_TESTS"; then
+    AC_DEFINE(MOZ_IPDL_TESTS)
+fi
+
+AC_SUBST(MOZ_IPDL_TESTS)
+
+dnl ========================================================
 dnl = Disable plugin support
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(plugins,
 [  --disable-plugins       Disable plugins support],
     MOZ_PLUGINS=,
     MOZ_PLUGINS=1)
 
 dnl ========================================================
@@ -6710,19 +6753,17 @@ if test "$MOZ_MEMORY"; then
     fi
 
     if test ! -d "$WIN32_CRT_SRC_DIR"; then
       AC_MSG_ERROR([Invalid Win32 CRT source directory: ${WIN32_CRT_SRC_DIR}])
     fi
     WIN32_CRT_SRC_DIR=`cd "$WIN32_CRT_SRC_DIR" && pwd -W`
     _objdir_win=`pwd -W`
     WIN32_CUSTOM_CRT_DIR="$_objdir_win/memory/jemalloc/crtsrc/build/intel"
-    dnl Statically link the C++ stdlib.  We only use this for Breakpad anyway.
-    AC_DEFINE(_STATIC_CPPLIB)
-    MOZ_MEMORY_LDFLAGS="-MANIFEST:NO -LIBPATH:\"$WIN32_CUSTOM_CRT_DIR\" -NODEFAULTLIB:msvcrt -NODEFAULTLIB:msvcrtd -DEFAULTLIB:mozcrt19"
+    MOZ_MEMORY_LDFLAGS="-MANIFEST:NO -LIBPATH:\"$WIN32_CUSTOM_CRT_DIR\" -NODEFAULTLIB:msvcrt -NODEFAULTLIB:msvcrtd -NODEFAULTLIB:msvcprt -NODEFAULTLIB:msvcprtd -DEFAULTLIB:mozcrt19 -DEFAULTLIB:mozcpp19"
     dnl Also pass this to NSPR/NSS
     DLLFLAGS="$DLLFLAGS $MOZ_MEMORY_LDFLAGS"
     export DLLFLAGS
     ;;
   *wince)
     AC_DEFINE(MOZ_MEMORY_WINCE)
     AC_DEFINE(MOZ_MEMORY_WINDOWS)
     if test -z "$WINCE_WINDOWS_MOBILE"; then
@@ -7373,16 +7414,17 @@ if test "$ac_nscap_nonconst_opeq_bug" = 
     AC_DEFINE(NSCAP_DONT_PROVIDE_NONCONST_OPEQ)
 fi
 fi # SKIP_COMPILER_CHECKS
 
 dnl ========================================================
 dnl C++ rtti
 dnl Should be smarter and check that the compiler does indeed have rtti
 dnl ========================================================
+
 MOZ_ARG_ENABLE_BOOL(cpp-rtti,
 [  --enable-cpp-rtti       Enable C++ RTTI ],
 [ _MOZ_USE_RTTI=1 ],
 [ _MOZ_USE_RTTI= ])
 
 if test "$_MOZ_USE_RTTI"; then
    _MOZ_RTTI_FLAGS=$_MOZ_RTTI_FLAGS_ON
 else
@@ -7481,34 +7523,33 @@ dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Static build options)
 
 MOZ_ARG_ENABLE_BOOL(static,
 [  --enable-static         Enable building of internal static libs],
     BUILD_STATIC_LIBS=1,
     BUILD_STATIC_LIBS=)
 
-dnl Disable libxul in debug builds, but not for xulrunner.
-if test -n "$MOZ_DEBUG" -a "$MOZ_BUILD_APP" != "xulrunner"; then
-   MOZ_ENABLE_LIBXUL=
-fi
-
 MOZ_ARG_ENABLE_BOOL(libxul,
 [  --enable-libxul         Enable building of libxul],
     MOZ_ENABLE_LIBXUL=1,
     MOZ_ENABLE_LIBXUL=)
 
 if test -n "$MOZ_STATIC_BUILD_UNSUPPORTED" -a -n "$BUILD_STATIC_LIBS"; then
 	AC_MSG_ERROR([--enable-static is not supported for building $MOZ_APP_NAME. You probably want --enable-libxul.])
 fi
 
 if test -n "$MOZ_ENABLE_LIBXUL" -a -n "$BUILD_STATIC_LIBS"; then
 	AC_MSG_ERROR([--enable-libxul is not compatible with --enable-static])
 fi
 
+if test -n "$MOZ_IPC" -a -z "$MOZ_ENABLE_LIBXUL"; then
+    AC_MSG_ERROR([--enable-ipc requires --enable-libxul])
+fi
+
 AC_SUBST(LIBXUL_LIBS)
 
 if test -n "$MOZ_ENABLE_LIBXUL"; then
     XPCOM_LIBS="$LIBXUL_LIBS"
     AC_DEFINE(MOZ_ENABLE_LIBXUL)
 else
     if test -n "$BUILD_STATIC_LIBS"; then
         AC_DEFINE(MOZ_STATIC_BUILD)
@@ -7798,17 +7839,17 @@ if test "$MOZ_TREE_CAIRO"; then
             MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $XLDFLAGS -lXrender -lfreetype -lfontconfig"
         fi
     fi
 
     CAIRO_FEATURES_H=gfx/cairo/cairo/src/cairo-features.h
     mv -f $CAIRO_FEATURES_H "$CAIRO_FEATURES_H".orig 2> /dev/null
 
 else
-   PKG_CHECK_MODULES(CAIRO, cairo >= $CAIRO_VERSION freetype2 fontconfig)
+   PKG_CHECK_MODULES(CAIRO, cairo >= $CAIRO_VERSION pixman-1 freetype2 fontconfig)
    MOZ_CAIRO_CFLAGS=$CAIRO_CFLAGS
    MOZ_CAIRO_LIBS=$CAIRO_LIBS
    if test "$MOZ_X11"; then
         PKG_CHECK_MODULES(CAIRO_XRENDER, cairo-xlib-xrender >= $CAIRO_VERSION)
         MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $XLDFLAGS $CAIRO_XRENDER_LIBS"
         MOZ_CAIRO_CFLAGS="$MOZ_CAIRO_CFLAGS $CAIRO_XRENDER_CFLAGS"
    fi
 fi
--- a/content/base/public/nsIObjectLoadingContent.idl
+++ b/content/base/public/nsIObjectLoadingContent.idl
@@ -34,16 +34,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIObjectFrame;
 interface nsIPluginInstance;
+interface nsIPluginTag;
 interface nsIDOMElement;
 interface nsIDOMClientRect;
 
 /**
  * This interface represents a content node that loads objects.
  */
 [scriptable, uuid(90ab443e-3e99-405e-88c9-9c42adaa3217)]
 interface nsIObjectLoadingContent : nsISupports
@@ -75,17 +76,16 @@ interface nsIObjectLoadingContent : nsIS
 
   /**
    * Returns the plugin instance if it has already been instantiated. This
    * will never instantiate the plugin and so is safe to call even when
    * content script must not execute.
    */
   [noscript] readonly attribute nsIPluginInstance pluginInstance;
 
-
   /**
    * Makes sure that a frame for this object exists, and that the plugin is
    * instantiated. This method does nothing if the type is not #TYPE_PLUGIN.
    * There is no guarantee that there will be a frame after this method is
    * called; for example, the node may have a display:none style. If plugin
    * instantiation is possible, it will be done synchronously by this method,
    * and the plugin instance will be returned. A success return value does not
    * necessarily mean that the instance is nonnull.
@@ -107,19 +107,24 @@ interface nsIObjectLoadingContent : nsIS
    * because nsIObjectFrame is unscriptable.
    */
   [noscript] void hasNewFrame(in nsIObjectFrame aFrame);
 };
 
 /**
  * This interface extends the nsIObjectLoadingContent for the 1.9.2 branch
  */
-[scriptable, uuid(f91247a2-fb8b-42d3-a9b6-8f1f49685c43)]
+[scriptable, uuid(2725a137-db4b-4e43-a096-a084aeaa8b0b)]
 interface nsIObjectLoadingContent_MOZILLA_1_9_2_BRANCH : nsISupports
 {
   /**
    * Tells the object to paint directly in this location ignoring any
    * positioning information that may have been provided otherwise
    */
   void setAbsoluteScreenPosition(in nsIDOMElement element,
                                  in nsIDOMClientRect position,
                                  in nsIDOMClientRect clip);
+
+  [noscript] void pluginCrashed(in nsIPluginTag pluginTag,
+                                in AString pluginDumpID,
+                                in AString browserDumpID,
+                                in boolean submittedCrashReport);
 };
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -39,26 +39,31 @@
 /*
  * A base class implementing nsIObjectLoadingContent for use by
  * various content nodes that want to provide plugin/document/image
  * loading functionality (eg <embed>, <object>, <applet>, etc).
  */
 
 // Interface headers
 #include "imgILoader.h"
+#include "nsEventDispatcher.h"
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
+#include "nsIDOMDataContainerEvent.h"
+#include "nsIDOMDocumentEvent.h"
+#include "nsIDOMEventTarget.h"
 #include "nsIExternalProtocolHandler.h"
 #include "nsIEventStateManager.h"
 #include "nsIObjectFrame.h"
 #include "nsIPluginDocument.h"
 #include "nsIPluginHost.h"
 #include "nsIPluginInstance.h"
 #include "nsIPresShell.h"
+#include "nsIPrivateDOMEvent.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamConverterService.h"
 #include "nsIURILoader.h"
 #include "nsIURL.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebNavigationInfo.h"
 #include "nsIScriptChannel.h"
@@ -75,16 +80,17 @@
 #include "nsContentUtils.h"
 #include "nsDocShellCID.h"
 #include "nsGkAtoms.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 #include "nsPresShellIterator.h"
 #include "nsMimeTypes.h"
 #include "nsStyleUtil.h"
+#include "nsGUIEvent.h"
 
 // Concrete classes
 #include "nsFrameLoader.h"
 
 #include "nsObjectLoadingContent.h"
 #include "mozAutoDocUpdate.h"
 
 #ifdef PR_LOGGING
@@ -205,16 +211,113 @@ nsPluginErrorEvent::Run()
       return NS_OK;
   }
   nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
                                        type, PR_TRUE, PR_TRUE);
 
   return NS_OK;
 }
 
+/**
+ * A task for firing PluginCrashed DOM Events.
+ */
+class nsPluginCrashedEvent : public nsRunnable {
+public:
+  nsCOMPtr<nsIContent> mContent;
+  nsString mPluginDumpID;
+  nsString mBrowserDumpID;
+  nsString mPluginName;
+  PRBool mSubmittedCrashReport;
+
+  nsPluginCrashedEvent(nsIContent* aContent,
+                       const nsAString& aPluginDumpID,
+                       const nsAString& aBrowserDumpID,
+                       const nsAString& aPluginName,
+                       PRBool submittedCrashReport)
+    : mContent(aContent),
+      mPluginDumpID(aPluginDumpID),
+      mBrowserDumpID(aBrowserDumpID),
+      mPluginName(aPluginName),
+      mSubmittedCrashReport(submittedCrashReport)
+  {}
+
+  ~nsPluginCrashedEvent() {}
+
+  NS_IMETHOD Run();
+};
+
+NS_IMETHODIMP
+nsPluginCrashedEvent::Run()
+{
+  LOG(("OBJLC []: Firing plugin crashed event for content %p\n",
+       mContent.get()));
+
+  nsCOMPtr<nsIDOMDocumentEvent> domEventDoc =
+    do_QueryInterface(mContent->GetDocument());
+  if (!domEventDoc) {
+    NS_WARNING("Couldn't get document for PluginCrashed event!");
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMEvent> event;
+  domEventDoc->CreateEvent(NS_LITERAL_STRING("datacontainerevents"),
+                           getter_AddRefs(event));
+  nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
+  nsCOMPtr<nsIDOMDataContainerEvent> containerEvent(do_QueryInterface(event));
+  if (!privateEvent || !containerEvent) {
+    NS_WARNING("Couldn't QI event for PluginCrashed event!");
+    return NS_OK;
+  }
+
+  event->InitEvent(NS_LITERAL_STRING("PluginCrashed"), PR_TRUE, PR_TRUE);
+  privateEvent->SetTrusted(PR_TRUE);
+  privateEvent->GetInternalNSEvent()->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
+  
+  nsCOMPtr<nsIWritableVariant> variant;
+
+  // add a "pluginDumpID" property to this event
+  variant = do_CreateInstance("@mozilla.org/variant;1");
+  if (!variant) {
+    NS_WARNING("Couldn't create pluginDumpID variant for PluginCrashed event!");
+    return NS_OK;
+  }
+  variant->SetAsAString(mPluginDumpID);
+  containerEvent->SetData(NS_LITERAL_STRING("pluginDumpID"), variant);
+
+  // add a "browserDumpID" property to this event
+  variant = do_CreateInstance("@mozilla.org/variant;1");
+  if (!variant) {
+    NS_WARNING("Couldn't create browserDumpID variant for PluginCrashed event!");
+    return NS_OK;
+  }
+  variant->SetAsAString(mBrowserDumpID);
+  containerEvent->SetData(NS_LITERAL_STRING("browserDumpID"), variant);
+
+  // add a "pluginName" property to this event
+  variant = do_CreateInstance("@mozilla.org/variant;1");
+  if (!variant) {
+    NS_WARNING("Couldn't create pluginName variant for PluginCrashed event!");
+    return NS_OK;
+  }
+  variant->SetAsAString(mPluginName);
+  containerEvent->SetData(NS_LITERAL_STRING("pluginName"), variant);
+
+  // add a "submittedCrashReport" property to this event
+  variant = do_CreateInstance("@mozilla.org/variant;1");
+  if (!variant) {
+    NS_WARNING("Couldn't create crashSubmit variant for PluginCrashed event!");
+    return NS_OK;
+  }
+  variant->SetAsBool(mSubmittedCrashReport);
+  containerEvent->SetData(NS_LITERAL_STRING("submittedCrashReport"), variant);
+
+  nsEventDispatcher::DispatchDOMEvent(mContent, nsnull, event, nsnull, nsnull);
+  return NS_OK;
+}
+
 class AutoNotifier {
   public:
     AutoNotifier(nsObjectLoadingContent* aContent, PRBool aNotify) :
       mContent(aContent), mNotify(aNotify) {
         mOldType = aContent->Type();
         mOldState = aContent->ObjectState();
     }
     ~AutoNotifier() {
@@ -251,17 +354,17 @@ class AutoFallback {
   public:
     AutoFallback(nsObjectLoadingContent* aContent, const nsresult* rv)
       : mContent(aContent), mResult(rv), mPluginState(ePluginOtherState) {}
     ~AutoFallback() {
       if (NS_FAILED(*mResult)) {
         LOG(("OBJLC [%p]: rv=%08x, falling back\n", mContent, *mResult));
         mContent->Fallback(PR_FALSE);
         if (mPluginState != ePluginOtherState) {
-          mContent->mPluginState = mPluginState;
+          mContent->mFallbackReason = mPluginState;
         }
       }
     }
 
     /**
      * This should be set to something other than ePluginOtherState to indicate
      * a specific failure that should be passed on.
      */
@@ -354,17 +457,17 @@ IsPluginEnabledByExtension(nsIURI* uri, 
 
 nsObjectLoadingContent::nsObjectLoadingContent()
   : mPendingInstantiateEvent(nsnull)
   , mChannel(nsnull)
   , mType(eType_Loading)
   , mInstantiating(PR_FALSE)
   , mUserDisabled(PR_FALSE)
   , mSuppressed(PR_FALSE)
-  , mPluginState(ePluginOtherState)
+  , mFallbackReason(ePluginOtherState)
 {
 }
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   DestroyImageLoadingContent();
   if (mFrameLoader) {
     mFrameLoader->Destroy();
@@ -593,26 +696,26 @@ nsObjectLoadingContent::OnStartRequest(n
       }
 
       break;
     case eType_Loading:
       NS_NOTREACHED("Should not have a loading type here!");
     case eType_Null:
       LOG(("OBJLC [%p]: Unsupported type, falling back\n", this));
       // Need to fallback here (instead of using the case below), so that we can
-      // set mPluginState without it being overwritten. This is also why we
+      // set mFallbackReason without it being overwritten. This is also why we
       // return early.
       Fallback(PR_FALSE);
 
       PluginSupportState pluginState = GetPluginSupportState(thisContent,
                                                              mContentType);
       // Do nothing, but fire the plugin not found event if needed
       if (pluginState != ePluginOtherState) {
+        mFallbackReason = pluginState;
         FirePluginError(thisContent, pluginState);
-        mPluginState = pluginState;
       }
       return NS_BINDING_ABORTED;
   }
 
   if (mFinalListener) {
     mType = newType;
     rv = mFinalListener->OnStartRequest(aRequest, aContext);
     if (NS_FAILED(rv)) {
@@ -926,23 +1029,26 @@ nsObjectLoadingContent::ObjectState() co
     case eType_Null:
       if (mSuppressed)
         return NS_EVENT_STATE_SUPPRESSED;
       if (mUserDisabled)
         return NS_EVENT_STATE_USERDISABLED;
 
       // Otherwise, broken
       PRInt32 state = NS_EVENT_STATE_BROKEN;
-      switch (mPluginState) {
+      switch (mFallbackReason) {
         case ePluginDisabled:
           state |= NS_EVENT_STATE_HANDLER_DISABLED;
           break;
         case ePluginBlocklisted:
           state |= NS_EVENT_STATE_HANDLER_BLOCKED;
           break;
+        case ePluginCrashed:
+          state |= NS_EVENT_STATE_HANDLER_CRASHED;
+          break;
         case ePluginUnsupported:
           state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
           break;
       }
       return state;
   };
   NS_NOTREACHED("unknown type?");
   // this return statement only exists to avoid a compile warning
@@ -1481,17 +1587,17 @@ nsObjectLoadingContent::UnloadContent()
   // Don't notify in CancelImageRequests. We do it ourselves.
   CancelImageRequests(PR_FALSE);
   if (mFrameLoader) {
     mFrameLoader->Destroy();
     mFrameLoader = nsnull;
   }
   mType = eType_Null;
   mUserDisabled = mSuppressed = PR_FALSE;
-  mPluginState = ePluginOtherState;
+  mFallbackReason = ePluginOtherState;
 }
 
 void
 nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
                                           PRInt32 aOldState,
                                           PRBool aSync)
 {
   LOG(("OBJLC [%p]: Notifying about state change: (%u, %x) -> (%u, %x) (sync=%i)\n",
@@ -1880,9 +1986,35 @@ nsObjectLoadingContent::SetAbsoluteScree
 {
   nsIObjectFrame* frame = GetExistingFrame(eFlushLayout);
   if (!frame)
     return NS_ERROR_NOT_AVAILABLE;
 
   return frame->SetAbsoluteScreenPosition(element, position, clip);
 }
 
+NS_IMETHODIMP
+nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
+                                      const nsAString& pluginDumpID,
+                                      const nsAString& browserDumpID,
+                                      PRBool submittedCrashReport)
+{
+  AutoNotifier notifier(this, PR_TRUE);
+  UnloadContent();
+  mFallbackReason = ePluginCrashed;
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
+  // Note that aPluginTag in invalidated after we're called, so copy 
+  // out any data we need now.
+  nsCAutoString pluginName;
+  aPluginTag->GetName(pluginName);
+
+  nsCOMPtr<nsIRunnable> ev = new nsPluginCrashedEvent(thisContent,
+                                                      pluginDumpID,
+                                                      browserDumpID,
+                                                      NS_ConvertUTF8toUTF16(pluginName),
+                                                      submittedCrashReport);
+  nsresult rv = NS_DispatchToCurrentThread(ev);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("failed to dispatch nsPluginCrashedEvent");
+  }
+  return NS_OK;
+}
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -55,23 +55,22 @@
 #include "nsIChannelClassifier.h"
 
 class nsAsyncInstantiateEvent;
 class AutoNotifier;
 class AutoFallback;
 class AutoSetInstantiatingToFalse;
 
 enum PluginSupportState {
-  ePluginUnsupported,  // The plugin is not supported (not installed, say)
-  ePluginDisabled,     // The plugin has been explicitly disabled by the
-                       // user.
+  ePluginUnsupported,  // The plugin is not supported (e.g. not installed)
+  ePluginDisabled,     // The plugin has been explicitly disabled by the user
   ePluginBlocklisted,  // The plugin is blocklisted and disabled
   ePluginOutdated,     // The plugin is considered outdated, but not disabled
-  ePluginOtherState    // Something else (e.g. not a plugin at all as far
-                       // as we can tell).
+  ePluginOtherState,   // Something else (e.g. uninitialized or not a plugin)
+  ePluginCrashed
 };
 
 /**
  * INVARIANTS OF THIS CLASS
  * - mChannel is non-null between asyncOpen and onStopRequest (NOTE: Only needs
  *   to be valid until onStopRequest is called on mFinalListener, not
  *   necessarily until the channel calls onStopRequest on us)
  * - mChannel corresponds to the channel that gets passed to the
@@ -417,15 +416,15 @@ class nsObjectLoadingContent : public ns
      * Whether we are about to call instantiate on our frame. If we aren't,
      * SetFrame needs to asynchronously call Instantiate.
      */
     PRBool                      mInstantiating : 1;
     // Blocking status from content policy
     PRBool                      mUserDisabled  : 1;
     PRBool                      mSuppressed    : 1;
     // A specific state that caused us to fallback
-    PluginSupportState          mPluginState;
+    PluginSupportState          mFallbackReason;
 
     friend class nsAsyncInstantiateEvent;
 };
 
 
 #endif
--- a/content/events/public/nsIEventStateManager.h
+++ b/content/events/public/nsIEventStateManager.h
@@ -192,9 +192,13 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventSt
 #define NS_EVENT_STATE_HANDLER_BLOCKED \
                                      0x01000000
 // Handler for the content has been disabled
 #define NS_EVENT_STATE_HANDLER_DISABLED \
                                      0x02000000
 
 #define NS_EVENT_STATE_INDETERMINATE 0x04000000 // CSS3-Selectors
 
+// Handler for the content has crashed
+#define NS_EVENT_STATE_HANDLER_CRASHED \
+                                     0x08000000
+
 #endif // nsIEventStateManager_h__
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -49,16 +49,19 @@ nsDOMMouseEvent::nsDOMMouseEvent(nsPresC
                  new nsMouseEvent(PR_FALSE, 0, nsnull,
                                   nsMouseEvent::eReal))
 {
   // There's no way to make this class' ctor allocate an nsMouseScrollEvent.
   // It's not that important, though, since a scroll event is not a real
   // DOM event.
   
   if (aEvent) {
+    NS_ASSERTION(static_cast<nsMouseEvent*>(mEvent)->reason
+                 != nsMouseEvent::eSynthesized,
+                 "Don't dispatch DOM events from synthesized mouse events");
     mEventIsInternal = PR_FALSE;
   }
   else {
     mEventIsInternal = PR_TRUE;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
   }
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -183,16 +183,25 @@ static nsITimerCallback* gUserInteractio
 // Pixel scroll accumulation for synthetic line scrolls
 static nscoord gPixelScrollDeltaX = 0;
 static nscoord gPixelScrollDeltaY = 0;
 static PRUint32 gPixelScrollDeltaTimeout = 0;
 
 static nscoord
 GetScrollableViewLineHeight(nsPresContext* aPresContext, nsIFrame* aTargetFrame);
 
+static inline PRBool
+IsMouseEventReal(nsEvent* aEvent)
+{
+  NS_ABORT_IF_FALSE(aEvent->eventStructType == NS_MOUSE_EVENT,
+                    "Not a mouse event");
+  // Return true if not synthesized.
+  return static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal;
+}
+
 #ifdef DEBUG_DOCSHELL_FOCUS
 static void
 PrintDocTree(nsIDocShellTreeItem* aParentItem, int aLevel)
 {
   for (PRInt32 i=0;i<aLevel;i++) printf("  ");
 
   PRInt32 childWebshellCount;
   aParentItem->GetChildCount(&childWebshellCount);
@@ -502,17 +511,17 @@ nsMouseWheelTransaction::OnEvent(nsEvent
           OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
         // Terminate the current mousewheel transaction if the mouse moved more
         // than ignoremovedelay milliseconds ago
         EndTransaction();
       }
       return;
     case NS_MOUSE_MOVE:
     case NS_DRAGDROP_OVER:
-      if (((nsMouseEvent*)aEvent)->reason == nsMouseEvent::eReal) {
+      if (IsMouseEventReal(aEvent)) {
         // If the cursor is moving to be outside the frame,
         // terminate the scrollwheel transaction.
         nsIntPoint pt = GetScreenPoint((nsGUIEvent*)aEvent);
         nsIntRect r = sTargetFrame->GetScreenRectExternal();
         if (!r.Contains(pt)) {
           EndTransaction();
           return;
         }
@@ -1024,17 +1033,17 @@ nsEventStateManager::PreHandleEvent(nsPr
     NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null.  this should not happen.  see bug #13007");
     if (!mCurrentTarget) return NS_ERROR_NULL_POINTER;
   }
 
   // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page
   // when user is not active doesn't change the state to active.
   if (NS_IS_TRUSTED_EVENT(aEvent) &&
       ((aEvent->eventStructType == NS_MOUSE_EVENT  &&
-        static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal &&
+        IsMouseEventReal(aEvent) &&
         aEvent->message != NS_MOUSE_ENTER &&
         aEvent->message != NS_MOUSE_EXIT) ||
        aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ||
        aEvent->eventStructType == NS_KEY_EVENT)) {
     if (gMouseOrKeyboardEventCounter == 0) {
       nsCOMPtr<nsIObserverService> obs =
         do_GetService("@mozilla.org/observer-service;1");
       if (obs) {
@@ -2923,23 +2932,25 @@ nsEventStateManager::PostHandleEvent(nsP
         // any of our own processing of a drag. Workaround for bug 43258.
         StopTrackingDragGesture();
       }
     }
     break;
   case NS_MOUSE_BUTTON_UP:
     {
       SetContentState(nsnull, NS_EVENT_STATE_ACTIVE);
-      if (!mCurrentTarget) {
-        nsIFrame* targ;
-        GetEventTarget(&targ);
-      }
-      if (mCurrentTarget) {
-        ret =
-          CheckForAndDispatchClick(presContext, (nsMouseEvent*)aEvent, aStatus);
+      if (IsMouseEventReal(aEvent)) {
+        if (!mCurrentTarget) {
+          nsIFrame* targ;
+          GetEventTarget(&targ);
+        }
+        if (mCurrentTarget) {
+          ret = CheckForAndDispatchClick(presContext, (nsMouseEvent*)aEvent,
+                                         aStatus);
+        }
       }
       nsIPresShell *shell = presContext->GetPresShell();
       if (shell) {
         nsIViewManager* viewMan = shell->GetViewManager();
         if (viewMan) {
           nsIView* grabbingView = nsnull;
           viewMan->GetMouseEventGrabber(grabbingView);
           if (grabbingView == aView) {
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -74,16 +74,17 @@ ifdef MOZ_SMIL
 DIRS += interfaces/smil
 endif
 
 DIRS += \
   public/coreEvents \
   base \
   src \
   locales \
+  plugins \
   $(NULL)
 
 ifdef ENABLE_TESTS
 DIRS += tests
 endif
 
 include $(topsrcdir)/config/rules.mk
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -3593,16 +3593,17 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMViewCSS)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMAbstractView)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageWindow)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DataContainerEvent, nsIDOMDataContainerEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataContainerEvent)
+    DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MessageEvent, nsIDOMMessageEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMessageEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(GeoGeolocation, nsIDOMGeoGeolocation)
@@ -9748,17 +9749,17 @@ nsHTMLPluginObjElementSH::Call(nsIXPConn
                                jsval *argv, jsval *vp, PRBool *_retval)
 {
   nsCOMPtr<nsIPluginInstance> pi;
   nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, getter_AddRefs(pi));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If obj is a native wrapper, or if there's no plugin around for
   // this object, throw.
-  if (!ObjectIsNativeWrapper(cx, obj) || !pi) {
+  if (ObjectIsNativeWrapper(cx, obj) || !pi) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   JSObject *pi_obj = nsnull;
   JSObject *pi_proto = nsnull;
 
   rv = GetPluginJSObject(cx, obj, pi, &pi_obj, &pi_proto);
   NS_ENSURE_SUCCESS(rv, rv);
new file mode 100644
--- /dev/null
+++ b/dom/plugins/AStream.h
@@ -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 Plugins.
+ *
+ * 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 ***** */
+
+#ifndef mozilla_plugins_AStream_h
+#define mozilla_plugins_AStream_h
+
+namespace mozilla {
+namespace plugins {
+
+/**
+ * When we are passed NPStream->{ndata,pdata} in {NPN,NPP}_DestroyStream, we
+ * don't know whether it's a plugin stream or a browser stream. This abstract
+ * class lets us cast to the right type of object and send the appropriate
+ * message.
+ */
+class AStream
+{
+public:
+  virtual bool IsBrowserStream() = 0;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/plugins/BrowserStreamChild.cpp
@@ -0,0 +1,319 @@
+/* -*- 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ * 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 "BrowserStreamChild.h"
+#include "PluginInstanceChild.h"
+#include "StreamNotifyChild.h"
+
+namespace mozilla {
+namespace plugins {
+
+BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
+                                       const nsCString& url,
+                                       const uint32_t& length,
+                                       const uint32_t& lastmodified,
+                                       StreamNotifyChild* notifyData,
+                                       const nsCString& headers,
+                                       const nsCString& mimeType,
+                                       const bool& seekable,
+                                       NPError* rv,
+                                       uint16_t* stype)
+  : mInstance(instance)
+  , mStreamStatus(kStreamOpen)
+  , mDestroyPending(NOT_DESTROYED)
+  , mNotifyPending(false)
+  , mInstanceDying(false)
+  , mState(CONSTRUCTING)
+  , mURL(url)
+  , mHeaders(headers)
+  , mStreamNotify(notifyData)
+  , mDeliveryTracker(this)
+{
+  PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s, %s)", FULLFUNCTION,
+                    url.get(), length, lastmodified, (void*) notifyData,
+                    headers.get(), mimeType.get()));
+
+  AssertPluginThread();
+
+  memset(&mStream, 0, sizeof(mStream));
+  mStream.ndata = static_cast<AStream*>(this);
+  mStream.url = NullableStringGet(mURL);
+  mStream.end = length;
+  mStream.lastmodified = lastmodified;
+  mStream.headers = NullableStringGet(mHeaders);
+  if (notifyData)
+    mStream.notifyData = notifyData->mClosure;
+}
+
+NPError
+BrowserStreamChild::StreamConstructed(
+            const nsCString& mimeType,
+            const bool& seekable,
+            uint16_t* stype)
+{
+  NPError rv = NPERR_NO_ERROR;
+
+  *stype = NP_NORMAL;
+  rv = mInstance->mPluginIface->newstream(
+    &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
+    &mStream, seekable, stype);
+  if (rv != NPERR_NO_ERROR) {
+    mState = DELETING;
+    mStreamNotify = NULL;
+  }
+  else {
+    mState = ALIVE;
+
+    if (mStreamNotify)
+      mStreamNotify->SetAssociatedStream(this);
+  }
+
+  return rv;
+}
+
+BrowserStreamChild::~BrowserStreamChild()
+{
+  NS_ASSERTION(!mStreamNotify, "Should have nulled it by now!");
+}
+
+bool
+BrowserStreamChild::RecvWrite(const int32_t& offset,
+                              const Buffer& data,
+                              const uint32_t& newlength)
+{
+  PLUGIN_LOG_DEBUG_FUNCTION;
+
+  AssertPluginThread();
+
+  if (ALIVE != mState)
+    NS_RUNTIMEABORT("Unexpected state: received data after NPP_DestroyStream?");
+
+  if (kStreamOpen != mStreamStatus)
+    return true;
+
+  mStream.end = newlength;
+
+  NS_ASSERTION(data.Length() > 0, "Empty data");
+
+  PendingData* newdata = mPendingData.AppendElement();
+  newdata->offset = offset;
+  newdata->data = data;
+  newdata->curpos = 0;
+
+  EnsureDeliveryPending();
+
+  return true;
+}
+
+bool
+BrowserStreamChild::AnswerNPP_StreamAsFile(const nsCString& fname)
+{
+  PLUGIN_LOG_DEBUG(("%s (fname=%s)", FULLFUNCTION, fname.get()));
+
+  AssertPluginThread();
+
+  if (ALIVE != mState)
+    NS_RUNTIMEABORT("Unexpected state: received file after NPP_DestroyStream?");
+
+  if (kStreamOpen != mStreamStatus)
+    return true;
+
+  mInstance->mPluginIface->asfile(&mInstance->mData, &mStream,
+                                  fname.get());
+  return true;
+}
+
+bool
+BrowserStreamChild::RecvNPP_DestroyStream(const NPReason& reason)
+{
+  PLUGIN_LOG_DEBUG_METHOD;
+
+  if (ALIVE != mState)
+    NS_RUNTIMEABORT("Unexpected state: recevied NPP_DestroyStream twice?");
+
+  mState = DYING;
+  mDestroyPending = DESTROY_PENDING;
+  if (NPRES_DONE != reason)
+    mStreamStatus = reason;
+
+  EnsureDeliveryPending();
+  return true;
+}
+
+bool
+BrowserStreamChild::Recv__delete__()
+{
+  AssertPluginThread();
+
+  if (DELETING != mState)
+    NS_RUNTIMEABORT("Bad state, not DELETING");
+
+  return true;
+}
+
+NPError
+BrowserStreamChild::NPN_RequestRead(NPByteRange* aRangeList)
+{
+  PLUGIN_LOG_DEBUG_FUNCTION;
+
+  AssertPluginThread();
+
+  if (ALIVE != mState || kStreamOpen != mStreamStatus)
+    return NPERR_GENERIC_ERROR;
+
+  IPCByteRanges ranges;
+  for (; aRangeList; aRangeList = aRangeList->next) {
+    IPCByteRange br = {aRangeList->offset, aRangeList->length};
+    ranges.push_back(br);
+  }
+
+  NPError result;
+  CallNPN_RequestRead(ranges, &result);
+  return result;
+}
+
+void
+BrowserStreamChild::NPN_DestroyStream(NPReason reason)
+{
+  mStreamStatus = reason;
+  if (ALIVE == mState)
+    SendNPN_DestroyStream(reason);
+
+  EnsureDeliveryPending();
+}
+
+void
+BrowserStreamChild::EnsureDeliveryPending()
+{
+  MessageLoop::current()->PostTask(FROM_HERE,
+    mDeliveryTracker.NewRunnableMethod(&BrowserStreamChild::Deliver));
+}
+
+void
+BrowserStreamChild::Deliver()
+{
+  while (kStreamOpen == mStreamStatus && mPendingData.Length()) {
+    if (DeliverPendingData() && kStreamOpen == mStreamStatus) {
+      SetSuspendedTimer();
+      return;
+    }
+  }
+  ClearSuspendedTimer();
+
+  NS_ASSERTION(kStreamOpen != mStreamStatus || 0 == mPendingData.Length(),
+               "Exit out of the data-delivery loop with pending data");
+  mPendingData.Clear();
+
+  if (DESTROY_PENDING == mDestroyPending) {
+    mDestroyPending = DESTROYED;
+    if (mState != DYING)
+      NS_RUNTIMEABORT("mDestroyPending but state not DYING");
+
+    NS_ASSERTION(NPRES_DONE != mStreamStatus, "Success status set too early!");
+    if (kStreamOpen == mStreamStatus)
+      mStreamStatus = NPRES_DONE;
+
+    (void) mInstance->mPluginIface
+      ->destroystream(&mInstance->mData, &mStream, mStreamStatus);
+  }
+  if (DESTROYED == mDestroyPending && mNotifyPending) {
+    NS_ASSERTION(mStreamNotify, "mDestroyPending but no mStreamNotify?");
+      
+    mNotifyPending = false;
+    mStreamNotify->NPP_URLNotify(mStreamStatus);
+    delete mStreamNotify;
+    mStreamNotify = NULL;
+  }
+  if (DYING == mState && DESTROYED == mDestroyPending
+      && !mStreamNotify && !mInstanceDying) {
+    SendStreamDestroyed();
+    mState = DELETING;
+  }
+}
+
+bool
+BrowserStreamChild::DeliverPendingData()
+{
+  if (mState != ALIVE && mState != DYING)
+    NS_RUNTIMEABORT("Unexpected state");
+
+  NS_ASSERTION(mPendingData.Length(), "Called from Deliver with empty pending");
+
+  while (mPendingData[0].curpos < mPendingData[0].data.Length()) {
+    int32_t r = mInstance->mPluginIface->writeready(&mInstance->mData, &mStream);
+    if (kStreamOpen != mStreamStatus)
+      return false;
+    if (0 == r) // plugin wants to suspend delivery
+      return true;
+
+    r = mInstance->mPluginIface->write(
+      &mInstance->mData, &mStream,
+      mPendingData[0].offset + mPendingData[0].curpos, // offset
+      mPendingData[0].data.Length() - mPendingData[0].curpos, // length
+      const_cast<char*>(mPendingData[0].data.BeginReading() + mPendingData[0].curpos));
+    if (kStreamOpen != mStreamStatus)
+      return false;
+    if (0 == r)
+      return true;
+    if (r < 0) { // error condition
+      NPN_DestroyStream(NPRES_NETWORK_ERR);
+      return false;
+    }
+    mPendingData[0].curpos += r;
+  }
+  mPendingData.RemoveElementAt(0);
+  return false;
+}
+
+void
+BrowserStreamChild::SetSuspendedTimer()
+{
+  if (mSuspendedTimer.IsRunning())
+    return;
+  mSuspendedTimer.Start(
+    base::TimeDelta::FromMilliseconds(100), // 100ms copied from Mozilla plugin host
+    this, &BrowserStreamChild::Deliver);
+}
+
+void
+BrowserStreamChild::ClearSuspendedTimer()
+{
+  mSuspendedTimer.Stop();
+}
+
+} /* namespace plugins */
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/dom/plugins/BrowserStreamChild.h
@@ -0,0 +1,205 @@
+/* -*- 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ * 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_plugins_BrowserStreamChild_h
+#define mozilla_plugins_BrowserStreamChild_h 1
+
+#include "mozilla/plugins/PBrowserStreamChild.h"
+#include "mozilla/plugins/AStream.h"
+
+namespace mozilla {
+namespace plugins {
+
+class PluginInstanceChild;
+class StreamNotifyChild;
+
+class BrowserStreamChild : public PBrowserStreamChild, public AStream
+{
+public:
+  BrowserStreamChild(PluginInstanceChild* instance,
+                     const nsCString& url,
+                     const uint32_t& length,
+                     const uint32_t& lastmodified,
+                     StreamNotifyChild* notifyData,
+                     const nsCString& headers,
+                     const nsCString& mimeType,
+                     const bool& seekable,
+                     NPError* rv,
+                     uint16_t* stype);
+  virtual ~BrowserStreamChild();
+
+  NS_OVERRIDE virtual bool IsBrowserStream() { return true; }
+
+  NPError StreamConstructed(
+            const nsCString& mimeType,
+            const bool& seekable,
+            uint16_t* stype);
+
+  virtual bool RecvWrite(const int32_t& offset,
+                         const Buffer& data,
+                         const uint32_t& newsize);
+  virtual bool AnswerNPP_StreamAsFile(const nsCString& fname);
+  virtual bool RecvNPP_DestroyStream(const NPReason& reason);
+  virtual bool Recv__delete__();
+
+  void EnsureCorrectInstance(PluginInstanceChild* i)
+  {
+    if (i != mInstance)
+      NS_RUNTIMEABORT("Incorrect stream instance");
+  }
+  void EnsureCorrectStream(NPStream* s)
+  {
+    if (s != &mStream)
+      NS_RUNTIMEABORT("Incorrect stream data");
+  }
+
+  NPError NPN_RequestRead(NPByteRange* aRangeList);
+  void NPN_DestroyStream(NPReason reason);
+
+  void NotifyPending() {
+    NS_ASSERTION(!mNotifyPending, "Pending twice?");
+    mNotifyPending = true;
+    EnsureDeliveryPending();
+  }
+
+  /**
+   * During instance destruction, artificially cancel all outstanding streams.
+   *
+   * @return false if we are already in the DELETING state.
+   */
+  bool InstanceDying() {
+    if (DELETING == mState)
+      return false;
+
+    mInstanceDying = true;
+    return true;
+  }
+
+  void FinishDelivery() {
+    NS_ASSERTION(mInstanceDying, "Should only be called after InstanceDying");
+    NS_ASSERTION(DELETING != mState, "InstanceDying didn't work?");
+    mStreamStatus = NPRES_USER_BREAK;
+    Deliver();
+    NS_ASSERTION(!mStreamNotify, "Didn't deliver NPN_URLNotify?");
+  }
+
+private:
+  friend class StreamNotifyChild;
+  using PBrowserStreamChild::SendNPN_DestroyStream;
+
+  /**
+   * Post an event to ensure delivery of pending data/destroy/urlnotify events
+   * outside of the current RPC stack.
+   */
+  void EnsureDeliveryPending();
+
+  /**
+   * Deliver data, destruction, notify scheduling
+   * or cancelling the suspended timer as needed.
+   */
+  void Deliver();
+
+  /**
+   * Deliver one chunk of pending data.
+   * @return true if the plugin indicated a pause was necessary
+   */
+  bool DeliverPendingData();
+
+  void SetSuspendedTimer();
+  void ClearSuspendedTimer();
+
+  PluginInstanceChild* mInstance;
+  NPStream mStream;
+
+  static const NPReason kStreamOpen = -1;
+
+  /**
+   * The plugin's notion of whether a stream has been "closed" (no more
+   * data delivery) differs from the plugin host due to asynchronous delivery
+   * of data and NPN_DestroyStream. While the plugin-visible stream is open,
+   * mStreamStatus should be kStreamOpen (-1). mStreamStatus will be a
+   * failure code if either the parent or child indicates stream failure.
+   */
+  NPReason mStreamStatus;
+
+  /**
+   * Delivery of NPP_DestroyStream and NPP_URLNotify must be postponed until
+   * all data has been delivered.
+   */
+  enum {
+    NOT_DESTROYED, // NPP_DestroyStream not yet received
+    DESTROY_PENDING, // NPP_DestroyStream received, not yet delivered
+    DESTROYED // NPP_DestroyStream delivered, NPP_URLNotify may still be pending
+  } mDestroyPending;
+  bool mNotifyPending;
+
+  // When NPP_Destroy is called for our instance (manager), this flag is set
+  // cancels the stream and avoids sending StreamDestroyed.
+  bool mInstanceDying;
+
+  enum {
+    CONSTRUCTING,
+    ALIVE,
+    DYING,
+    DELETING
+  } mState;
+  nsCString mURL;
+  nsCString mHeaders;
+  StreamNotifyChild* mStreamNotify;
+
+  struct PendingData
+  {
+    int32_t offset;
+    Buffer data;
+    int32_t curpos;
+  };
+  nsTArray<PendingData> mPendingData;
+
+  /**
+   * Asynchronous RecvWrite messages are never delivered to the plugin
+   * immediately, because that may be in the midst of an unexpected RPC
+   * stack frame. It instead posts a runnable using this tracker to cancel
+   * in case we are destroyed.
+   */
+  ScopedRunnableMethodFactory<BrowserStreamChild> mDeliveryTracker;
+  base::RepeatingTimer<BrowserStreamChild> mSuspendedTimer;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif /* mozilla_plugins_BrowserStreamChild_h */
new file mode 100644
--- /dev/null
+++ b/dom/plugins/BrowserStreamParent.cpp
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+
+#include "BrowserStreamParent.h"
+#include "PluginInstanceParent.h"
+
+// How much data are we willing to send across the wire
+// in one chunk?
+static const int32_t kSendDataChunk = 0x1000;
+
+namespace mozilla {
+namespace plugins {
+
+BrowserStreamParent::BrowserStreamParent(PluginInstanceParent* npp,
+                                         NPStream* stream)
+  : mNPP(npp)
+  , mStream(stream)
+  , mState(ALIVE)
+{
+  mStream->pdata = static_cast<AStream*>(this);
+}
+
+BrowserStreamParent::~BrowserStreamParent()
+{
+}
+
+bool
+BrowserStreamParent::AnswerNPN_RequestRead(const IPCByteRanges& ranges,
+                                           NPError* result)
+{
+  PLUGIN_LOG_DEBUG_FUNCTION;
+
+  switch (mState) {
+  case ALIVE:
+    break;
+
+  case DYING:
+    *result = NPERR_GENERIC_ERROR;
+    return true;
+
+  default:
+    NS_ERROR("Unexpected state");
+    return false;
+  }
+
+  if (!mStream)
+    return false;
+
+  if (ranges.size() > PR_INT32_MAX)
+    return false;
+
+  nsAutoArrayPtr<NPByteRange> rp(new NPByteRange[ranges.size()]);
+  for (PRUint32 i = 0; i < ranges.size(); ++i) {
+    rp[i].offset = ranges[i].offset;
+    rp[i].length = ranges[i].length;
+    rp[i].next = &rp[i + 1];
+  }
+  rp[ranges.size() - 1].next = NULL;
+
+  *result = mNPP->mNPNIface->requestread(mStream, rp);
+  return true;
+}
+
+bool
+BrowserStreamParent::RecvNPN_DestroyStream(const NPReason& reason)
+{
+  switch (mState) {
+  case ALIVE:
+    break;
+
+  case DYING:
+    return true;
+
+  default:
+    NS_ERROR("Unexpected state");
+    return false;
+  };
+
+  mNPP->mNPNIface->destroystream(mNPP->mNPP, mStream, reason);
+  return true;
+}
+
+void
+BrowserStreamParent::NPP_DestroyStream(NPReason reason)
+{
+  NS_ASSERTION(ALIVE == mState, "NPP_DestroyStream called twice?");
+  mState = DYING;
+  SendNPP_DestroyStream(reason);
+}
+
+bool
+BrowserStreamParent::RecvStreamDestroyed()
+{
+  if (DYING != mState) {
+    NS_ERROR("Unexpected state");
+    return false;
+  }
+
+  mState = DELETING;
+  Send__delete__(this);
+  return true;
+}
+
+int32_t
+BrowserStreamParent::WriteReady()
+{
+  return kSendDataChunk;
+}
+
+int32_t
+BrowserStreamParent::Write(int32_t offset,
+                           int32_t len,
+                           void* buffer)
+{
+  PLUGIN_LOG_DEBUG_FUNCTION;
+
+  NS_ASSERTION(ALIVE == mState, "Sending data after NPP_DestroyStream?");
+  NS_ASSERTION(len > 0, "Non-positive length to NPP_Write");
+
+  if (len > kSendDataChunk)
+    len = kSendDataChunk;
+
+  SendWrite(offset,
+    nsCString(static_cast<char*>(buffer), len),
+    mStream->end);
+
+  return len;
+}
+
+void
+BrowserStreamParent::StreamAsFile(const char* fname)
+{
+  PLUGIN_LOG_DEBUG_FUNCTION;
+
+  NS_ASSERTION(ALIVE == mState,
+               "Calling streamasfile after NPP_DestroyStream?");
+
+  CallNPP_StreamAsFile(nsCString(fname));
+  return;
+}
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/BrowserStreamParent.h
@@ -0,0 +1,90 @@
+/* -*- 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 Plugins.
+ *
+ * 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 ***** */
+
+#ifndef mozilla_plugins_BrowserStreamParent_h
+#define mozilla_plugins_BrowserStreamParent_h
+
+#include "mozilla/plugins/PBrowserStreamParent.h"
+#include "mozilla/plugins/AStream.h"
+
+namespace mozilla {
+namespace plugins {
+
+class PluginInstanceParent;
+
+class BrowserStreamParent : public PBrowserStreamParent, public AStream
+{
+  friend class PluginModuleParent;
+  friend class PluginInstanceParent;
+
+public:
+  BrowserStreamParent(PluginInstanceParent* npp,
+                      NPStream* stream);
+  virtual ~BrowserStreamParent();
+
+  NS_OVERRIDE virtual bool IsBrowserStream() { return true; }
+
+  virtual bool AnswerNPN_RequestRead(const IPCByteRanges& ranges,
+                                     NPError* result);
+
+  virtual bool RecvNPN_DestroyStream(const NPReason& reason);
+
+  virtual bool RecvStreamDestroyed();
+
+  int32_t WriteReady();
+  int32_t Write(int32_t offset, int32_t len, void* buffer);
+  void StreamAsFile(const char* fname);
+
+  void NPP_DestroyStream(NPReason reason);
+
+private:
+  using PBrowserStreamParent::SendNPP_DestroyStream;
+
+  PluginInstanceParent* mNPP;
+  NPStream* mStream;
+
+  enum {
+    ALIVE,
+    DYING,
+    DELETING
+  } mState;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ChildAsyncCall.cpp
@@ -0,0 +1,73 @@
+/* -*- 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 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ChildAsyncCall.h"
+#include "PluginInstanceChild.h"
+
+namespace mozilla {
+namespace plugins {
+
+ChildAsyncCall::ChildAsyncCall(PluginInstanceChild* instance,
+                               PluginThreadCallback aFunc, void* aUserData)
+  : mInstance(instance)
+  , mFunc(aFunc)
+  , mData(aUserData)
+{
+}
+
+void
+ChildAsyncCall::Cancel()
+{
+  mInstance = NULL;
+  mFunc = NULL;
+  mData = NULL;
+}
+
+void
+ChildAsyncCall::Run()
+{
+  if (mFunc) {
+    mInstance->mPendingAsyncCalls.RemoveElement(this);
+    mFunc(mData);
+  }
+}
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ChildAsyncCall.h
@@ -0,0 +1,72 @@
+/* -*- 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 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_plugins_ChildAsyncCall_h
+#define mozilla_plugins_ChildAsyncCall_h
+
+#include "PluginMessageUtils.h"
+#include "base/task.h"
+
+namespace mozilla {
+namespace plugins {
+
+typedef void (*PluginThreadCallback)(void*);
+
+class PluginInstanceChild;
+
+class ChildAsyncCall : public CancelableTask
+{
+public:
+  ChildAsyncCall(PluginInstanceChild* instance,
+                 PluginThreadCallback aFunc, void* aUserData);
+
+  NS_OVERRIDE void Run();
+  NS_OVERRIDE void Cancel();
+
+private:
+  PluginInstanceChild* mInstance;
+  PluginThreadCallback mFunc;
+  void* mData;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // mozilla_plugins_ChildAsyncCall_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/Makefile.in
@@ -0,0 +1,130 @@
+# ***** 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 Plugins.
+#
+# 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 *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = dom
+
+EXPORTS_NAMESPACES = mozilla
+
+EXPORTS_mozilla = \
+  PluginLibrary.h \
+  PluginPRLibrary.h \
+  $(NULL)
+
+ifdef MOZ_IPC
+
+EXPORTS_NAMESPACES = mozilla mozilla/plugins
+
+EXPORTS_mozilla/plugins = \
+  BrowserStreamChild.h \
+  BrowserStreamParent.h \
+  ChildAsyncCall.h \
+  NPEventOSX.h \
+  NPEventWindows.h \
+  NPEventX11.h \
+  PluginIdentifierChild.h \
+  PluginIdentifierParent.h \
+  PluginInstanceChild.h \
+  PluginInstanceParent.h \
+  PluginMessageUtils.h \
+  PluginModuleChild.h \
+  PluginModuleParent.h \
+  PluginProcessParent.h \
+  PluginScriptableObjectChild.h \
+  PluginScriptableObjectParent.h \
+  PluginScriptableObjectUtils.h \
+  PluginScriptableObjectUtils-inl.h \
+  PluginInstanceChild.h \
+  PluginInstanceParent.h \
+  AStream.h \
+  BrowserStreamChild.h \
+  BrowserStreamParent.h \
+  PluginStreamChild.h \
+  PluginStreamParent.h \
+  PluginMessageUtils.h \
+  PluginProcessParent.h \
+  PluginThreadChild.h \
+  StreamNotifyChild.h \
+  StreamNotifyParent.h \
+  $(NULL)
+
+MODULE           = dom
+LIBRARY_NAME     = domplugins_s
+LIBXUL_LIBRARY   = 1
+FORCE_STATIC_LIB = 1
+EXPORT_LIBRARY = 1
+ENABLE_CXX_EXCEPTIONS = 1
+
+CPPSRCS = \
+  ChildAsyncCall.cpp \
+  PluginMessageUtils.cpp \
+  PluginInstanceChild.cpp \
+  PluginInstanceParent.cpp \
+  PluginModuleChild.cpp \
+  PluginModuleParent.cpp \
+  PluginProcessParent.cpp \
+  PluginScriptableObjectChild.cpp \
+  PluginScriptableObjectParent.cpp \
+  BrowserStreamChild.cpp \
+  BrowserStreamParent.cpp \
+  PluginStreamChild.cpp \
+  PluginStreamParent.cpp \
+  PluginThreadChild.cpp \
+  $(NULL)
+
+LOCAL_INCLUDES = \
+  -I$(topsrcdir)/modules/plugin/base/public/ \
+  -I$(topsrcdir)/modules/plugin/base/src/ \
+  -I$(topsrcdir)/toolkit/xre \
+  -I$(topsrcdir)/toolkit/crashreporter \
+  $(NULL)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+CXXFLAGS += $(TK_CFLAGS)
+
+DEFINES += -DFORCE_PR_LOG
new file mode 100644
--- /dev/null
+++ b/dom/plugins/NPEventOSX.h
@@ -0,0 +1,79 @@
+/* -*- 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 Plugin 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_plugins_NPEventOSX_h
+#define mozilla_dom_plugins_NPEventOSX_h 1
+
+
+#include "npapi.h"
+#include "IPC/IPCMessageUtils.h"
+
+#warning This is only a stub implementation IMPLEMENT ME
+
+namespace mozilla {
+namespace plugins {
+struct NPRemoteEvent {
+    NPEvent event;
+};
+}
+}
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::plugins::NPRemoteEvent>
+{
+    typedef mozilla::plugins::NPRemoteEvent paramType;
+
+    static void Write(Message* aMsg, const paramType& aParam)
+    {
+    }
+
+    static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+    {
+        return true;
+    }
+
+    static void Log(const paramType& aParam, std::wstring* aLog)
+    {
+    }
+};
+
+} // namespace IPC
+
+#endif // ifndef mozilla_dom_plugins_NPEventOSX_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/NPEventWindows.h
@@ -0,0 +1,172 @@
+/* -*- 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 Plugin 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_plugins_NPEventWindows_h
+#define mozilla_dom_plugins_NPEventWindows_h 1
+
+
+#include "npapi.h"
+namespace mozilla {
+
+namespace plugins {
+
+// We use an NPRemoteEvent struct so that we can store the extra data on
+// the stack so that we don't need to worry about managing the memory.
+struct NPRemoteEvent
+{
+    NPEvent event;
+    union {
+        RECT rect;
+        WINDOWPOS windowpos;
+    } lParamData;
+};
+
+}
+
+}
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::plugins::NPRemoteEvent>
+{
+    typedef mozilla::plugins::NPRemoteEvent paramType;
+
+    static void Write(Message* aMsg, const paramType& aParam)
+    {
+        // Make a non-const copy of aParam so that we can muck with
+        // its insides for tranport
+        paramType paramCopy;
+
+        paramCopy.event = aParam.event;
+
+        // We can't blindly ipc events because they may sometimes contain
+        // pointers to memory in the sending process. For example, the
+        // WM_IME_CONTROL with the IMC_GETCOMPOSITIONFONT message has lParam
+        // set to a pointer to a LOGFONT structure.
+        switch (paramCopy.event.event) {
+            case WM_WINDOWPOSCHANGED:
+                // The lParam paramter of WM_WINDOWPOSCHANGED holds a pointer to
+                // a WINDOWPOS structure that contains information about the
+                // window's new size and position
+                paramCopy.lParamData.windowpos = *(reinterpret_cast<WINDOWPOS*>(paramCopy.event.lParam));
+                break;
+            case WM_PAINT:
+                // The lParam paramter of WM_PAINT holds a pointer to an RECT
+                // structure specifying the bounding box of the update area.
+                paramCopy.lParamData.rect = *(reinterpret_cast<RECT*>(paramCopy.event.lParam));
+                break;
+
+            // the white list of events that we will ipc to the client
+            case WM_CHAR:
+            case WM_SYSCHAR:
+
+            case WM_KEYUP:
+            case WM_SYSKEYUP:
+
+            case WM_KEYDOWN:
+            case WM_SYSKEYDOWN:
+
+            case WM_DEADCHAR:
+            case WM_SYSDEADCHAR:
+            case WM_CONTEXTMENU:
+
+            case WM_CUT:
+            case WM_COPY:
+            case WM_PASTE:
+            case WM_CLEAR:
+            case WM_UNDO:
+
+            case WM_MOUSELEAVE:
+            case WM_MOUSEMOVE:
+            case WM_LBUTTONDOWN:
+            case WM_MBUTTONDOWN:
+            case WM_RBUTTONDOWN:
+            case WM_LBUTTONUP:
+            case WM_MBUTTONUP:
+            case WM_RBUTTONUP:
+            case WM_LBUTTONDBLCLK:
+            case WM_MBUTTONDBLCLK:
+            case WM_RBUTTONDBLCLK:
+
+            case WM_SETFOCUS:
+            case WM_KILLFOCUS:
+                break;
+
+            default:
+                // RegisterWindowMessage events should be passed.
+                if (paramCopy.event.event >= 0xC000 && paramCopy.event.event <= 0xFFFF)
+                    break;
+
+                // ignore any events we don't expect
+                return;
+        }
+
+        aMsg->WriteBytes(&paramCopy, sizeof(paramType));
+    }
+
+    static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+    {
+        const char* bytes = 0;
+
+        if (!aMsg->ReadBytes(aIter, &bytes, sizeof(paramType))) {
+            return false;
+        }
+        memcpy(aResult, bytes, sizeof(paramType));
+
+        if (aResult->event.event == WM_PAINT) {
+            // restore the lParam to point at the RECT
+            aResult->event.lParam = reinterpret_cast<LPARAM>(&aResult->lParamData.rect);
+        } else if (aResult->event.event == WM_WINDOWPOSCHANGED) {
+            // restore the lParam to point at the WINDOWPOS
+            aResult->event.lParam = reinterpret_cast<LPARAM>(&aResult->lParamData.windowpos);
+        }
+
+        return true;
+    }
+
+    static void Log(const paramType& aParam, std::wstring* aLog)
+    {
+        aLog->append(L"(WINEvent)");
+    }
+
+};
+
+} // namespace IPC
+
+#endif // ifndef mozilla_dom_plugins_NPEventWindows_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/NPEventX11.h
@@ -0,0 +1,158 @@
+/* -*- 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 Plugin 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):
+ *   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 mozilla_dom_plugins_NPEventX11_h
+#define mozilla_dom_plugins_NPEventX11_h 1
+
+#if defined(MOZ_WIDGET_GTK2)
+#  include <gdk/gdkx.h>
+#elif defined(MOZ_WIDGET_QT)
+// X11/X.h has #define CursorShape 0, but Qt's qnamespace.h defines
+//   enum CursorShape { ... }.  Good times!
+#  undef CursorShape
+#  include <QX11Info>
+#else
+#  error Implement me for your toolkit
+#endif
+
+#include "npapi.h"
+
+namespace mozilla {
+
+namespace plugins {
+
+struct NPRemoteEvent {
+    NPEvent event;
+};
+
+}
+
+}
+
+
+//
+// XEvent is defined as a union of all more specific X*Events.
+// Luckily, as of xorg 1.6.0 / X protocol 11 rev 0, the only pointer
+// field contained in any of these specific X*Event structs is a
+// |Display*|.  So to simplify serializing these XEvents, we make the
+// 
+// ********** XXX ASSUMPTION XXX **********
+//
+// that the process to which the event is forwarded shares the same
+// display as the process on which the event originated.
+//
+// With this simplification, serialization becomes a simple memcpy to
+// the output stream.  Deserialization starts as just a memcpy from
+// the input stream, BUT we then have to write the correct |Display*|
+// into the right field of each X*Event that contains one.
+//
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::plugins::NPRemoteEvent>     // synonym for XEvent
+{
+    typedef mozilla::plugins::NPRemoteEvent paramType;
+
+    static void Write(Message* aMsg, const paramType& aParam)
+    {
+        aMsg->WriteBytes(&aParam, sizeof(paramType));
+    }
+
+    static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+    {
+        const char* bytes = 0;
+
+        if (!aMsg->ReadBytes(aIter, &bytes, sizeof(paramType))) {
+            return false;
+        }
+
+        memcpy(aResult, bytes, sizeof(paramType));
+        SetXDisplay(aResult->event);
+        return true;
+    }
+
+    static void Log(const paramType& aParam, std::wstring* aLog)
+    {
+        // TODO
+        aLog->append(L"(XEvent)");
+    }
+
+private:
+    static Display* GetXDisplay(const XAnyEvent& ev)
+    {
+        // TODO: get Display* from Window in |ev|
+
+        // FIXME: do this using Xlib
+#if defined(MOZ_WIDGET_GTK2)
+        return GDK_DISPLAY();
+#elif defined(MOZ_WIDGET_QT)
+        return QX11Info::display();
+#endif
+    }
+
+    static Display* GetXDisplay(const XErrorEvent& ev)
+    {
+        // TODO: get Display* from Window in |ev|
+
+        // FIXME: do this using Xlib
+#if defined(MOZ_WIDGET_GTK2)
+        return GDK_DISPLAY();
+#elif defined(MOZ_WIDGET_QT)
+        return QX11Info::display();
+#endif
+    }
+
+    static void SetXDisplay(XEvent& ev)
+    {
+        if (ev.type >= KeyPress) {
+            ev.xany.display = GetXDisplay(ev.xany);
+        }
+        else {
+            // XXX assuming that this is an error event
+            // (type == 0? not clear from Xlib.h)
+            ev.xerror.display = GetXDisplay(ev.xerror);
+        }
+    }
+};
+
+} // namespace IPC
+
+
+#endif // ifndef mozilla_dom_plugins_NPEventX11_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PBrowserStream.ipdl
@@ -0,0 +1,101 @@
+/* -*- 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 Plugins.
+ *
+ * The Initial Developer of the Original Code is
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ * 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 "PPluginInstance.ipdl";
+
+include "mozilla/plugins/PluginMessageUtils.h";
+
+using mozilla::plugins::Buffer;
+using mozilla::plugins::IPCByteRanges;
+
+using NPError;
+using NPReason;
+
+namespace mozilla {
+namespace plugins {
+
+/**
+ * NPBrowserStream represents a NPStream sent from the browser to the plugin.
+ */
+
+rpc protocol PBrowserStream
+{
+  manager PPluginInstance;
+
+child:
+  async Write(int32_t offset, Buffer data,
+              uint32_t newlength);
+  rpc NPP_StreamAsFile(nsCString fname);
+
+  /**
+   * NPP_DestroyStream may race with other messages: the child acknowledges
+   * the message with StreamDestroyed before this actor is deleted.
+   */
+  async NPP_DestroyStream(NPReason reason);
+  async __delete__();
+
+parent:
+  rpc NPN_RequestRead(IPCByteRanges ranges)
+    returns (NPError result);
+  async NPN_DestroyStream(NPReason reason);
+  async StreamDestroyed();
+
+/*
+  TODO: turn on state machine.
+
+  // need configurable start state: if the constructor
+  // returns an error in result, start state should
+  // be DELETING.
+start state ALIVE:
+  send Write goto ALIVE;
+  call NPP_StreamAsFile goto ALIVE;
+  send NPP_DestroyStream goto ALIVE;
+  answer NPN_RequestRead goto ALIVE;
+  recv NPN_DestroyStream goto DYING;
+
+state DYING:
+  answer NPN_RequestRead goto DYING;
+  recv NPN_DestroyStream goto DYING;
+  recv StreamDestroyed goto DELETING;
+
+state DELETING:
+  send __delete__;
+*/
+};
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PPluginIdentifier.ipdl
@@ -0,0 +1,56 @@
+/* -*- 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 Plugins.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Turner <bent.mozilla@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 "PPluginModule.ipdl";
+
+namespace mozilla {
+namespace plugins {
+
+/**
+ * Represents an NPIdentifier that wraps either a string or an integer.
+ */
+async protocol PPluginIdentifier
+{
+  manager PPluginModule;
+
+child:
+  async __delete__();
+};
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PPluginInstance.ipdl
@@ -0,0 +1,174 @@
+/* -*- 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 Plugins.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ *   Ben Turner <bent.mozilla@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 "PPluginModule.ipdl";
+include protocol "PPluginScriptableObject.ipdl";
+include protocol "PBrowserStream.ipdl";
+include protocol "PPluginStream.ipdl";
+include protocol "PStreamNotify.ipdl";
+
+include "mozilla/plugins/PluginMessageUtils.h";
+
+using NPError;
+using NPRemoteWindow;
+using NPRemoteEvent;
+using NPRect;
+using NPNURLVariable;
+using mozilla::plugins::NativeWindowHandle;
+
+namespace mozilla {
+namespace plugins {
+
+rpc protocol PPluginInstance
+{
+  manager PPluginModule;
+
+  manages PPluginScriptableObject;
+  manages PBrowserStream;
+  manages PPluginStream;
+  manages PStreamNotify;
+
+child:
+  rpc __delete__();
+
+  rpc NPP_SetWindow(NPRemoteWindow window);
+
+  // this message is not used on non-X platforms
+  rpc NPP_GetValue_NPPVpluginNeedsXEmbed()
+    returns (bool value, NPError result);
+  rpc NPP_GetValue_NPPVpluginScriptableNPObject()
+    returns (nullable PPluginScriptableObject value, NPError result);
+
+  rpc NPP_SetValue_NPNVprivateModeBool(bool value) returns (NPError result);
+
+  rpc NPP_HandleEvent(NPRemoteEvent event)
+    returns (int16_t handled);
+  // special cases of HandleEvent to make mediating races simpler
+  rpc Paint(NPRemoteEvent event)
+    returns (int16_t handled);
+  // this is only used on windows to forward WM_WINDOWPOSCHANGE
+  async WindowPosChanged(NPRemoteEvent event);
+
+  rpc NPP_Destroy()
+    returns (NPError rv);
+
+parent:
+  rpc NPN_GetValue_NPNVjavascriptEnabledBool()
+    returns (bool value, NPError result);
+  rpc NPN_GetValue_NPNVisOfflineBool()
+    returns (bool value, NPError result);
+  rpc NPN_GetValue_NPNVWindowNPObject()
+    returns (nullable PPluginScriptableObject value, NPError result);
+  rpc NPN_GetValue_NPNVPluginElementNPObject()
+    returns (nullable PPluginScriptableObject value, NPError result);
+  rpc NPN_GetValue_NPNVprivateModeBool()
+    returns (bool value, NPError result);
+  rpc NPN_GetValue_NPNVnetscapeWindow()
+    returns (NativeWindowHandle value, NPError result);
+
+  rpc NPN_SetValue_NPPVpluginWindow(bool windowed)
+    returns (NPError result);
+  rpc NPN_SetValue_NPPVpluginTransparent(bool transparent)
+    returns (NPError result);
+
+  rpc NPN_GetURL(nsCString url, nsCString target)
+    returns (NPError result);
+  rpc NPN_PostURL(nsCString url, nsCString target, nsCString buffer, bool file)
+    returns (NPError result);
+
+  /**
+   * Covers both NPN_GetURLNotify and NPN_PostURLNotify.
+   * @TODO This would be more readable as an overloaded method,
+   *       but IPDL doesn't allow that for constructors.
+   */
+  rpc PStreamNotify(nsCString url, nsCString target, bool post,
+                    nsCString buffer, bool file)
+    returns (NPError result);
+
+  async NPN_InvalidateRect(NPRect rect);
+
+  rpc NPN_PushPopupsEnabledState(bool aState)
+    returns (bool aSuccess);
+
+  rpc NPN_PopPopupsEnabledState()
+    returns (bool aSuccess);
+
+  rpc NPN_GetValueForURL(NPNURLVariable variable, nsCString url)
+    returns (nsCString value, NPError result);
+
+  rpc NPN_SetValueForURL(NPNURLVariable variable, nsCString url,
+                         nsCString value)
+    returns (NPError result);
+
+  rpc NPN_GetAuthenticationInfo(nsCString protocol_, nsCString host,
+                                int32_t port, nsCString scheme,
+                                nsCString realm)
+    returns (nsCString username, nsCString password, NPError result);
+
+both:
+  async PPluginScriptableObject();
+
+child:
+  /* NPP_NewStream */
+  rpc PBrowserStream(nsCString url,
+                     uint32_t length,
+                     uint32_t lastmodified,
+                     nullable PStreamNotify notifyData,
+                     nsCString headers,
+                     nsCString mimeType,
+                     bool seekable)
+    returns (NPError rv,
+             uint16_t stype);
+
+parent:
+  /* NPN_NewStream */
+  rpc PPluginStream(nsCString mimeType,
+                    nsCString target)
+    returns (NPError result);
+
+parent:
+  rpc PluginGotFocus();
+  sync SetNestedEventState(bool aState);
+child:
+  rpc SetPluginFocus();
+  rpc UpdateWindow();
+};
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PPluginModule.ipdl
@@ -0,0 +1,102 @@
+/* -*- 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 Plugins.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ *   Ben Turner <bent.mozilla@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 "PPluginIdentifier.ipdl";
+include protocol "PPluginInstance.ipdl";
+
+include "npapi.h";
+include "mozilla/plugins/PluginMessageUtils.h";
+
+using NPError;
+using NPNVariable;
+using mozilla::plugins::NativeThreadId;
+
+namespace mozilla {
+namespace plugins {
+
+rpc protocol PPluginModule
+{
+  manages PPluginInstance;
+  manages PPluginIdentifier;
+
+both:
+  /**
+   * Sending a void string to this constructor creates an int identifier whereas
+   * sending a non-void string will create a string identifier. This constructor
+   * may be called by either child or parent. If a race occurs by calling the
+   * constructor with the same string or int argument then we create two actors
+   * and detect the second instance in the child. We prevent the parent's actor
+   * from leaking out to plugin code and only allow the child's to be used.
+   */
+  async PPluginIdentifier(nsCString aString,
+                          int32_t aInt);
+
+child:
+  // Return the plugin's thread ID, if it can be found.
+  rpc NP_Initialize()
+    returns (NativeThreadId tid, NPError rv);
+
+  rpc PPluginInstance(nsCString aMimeType,
+                      uint16_t aMode,
+                      nsCString[] aNames,
+                      nsCString[] aValues)
+    returns (NPError rv);
+
+  rpc NP_Shutdown()
+    returns (NPError rv);
+
+parent:
+  rpc NPN_UserAgent()
+    returns (nsCString userAgent);
+
+  rpc NPN_GetValue_WithBoolReturn(NPNVariable aVariable)
+    returns (NPError aError,
+             bool aBoolVal);
+
+  // Wake up and process a few native events.  Periodically called by
+  // Gtk-specific code upon detecting that the plugin process has
+  // entered a nested event loop.  If the browser doesn't process
+  // native events, then "livelock" and some other glitches can occur.
+  rpc ProcessSomeEvents();
+
+  sync AppendNotesToCrashReport(nsCString aNotes);
+};
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PPluginScriptableObject.ipdl
@@ -0,0 +1,126 @@
+/* -*- 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 Plugins.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ *   Ben Turner <bent.mozilla@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 "PPluginInstance.ipdl";
+include protocol "PPluginIdentifier.ipdl";
+
+include "npapi.h";
+include "npruntime.h";
+include "mozilla/plugins/PluginMessageUtils.h";
+
+using mozilla::void_t;
+using mozilla::null_t;
+
+namespace mozilla {
+namespace plugins {
+
+union Variant {
+  void_t;
+  null_t;
+  bool;
+  int;
+  double;
+  nsCString;
+  nullable PPluginScriptableObject;
+};
+
+rpc protocol PPluginScriptableObject
+{
+  manager PPluginInstance;
+
+both:
+  async __delete__();
+
+parent:
+  rpc NPN_Evaluate(nsCString aScript)
+    returns (Variant aResult,
+             bool aSuccess);
+
+child:
+  rpc Invalidate();
+
+both:
+  // NPClass methods
+  rpc HasMethod(PPluginIdentifier aId)
+    returns (bool aHasMethod);
+
+  rpc Invoke(PPluginIdentifier aId,
+             Variant[] aArgs)
+    returns (Variant aResult,
+             bool aSuccess);
+
+  rpc InvokeDefault(Variant[] aArgs)
+    returns (Variant aResult,
+             bool aSuccess);
+
+  rpc HasProperty(PPluginIdentifier aId)
+    returns (bool aHasProperty);
+
+  rpc GetProperty(PPluginIdentifier aId)
+    returns (Variant aResult,
+             bool aSuccess);
+
+  rpc SetProperty(PPluginIdentifier aId,
+                  Variant aValue)
+    returns (bool aSuccess);
+
+  rpc RemoveProperty(PPluginIdentifier aId)
+    returns (bool aSuccess);
+
+  rpc Enumerate()
+    returns (PPluginIdentifier[] aProperties,
+             bool aSuccess);
+
+  rpc Construct(Variant[] aArgs)
+    returns (Variant aResult,
+             bool aSuccess);
+
+  // Objects are initially unprotected, and the Protect and Unprotect functions
+  // only affect protocol objects that represent NPObjects created in the same
+  // process (rather than protocol objects that are a proxy for an NPObject
+  // created in another process). Protocol objects representing local NPObjects
+  // are protected after an NPObject has been associated with the protocol
+  // object. Sending the protocol object as an argument to the other process
+  // temporarily protects the protocol object again for the duration of the call.
+  async Protect();
+  async Unprotect();
+};
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PPluginStream.ipdl
@@ -0,0 +1,70 @@
+/* -*- 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 Plugins.
+ *
+ * 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 ***** */
+
+include protocol "PPluginInstance.ipdl";
+
+include "mozilla/plugins/PluginMessageUtils.h";
+
+using mozilla::plugins::Buffer;
+using NPError;
+using NPReason;
+
+namespace mozilla {
+namespace plugins {
+
+/**
+ * PPluginStream represents an NPStream sent from the plugin to the browser.
+ */
+
+rpc protocol PPluginStream
+{
+  manager PPluginInstance;
+
+parent:
+  rpc NPN_Write(Buffer data) returns (int32_t written);
+
+both:
+  /**
+   * ~PPluginStream is for both NPN_DestroyStream and NPP_DestroyStream.
+   * @param artificial True when the stream is closed as a by-product of
+   *                        some other call (such as a failure in NPN_Write).
+   */
+  rpc __delete__(NPReason reason, bool artificial);
+};
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PStreamNotify.ipdl
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+
+include protocol "PPluginInstance.ipdl";
+
+include "npapi.h";
+
+using NPReason;
+
+namespace mozilla {
+namespace plugins {
+
+/**
+ * This empty protocol exists only to be constructed and destroyed.
+ */
+rpc protocol PStreamNotify
+{
+  manager PPluginInstance;
+
+child:
+  /**
+   * Represents NPP_URLNotify
+   */
+  async __delete__(NPReason reason);
+};
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginIdentifierChild.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 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 Plugins.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Turner <bent.mozilla@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_plugins_PluginIdentifierChild_h
+#define dom_plugins_PluginIdentifierChild_h
+
+#include "mozilla/plugins/PPluginIdentifierChild.h"
+#include "mozilla/plugins/PluginModuleChild.h"
+
+#include "nsStringGlue.h"
+
+namespace mozilla {
+namespace plugins {
+
+class PluginIdentifierChild : public PPluginIdentifierChild
+{
+  friend class PluginModuleChild;
+public:
+  bool IsString()
+  {
+    return reinterpret_cast<intptr_t>(mCanonicalIdentifier) & 1;
+  }
+
+  NPIdentifier ToNPIdentifier()
+  {
+    return reinterpret_cast<PluginIdentifierChild*>(
+      reinterpret_cast<intptr_t>(mCanonicalIdentifier) & ~1);
+  }
+
+protected:
+  PluginIdentifierChild(bool aIsString)
+    : ALLOW_THIS_IN_INITIALIZER_LIST(mCanonicalIdentifier(this))
+  {
+    MOZ_COUNT_CTOR(PluginIdentifierChild);
+    if (aIsString) {
+      SetIsString();
+    }
+  }
+
+  virtual ~PluginIdentifierChild()
+  {
+    MOZ_COUNT_DTOR(PluginIdentifierChild);
+  }
+
+  void SetCanonicalIdentifier(PluginIdentifierChild* aIdentifier)
+  {
+    NS_ASSERTION(ToNPIdentifier() == this, "Already got one!");
+    bool isString = IsString();
+    mCanonicalIdentifier = aIdentifier;
+    if (isString) {
+      SetIsString();
+    }
+  }
+
+private:
+  void SetIsString()
+  {
+    mCanonicalIdentifier = reinterpret_cast<PluginIdentifierChild*>(
+      reinterpret_cast<intptr_t>(mCanonicalIdentifier) | 1);
+  }
+
+  PluginIdentifierChild* mCanonicalIdentifier;
+};
+
+class PluginIdentifierChildString : public PluginIdentifierChild
+{
+  friend class PluginModuleChild;
+public:
+  NPUTF8* ToString()
+  {
+    return ToNewCString(mString);
+  }
+
+protected:
+  PluginIdentifierChildString(const nsCString& aString)
+    : PluginIdentifierChild(true),
+      mString(aString)
+  { }
+
+  nsCString mString;
+};
+
+class PluginIdentifierChildInt : public PluginIdentifierChild
+{
+  friend class PluginModuleChild;
+public:
+  int32_t ToInt()
+  {
+    return mInt;
+  }
+
+protected:
+  PluginIdentifierChildInt(int32_t aInt)
+    : PluginIdentifierChild(false),
+      mInt(aInt)
+  { }
+
+  int32_t mInt;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // dom_plugins_PluginIdentifierChild_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginIdentifierParent.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 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 Plugins.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Turner <bent.mozilla@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_plugins_PluginIdentifierParent_h
+#define dom_plugins_PluginIdentifierParent_h
+
+#include "mozilla/plugins/PPluginIdentifierParent.h"
+
+#include "npapi.h"
+#include "npruntime.h"
+
+namespace mozilla {
+namespace plugins {
+
+class PluginIdentifierParent : public PPluginIdentifierParent
+{
+  friend class PluginModuleParent;
+
+public:
+  NPIdentifier ToNPIdentifier()
+  {
+    return mIdentifier;
+  }
+
+protected:
+  PluginIdentifierParent(NPIdentifier aIdentifier)
+    : mIdentifier(aIdentifier)
+  {
+    MOZ_COUNT_CTOR(PluginIdentifierParent);
+  }
+
+  virtual ~PluginIdentifierParent()
+  {
+    MOZ_COUNT_DTOR(PluginIdentifierParent);
+  }
+
+private:
+  NPIdentifier mIdentifier;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // dom_plugins_PluginIdentifierParent_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -0,0 +1,1656 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jim Mathies <jmathies@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 ***** */
+
+#include "PluginInstanceChild.h"
+#include "PluginModuleChild.h"
+#include "BrowserStreamChild.h"
+#include "PluginStreamChild.h"
+#include "StreamNotifyChild.h"
+
+#include "mozilla/ipc/SyncChannel.h"
+
+using namespace mozilla::plugins;
+
+#ifdef MOZ_WIDGET_GTK2
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+#include "gtk2xtbin.h"
+
+#elif defined(MOZ_WIDGET_QT)
+#include <QX11Info>
+#elif defined(OS_WIN)
+
+#include "nsWindowsDllInterceptor.h"
+
+typedef BOOL (WINAPI *User32TrackPopupMenu)(HMENU hMenu,
+                                            UINT uFlags,
+                                            int x,
+                                            int y,
+                                            int nReserved,
+                                            HWND hWnd,
+                                            CONST RECT *prcRect);
+static WindowsDllInterceptor sUser32Intercept;
+static HWND sWinlessPopupSurrogateHWND = NULL;
+static User32TrackPopupMenu sUser32TrackPopupMenuStub = NULL;
+
+using mozilla::gfx::SharedDIB;
+
+#include <windows.h>
+#include <windowsx.h>
+
+#define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg")
+
+#endif // defined(OS_WIN)
+
+PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
+                                         const nsCString& aMimeType)
+    : mPluginIface(aPluginIface)
+    , mQuirks(0)
+    , mCachedWindowActor(nsnull)
+    , mCachedElementActor(nsnull)
+#if defined(OS_WIN)
+    , mPluginWindowHWND(0)
+    , mPluginWndProc(0)
+    , mPluginParentHWND(0)
+    , mNestedEventHook(0)
+    , mNestedEventLevelDepth(0)
+    , mNestedEventState(false)
+    , mCachedWinlessPluginHWND(0)
+    , mWinlessPopupSurrogateHWND(0)
+#endif // OS_WIN
+{
+    memset(&mWindow, 0, sizeof(mWindow));
+    mData.ndata = (void*) this;
+    mData.pdata = nsnull;
+#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
+    mWindow.ws_info = &mWsInfo;
+    memset(&mWsInfo, 0, sizeof(mWsInfo));
+#ifdef MOZ_WIDGET_GTK2
+    mWsInfo.display = GDK_DISPLAY();
+#elif defined(MOZ_WIDGET_QT)
+    mWsInfo.display = QX11Info::display();
+#endif // MOZ_WIDGET_GTK2
+#endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
+#if defined(OS_WIN)
+    memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
+    mAlphaExtract.doublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID);
+#endif // OS_WIN
+    InitQuirksModes(aMimeType);
+#if defined(OS_WIN)
+    InitPopupMenuHook();
+#endif // OS_WIN
+}
+
+PluginInstanceChild::~PluginInstanceChild()
+{
+#if defined(OS_WIN)
+  DestroyPluginWindow();
+#endif
+}
+
+void
+PluginInstanceChild::InitQuirksModes(const nsCString& aMimeType)
+{
+#ifdef OS_WIN
+    // application/x-silverlight
+    // application/x-silverlight-2
+    NS_NAMED_LITERAL_CSTRING(silverlight, "application/x-silverlight");
+    // application/x-shockwave-flash
+    NS_NAMED_LITERAL_CSTRING(flash, "application/x-shockwave-flash");
+    if (FindInReadable(silverlight, aMimeType)) {
+        mQuirks |= QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION;
+        mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
+    }
+    else if (FindInReadable(flash, aMimeType)) {
+        mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
+    }
+#endif
+}
+
+NPError
+PluginInstanceChild::InternalGetNPObjectForValue(NPNVariable aValue,
+                                                 NPObject** aObject)
+{
+    PluginScriptableObjectChild* actor;
+    NPError result = NPERR_NO_ERROR;
+
+    switch (aValue) {
+        case NPNVWindowNPObject:
+            if (!(actor = mCachedWindowActor)) {
+                PPluginScriptableObjectChild* actorProtocol;
+                CallNPN_GetValue_NPNVWindowNPObject(&actorProtocol, &result);
+                if (result == NPERR_NO_ERROR) {
+                    actor = mCachedWindowActor =
+                        static_cast<PluginScriptableObjectChild*>(actorProtocol);
+                    NS_ASSERTION(actor, "Null actor!");
+                    PluginModuleChild::sBrowserFuncs.retainobject(
+                        actor->GetObject(false));
+                }
+            }
+            break;
+
+        case NPNVPluginElementNPObject:
+            if (!(actor = mCachedElementActor)) {
+                PPluginScriptableObjectChild* actorProtocol;
+                CallNPN_GetValue_NPNVPluginElementNPObject(&actorProtocol,
+                                                           &result);
+                if (result == NPERR_NO_ERROR) {
+                    actor = mCachedElementActor =
+                        static_cast<PluginScriptableObjectChild*>(actorProtocol);
+                    NS_ASSERTION(actor, "Null actor!");
+                    PluginModuleChild::sBrowserFuncs.retainobject(
+                        actor->GetObject(false));
+                }
+            }
+            break;
+
+        default:
+            NS_NOTREACHED("Don't know what to do with this value type!");
+    }
+
+#ifdef DEBUG
+    {
+        NPError currentResult;
+        PPluginScriptableObjectChild* currentActor;
+
+        switch (aValue) {
+            case NPNVWindowNPObject:
+                CallNPN_GetValue_NPNVWindowNPObject(&currentActor,
+                                                    &currentResult);
+                break;
+            case NPNVPluginElementNPObject:
+                CallNPN_GetValue_NPNVPluginElementNPObject(&currentActor,
+                                                           &currentResult);
+                break;
+            default:
+                NS_NOTREACHED("Don't know what to do with this value type!");
+        }
+
+        // Make sure that the current actor returned by the parent matches our
+        // cached actor!
+        NS_ASSERTION(static_cast<PluginScriptableObjectChild*>(currentActor) ==
+                     actor, "Cached actor is out of date!");
+        NS_ASSERTION(currentResult == result, "Results don't match?!");
+    }
+#endif
+
+    if (result != NPERR_NO_ERROR) {
+        return result;
+    }
+
+    NPObject* object = actor->GetObject(false);
+    NS_ASSERTION(object, "Null object?!");
+
+    *aObject = PluginModuleChild::sBrowserFuncs.retainobject(object);
+    return NPERR_NO_ERROR;
+
+}
+
+NPError
+PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
+                                  void* aValue)
+{
+    PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar));
+    AssertPluginThread();
+
+    switch(aVar) {
+
+    case NPNVSupportsWindowless:
+#if defined(OS_LINUX) || defined(OS_WIN)
+        *((NPBool*)aValue) = true;
+#else
+        *((NPBool*)aValue) = false;
+#endif
+        return NPERR_NO_ERROR;
+
+#if defined(OS_LINUX)
+    case NPNVSupportsXEmbedBool:
+        *((NPBool*)aValue) = true;
+        return NPERR_NO_ERROR;
+
+    case NPNVToolkit:
+        *((NPNToolkitType*)aValue) = NPNVGtk2;
+        return NPERR_NO_ERROR;
+
+#elif defined(OS_WIN)
+    case NPNVToolkit:
+        return NPERR_GENERIC_ERROR;
+#endif
+    case NPNVjavascriptEnabledBool: {
+        bool v = false;
+        NPError result;
+        if (!CallNPN_GetValue_NPNVjavascriptEnabledBool(&v, &result)) {
+            return NPERR_GENERIC_ERROR;
+        }
+        *static_cast<NPBool*>(aValue) = v;
+        return result;
+    }
+
+    case NPNVisOfflineBool: {
+        bool v = false;
+        NPError result;
+        if (!CallNPN_GetValue_NPNVisOfflineBool(&v, &result)) {
+            return NPERR_GENERIC_ERROR;
+        }
+        *static_cast<NPBool*>(aValue) = v;
+        return result;
+    }
+
+    case NPNVprivateModeBool: {
+        bool v = false;
+        NPError result;
+        if (!CallNPN_GetValue_NPNVprivateModeBool(&v, &result)) {
+            return NPERR_GENERIC_ERROR;
+        }
+        *static_cast<NPBool*>(aValue) = v;
+        return result;
+    }
+
+    case NPNVWindowNPObject: // Intentional fall-through
+    case NPNVPluginElementNPObject: {
+        NPObject* object;
+        NPError result = InternalGetNPObjectForValue(aVar, &object);
+        if (result == NPERR_NO_ERROR) {
+            *((NPObject**)aValue) = object;
+        }
+        return result;
+    }
+
+    case NPNVnetscapeWindow: {
+#ifdef XP_WIN
+        if (mWindow.type == NPWindowTypeDrawable) {
+            if (mCachedWinlessPluginHWND) {
+              *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND;
+              return NPERR_NO_ERROR;
+            }
+            NPError result;
+            if (!CallNPN_GetValue_NPNVnetscapeWindow(&mCachedWinlessPluginHWND, &result)) {
+                return NPERR_GENERIC_ERROR;
+            }
+            *static_cast<HWND*>(aValue) = mCachedWinlessPluginHWND;
+            return result;
+        }
+        else {
+            *static_cast<HWND*>(aValue) = mPluginWindowHWND;
+            return NPERR_NO_ERROR;
+        }
+#elif defined(MOZ_X11)
+        NPError result;
+        CallNPN_GetValue_NPNVnetscapeWindow(static_cast<XID*>(aValue), &result);
+        return result;
+#else
+        return NPERR_GENERIC_ERROR;
+#endif
+    }
+
+    default:
+        PR_LOG(gPluginLog, PR_LOG_WARNING,
+               ("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)",
+                (int) aVar, NPNVariableToString(aVar)));
+        return NPERR_GENERIC_ERROR;
+    }
+
+}
+
+
+NPError
+PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
+{
+    PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s (aVar=%i, aValue=%p)",
+                                      FULLFUNCTION, (int) aVar, aValue));
+
+    AssertPluginThread();
+
+    switch (aVar) {
+    case NPPVpluginWindowBool: {
+        NPError rv;
+        bool windowed = (NPBool) (intptr_t) aValue;
+
+        if (!CallNPN_SetValue_NPPVpluginWindow(windowed, &rv))
+            return NPERR_GENERIC_ERROR;
+
+        return rv;
+    }
+
+    case NPPVpluginTransparentBool: {
+        NPError rv;
+        bool transparent = (NPBool) (intptr_t) aValue;
+
+        if (!CallNPN_SetValue_NPPVpluginTransparent(transparent, &rv))
+            return NPERR_GENERIC_ERROR;
+
+        return rv;
+    }
+
+    default:
+        PR_LOG(gPluginLog, PR_LOG_WARNING,
+               ("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)",
+                (int) aVar, NPPVariableToString(aVar)));
+        return NPERR_GENERIC_ERROR;
+    }
+}
+
+bool
+PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(
+    bool* needs, NPError* rv)
+{
+    AssertPluginThread();
+
+#ifdef MOZ_X11
+    // The documentation on the types for many variables in NP(N|P)_GetValue
+    // is vague.  Often boolean values are NPBool (1 byte), but
+    // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins
+    // treats NPPVpluginNeedsXEmbed as PRBool (int), and
+    // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|.
+    // thus we can't use NPBool for needsXEmbed, or the three bytes above
+    // it on the stack would get clobbered. so protect with the larger PRBool.
+    PRBool needsXEmbed = 0;
+    if (!mPluginIface->getvalue) {
+        *rv = NPERR_GENERIC_ERROR;
+    }
+    else {
+        *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginNeedsXEmbed,
+                                     &needsXEmbed);
+    }
+    *needs = needsXEmbed;
+    return true;
+
+#else
+
+    NS_RUNTIMEABORT("shouldn't be called on non-X11 platforms");
+    return false;               // not reached
+
+#endif
+}
+
+bool
+PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject(
+                                          PPluginScriptableObjectChild** aValue,
+                                          NPError* aResult)
+{
+    AssertPluginThread();
+
+    NPObject* object = nsnull;
+    NPError result = NPERR_GENERIC_ERROR;
+    if (mPluginIface->getvalue) {
+        result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject,
+                                        &object);
+    }
+    if (result == NPERR_NO_ERROR && object) {
+        PluginScriptableObjectChild* actor = GetActorForNPObject(object);
+
+        // If we get an actor then it has retained. Otherwise we don't need it
+        // any longer.
+        PluginModuleChild::sBrowserFuncs.releaseobject(object);
+        if (actor) {
+            *aValue = actor;
+            *aResult = NPERR_NO_ERROR;
+            return true;
+        }
+
+        NS_ERROR("Failed to get actor!");
+        result = NPERR_GENERIC_ERROR;
+    }
+    else {
+        result = NPERR_GENERIC_ERROR;
+    }
+
+    *aValue = nsnull;
+    *aResult = result;
+    return true;
+}
+
+bool
+PluginInstanceChild::AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value,
+                                                            NPError* result)
+{
+    if (!mPluginIface->setvalue) {
+        *result = NPERR_GENERIC_ERROR;
+        return true;
+    }
+
+    // Use `long` instead of NPBool because Flash and other plugins read
+    // this as a word-size value instead of the 1-byte NPBool that it is.
+    long v = value;
+    *result = mPluginIface->setvalue(GetNPP(), NPNVprivateModeBool, &v);
+    return true;
+}
+
+bool
+PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
+                                           int16_t* handled)
+{
+    PLUGIN_LOG_DEBUG_FUNCTION;
+    AssertPluginThread();
+
+#if defined(OS_LINUX) && defined(DEBUG)
+    if (GraphicsExpose == event.event.type)
+        PLUGIN_LOG_DEBUG(("  received drawable 0x%lx\n",
+                          event.event.xgraphicsexpose.drawable));
+#endif
+
+    // Make a copy since we may modify values.
+    NPEvent evcopy = event.event;
+
+#ifdef OS_WIN
+    // Painting for win32. SharedSurfacePaint handles everything.
+    if (mWindow.type == NPWindowTypeDrawable) {
+       if (evcopy.event == WM_PAINT) {
+          *handled = SharedSurfacePaint(evcopy);
+          return true;
+       }
+       else if (evcopy.event == mAlphaExtract.doublePassEvent) {
+            // We'll render to mSharedSurfaceDib first, then render to a cached bitmap
+            // we store locally. The two passes are for alpha extraction, so the second
+            // pass must be to a flat white surface in order for things to work.
+            mAlphaExtract.doublePass = RENDER_BACK_ONE;
+            *handled = true;
+            return true;
+       }
+    }
+    *handled = WinlessHandleEvent(evcopy);
+    return true;
+#endif
+
+    if (!mPluginIface->event)
+        *handled = false;
+    else
+        *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
+
+#ifdef MOZ_X11
+    if (GraphicsExpose == event.event.type) {
+        // Make sure the X server completes the drawing before the parent
+        // draws on top and destroys the Drawable.
+        //
+        // XSync() waits for the X server to complete.  Really this child
+        // process does not need to wait; the parent is the process that needs
+        // to wait.  A possibly-slightly-better alternative would be to send
+        // an X event to the parent that the parent would wait for.
+        XSync(mWsInfo.display, False);
+    }
+#endif
+
+    return true;
+}
+
+bool
+PluginInstanceChild::RecvWindowPosChanged(const NPRemoteEvent& event)
+{
+#ifdef OS_WIN
+    int16_t dontcare;
+    return AnswerNPP_HandleEvent(event, &dontcare);
+#else
+    NS_RUNTIMEABORT("WindowPosChanged is a windows-only message");
+    return false;
+#endif
+}
+
+
+#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
+static bool
+XVisualIDToInfo(Display* aDisplay, VisualID aVisualID,
+                Visual** aVisual, unsigned int* aDepth)
+{
+    if (aVisualID == None) {
+        *aVisual = NULL;
+        *aDepth = 0;
+        return true;
+    }
+
+    const Screen* screen = DefaultScreenOfDisplay(aDisplay);
+
+    for (int d = 0; d < screen->ndepths; d++) {
+        Depth *d_info = &screen->depths[d];
+        for (int v = 0; v < d_info->nvisuals; v++) {
+            Visual* visual = &d_info->visuals[v];
+            if (visual->visualid == aVisualID) {
+                *aVisual = visual;
+                *aDepth = d_info->depth;
+                return true;
+            }
+        }
+    }
+
+    NS_ERROR("VisualID not on Screen.");
+    return false;
+}
+#endif
+
+bool
+PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
+{
+    PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
+                      FULLFUNCTION,
+                      aWindow.window,
+                      aWindow.x, aWindow.y,
+                      aWindow.width, aWindow.height));
+    AssertPluginThread();
+
+#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
+    // The minimum info is sent over IPC to allow this
+    // code to determine the rest.
+
+    mWindow.window = reinterpret_cast<void*>(aWindow.window);
+    mWindow.x = aWindow.x;
+    mWindow.y = aWindow.y;
+    mWindow.width = aWindow.width;
+    mWindow.height = aWindow.height;
+    mWindow.clipRect = aWindow.clipRect;
+    mWindow.type = aWindow.type;
+
+    mWsInfo.colormap = aWindow.colormap;
+    if (!XVisualIDToInfo(mWsInfo.display, aWindow.visualID,
+                         &mWsInfo.visual, &mWsInfo.depth))
+        return false;
+
+    if (aWindow.type == NPWindowTypeWindow) {
+#ifdef MOZ_WIDGET_GTK2
+        if (GdkWindow* socket_window = gdk_window_lookup(aWindow.window)) {
+            // A GdkWindow for the socket already exists.  Need to
+            // workaround https://bugzilla.gnome.org/show_bug.cgi?id=607061
+            // See wrap_gtk_plug_embedded in PluginModuleChild.cpp.
+            g_object_set_data(G_OBJECT(socket_window),
+                              "moz-existed-before-set-window",
+                              GUINT_TO_POINTER(1));
+        }
+#endif
+    }
+
+    if (mPluginIface->setwindow)
+        (void) mPluginIface->setwindow(&mData, &mWindow);
+
+#elif defined(OS_WIN)
+    switch (aWindow.type) {
+      case NPWindowTypeWindow:
+      {
+          if (!CreatePluginWindow())
+              return false;
+
+          ReparentPluginWindow((HWND)aWindow.window);
+          SizePluginWindow(aWindow.width, aWindow.height);
+
+          mWindow.window = (void*)mPluginWindowHWND;
+          mWindow.x = aWindow.x;
+          mWindow.y = aWindow.y;
+          mWindow.width = aWindow.width;
+          mWindow.height = aWindow.height;
+          mWindow.type = aWindow.type;
+
+          if (mPluginIface->setwindow) {
+              (void) mPluginIface->setwindow(&mData, &mWindow);
+              WNDPROC wndProc = reinterpret_cast<WNDPROC>(
+                  GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
+              if (wndProc != PluginWindowProc) {
+                  mPluginWndProc = reinterpret_cast<WNDPROC>(
+                      SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
+                                       reinterpret_cast<LONG>(PluginWindowProc)));
+              }
+          }
+      }
+      break;
+
+      case NPWindowTypeDrawable:
+          if (mQuirks & QUIRK_WINLESS_TRACKPOPUP_HOOK)
+              CreateWinlessPopupSurrogate();
+          return SharedSurfaceSetWindow(aWindow);
+      break;
+
+      default:
+          NS_NOTREACHED("Bad plugin window type.");
+          return false;
+      break;
+    }
+
+#elif defined(OS_MACOSX)
+#  warning This is only a stub implementation IMPLEMENT ME
+
+#else
+#  error Implement me for your OS
+#endif
+
+    return true;
+}
+
+bool
+PluginInstanceChild::Initialize()
+{
+    return true;
+}
+
+#if defined(OS_WIN)
+
+static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow");
+static const TCHAR kPluginInstanceChildProperty[] = TEXT("PluginInstanceChildProperty");
+
+// static
+bool
+PluginInstanceChild::RegisterWindowClass()
+{
+    static bool alreadyRegistered = false;
+    if (alreadyRegistered)
+        return true;
+
+    alreadyRegistered = true;
+
+    WNDCLASSEX wcex;
+    wcex.cbSize         = sizeof(WNDCLASSEX);
+    wcex.style          = CS_DBLCLKS;
+    wcex.lpfnWndProc    = DummyWindowProc;
+    wcex.cbClsExtra     = 0;
+    wcex.cbWndExtra     = 0;
+    wcex.hInstance      = GetModuleHandle(NULL);
+    wcex.hIcon          = 0;
+    wcex.hCursor        = 0;
+    wcex.hbrBackground  = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
+    wcex.lpszMenuName   = 0;
+    wcex.lpszClassName  = kWindowClassName;
+    wcex.hIconSm        = 0;
+
+    return RegisterClassEx(&wcex) ? true : false;
+}
+
+bool
+PluginInstanceChild::CreatePluginWindow()
+{
+    // already initialized
+    if (mPluginWindowHWND)
+        return true;
+        
+    if (!RegisterWindowClass())
+        return false;
+
+    mPluginWindowHWND =
+        CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING |
+                       WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this!
+                       WS_EX_RIGHTSCROLLBAR,
+                       kWindowClassName, 0,
+                       WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0,
+                       0, 0, NULL, 0, GetModuleHandle(NULL), 0);
+    if (!mPluginWindowHWND)
+        return false;
+    if (!SetProp(mPluginWindowHWND, kPluginInstanceChildProperty, this))
+        return false;
+
+    // Apparently some plugins require an ASCII WndProc.
+    SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC,
+                      reinterpret_cast<LONG>(DefWindowProcA));
+
+    return true;
+}
+
+void
+PluginInstanceChild::DestroyPluginWindow()
+{
+    if (mPluginWindowHWND) {
+        // Unsubclass the window.
+        WNDPROC wndProc = reinterpret_cast<WNDPROC>(
+            GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
+        if (wndProc == PluginWindowProc) {
+            NS_ASSERTION(mPluginWndProc, "Should have old proc here!");
+            SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
+                             reinterpret_cast<LONG>(mPluginWndProc));
+            mPluginWndProc = 0;
+        }
+
+        RemoveProp(mPluginWindowHWND, kPluginInstanceChildProperty);
+        DestroyWindow(mPluginWindowHWND);
+        mPluginWindowHWND = 0;
+    }
+}
+
+void
+PluginInstanceChild::ReparentPluginWindow(HWND hWndParent)
+{
+    if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) {
+        // Fix the child window's style to be a child window.
+        LONG style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE);
+        style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+        style &= ~WS_POPUP;
+        SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style);
+
+        // Do the reparenting.
+        SetParent(mPluginWindowHWND, hWndParent);
+
+        // Make sure we're visible.
+        ShowWindow(mPluginWindowHWND, SW_SHOWNA);
+    }
+    mPluginParentHWND = hWndParent;
+}
+
+void
+PluginInstanceChild::SizePluginWindow(int width,
+                                      int height)
+{
+    if (mPluginWindowHWND) {
+        mPluginSize.x = width;
+        mPluginSize.y = height;
+        SetWindowPos(mPluginWindowHWND, NULL, 0, 0, width, height,
+                     SWP_NOZORDER | SWP_NOREPOSITION);
+    }
+}
+
+// See chromium's webplugin_delegate_impl.cc for explanation of this function.
+// static
+LRESULT CALLBACK
+PluginInstanceChild::DummyWindowProc(HWND hWnd,
+                                     UINT message,
+                                     WPARAM wParam,
+                                     LPARAM lParam)
+{
+    return CallWindowProc(DefWindowProc, hWnd, message, wParam, lParam);
+}
+
+// static
+LRESULT CALLBACK
+PluginInstanceChild::PluginWindowProc(HWND hWnd,
+                                      UINT message,
+                                      WPARAM wParam,
+                                      LPARAM lParam)
+{
+    NS_ASSERTION(!mozilla::ipc::SyncChannel::IsPumpingMessages(),
+                 "Failed to prevent a nonqueued message from running!");
+
+    PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
+        GetProp(hWnd, kPluginInstanceChildProperty));
+    if (!self) {
+        NS_NOTREACHED("Badness!");
+        return 0;
+    }
+
+    NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!");
+
+    // Adobe's shockwave positions the plugin window relative to the browser
+    // frame when it initializes. With oopp disabled, this wouldn't have an
+    // effect. With oopp, GeckoPluginWindow is a child of the parent plugin
+    // window, so the move offsets the child within the parent. Generally
+    // we don't want plugins moving or sizing our window, so we prevent these
+    // changes here.
+    if (message == WM_WINDOWPOSCHANGING) {
+      WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lParam);
+      if (pos && (!(pos->flags & SWP_NOMOVE) || !(pos->flags & SWP_NOSIZE))) {
+        pos->x = pos->y = 0;
+        pos->cx = self->mPluginSize.x;
+        pos->cy = self->mPluginSize.y;
+        LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
+                                     lParam);
+        pos->x = pos->y = 0;
+        pos->cx = self->mPluginSize.x;
+        pos->cy = self->mPluginSize.y;
+        return res;
+      }
+    }
+
+    // The plugin received keyboard focus, let the parent know so the dom is up to date.
+    if (message == WM_MOUSEACTIVATE)
+        self->CallPluginGotFocus();
+
+    // Prevent lockups due to plugins making rpc calls when the parent
+    // is making a synchronous SetFocus api call. (bug 541362) Add more
+    // windowing events as needed for other api.
+    if (message == WM_KILLFOCUS && 
+        ((InSendMessageEx(NULL) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND)) {
+        ReplyMessage(0); // Unblock the caller
+    }
+
+    LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
+                                 lParam);
+
+    if (message == WM_CLOSE)
+        self->DestroyPluginWindow();
+
+    if (message == WM_NCDESTROY)
+        RemoveProp(hWnd, kPluginInstanceChildProperty);
+
+    return res;
+}
+
+/* winless modal ui loop logic */
+
+// gTempChildPointer is only in use from the time we enter handle event, to the
+// point where ui might be created by that call. If ui isn't created, there's
+// no issue. If ui is created, the parent can't start processing messages in
+// spin loop until InternalCallSetNestedEventState is set, at which point,
+// gTempChildPointer is no longer needed.
+static PluginInstanceChild* gTempChildPointer;
+
+LRESULT CALLBACK
+PluginInstanceChild::NestedInputEventHook(int nCode,
+                                          WPARAM wParam,
+                                          LPARAM lParam)
+{
+    if (!gTempChildPointer) {
+        return CallNextHookEx(NULL, nCode, wParam, lParam);
+    }
+
+    if (nCode >= 0) {
+        NS_ASSERTION(gTempChildPointer, "Never should be null here!");
+        gTempChildPointer->ResetNestedEventHook();
+        gTempChildPointer->InternalCallSetNestedEventState(true);
+
+        gTempChildPointer = NULL;
+    }
+    return CallNextHookEx(NULL, nCode, wParam, lParam);
+}
+
+void
+PluginInstanceChild::SetNestedInputEventHook()
+{
+    NS_ASSERTION(!mNestedEventHook,
+        "mNestedEventHook already setup in call to SetNestedInputEventHook?");
+
+    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
+
+    // WH_GETMESSAGE hooks are triggered by peek message calls in parent due to
+    // attached message queues, resulting in stomped in-process ipc calls.  So
+    // we use a filter hook specific to dialogs, menus, and scroll bars to kick
+    // things off.
+    mNestedEventHook = SetWindowsHookEx(WH_MSGFILTER,
+                                        NestedInputEventHook,
+                                        NULL,
+                                        GetCurrentThreadId());
+}
+
+void
+PluginInstanceChild::ResetNestedEventHook()
+{
+    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
+    if (mNestedEventHook)
+        UnhookWindowsHookEx(mNestedEventHook);
+    mNestedEventHook = NULL;
+}
+
+void
+PluginInstanceChild::InternalCallSetNestedEventState(bool aState)
+{
+    if (aState != mNestedEventState) {
+        PLUGIN_LOG_DEBUG(
+            ("PluginInstanceChild::InternalCallSetNestedEventState(%i)",
+            (int)aState));
+        mNestedEventState = aState;
+        SendSetNestedEventState(mNestedEventState);
+    }
+}
+
+/* windowless track popup menu helpers */
+
+BOOL
+WINAPI
+PluginInstanceChild::TrackPopupHookProc(HMENU hMenu,
+                                        UINT uFlags,
+                                        int x,
+                                        int y,
+                                        int nReserved,
+                                        HWND hWnd,
+                                        CONST RECT *prcRect)
+{
+  if (!sUser32TrackPopupMenuStub) {
+      NS_ERROR("TrackPopupMenu stub isn't set! Badness!");
+      return 0;
+  }
+
+  // Only change the parent when we know this is a context on the plugin
+  // surface within the browser. Prevents resetting the parent on child ui
+  // displayed by plugins that have working parent-child relationships.
+  PRUnichar szClass[21];
+  bool haveClass = GetClassNameW(hWnd, szClass, NS_ARRAY_LENGTH(szClass));
+  if (!haveClass || 
+      (wcscmp(szClass, L"MozillaWindowClass") &&
+       wcscmp(szClass, L"SWFlash_Placeholder"))) {
+      // Unrecognized parent
+      return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved,
+                                       hWnd, prcRect);
+  }
+
+  // Called on an unexpected event, warn.
+  if (!sWinlessPopupSurrogateHWND) {
+      NS_WARNING(
+          "Untraced TrackPopupHookProc call! Menu might not work right!");
+      return sUser32TrackPopupMenuStub(hMenu, uFlags, x, y, nReserved,
+                                       hWnd, prcRect);
+  }
+
+  HWND surrogateHwnd = sWinlessPopupSurrogateHWND;
+  sWinlessPopupSurrogateHWND = NULL;
+
+  // Popups that don't use TPM_RETURNCMD expect a final command message
+  // when an item is selected and the context closes. Since we replace
+  // the parent, we need to forward this back to the real parent so it
+  // can act on the menu item selected.
+  bool isRetCmdCall = (uFlags & TPM_RETURNCMD);
+
+  // A little trick scrounged from chromium's code - set the focus
+  // to our surrogate parent so keyboard nav events go to the menu. 
+  HWND focusHwnd = SetFocus(surrogateHwnd);
+  DWORD res = sUser32TrackPopupMenuStub(hMenu, uFlags|TPM_RETURNCMD, x, y,
+                                        nReserved, surrogateHwnd, prcRect);
+  if (IsWindow(focusHwnd)) {
+      SetFocus(focusHwnd);
+  }
+
+  if (!isRetCmdCall && res) {
+      SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(res, 0), 0);
+  }
+
+  return res;
+}
+
+void
+PluginInstanceChild::InitPopupMenuHook()
+{
+    if (!(mQuirks & QUIRK_WINLESS_TRACKPOPUP_HOOK) ||
+        sUser32TrackPopupMenuStub)
+        return;
+
+    // Note, once WindowsDllInterceptor is initialized for a module,
+    // it remains initialized for that particular module for it's
+    // lifetime. Additional instances are needed if other modules need
+    // to be hooked.
+    sUser32Intercept.Init("user32.dll");
+    sUser32Intercept.AddHook("TrackPopupMenu", TrackPopupHookProc,
+                             (void**) &sUser32TrackPopupMenuStub);
+}
+
+void
+PluginInstanceChild::CreateWinlessPopupSurrogate()
+{
+    // already initialized
+    if (mWinlessPopupSurrogateHWND)
+        return;
+
+    HWND hwnd = NULL;
+    NPError result;
+    if (!CallNPN_GetValue_NPNVnetscapeWindow(&hwnd, &result)) {
+        NS_ERROR("CallNPN_GetValue_NPNVnetscapeWindow failed.");
+        return;
+    }
+
+    mWinlessPopupSurrogateHWND =
+        CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", NULL, WS_CHILD, 0, 0,
+                       0, 0, hwnd, 0, GetModuleHandle(NULL), 0);
+    if (!mWinlessPopupSurrogateHWND) {
+        NS_ERROR("CreateWindowEx failed for winless placeholder!");
+        return;
+    }
+    return;
+}
+
+void
+PluginInstanceChild::DestroyWinlessPopupSurrogate()
+{
+    if (mWinlessPopupSurrogateHWND)
+        DestroyWindow(mWinlessPopupSurrogateHWND);
+    mWinlessPopupSurrogateHWND = NULL;
+}
+
+/* windowless handle event helpers */
+
+static bool
+NeedsNestedEventCoverage(UINT msg)
+{
+    // Events we assume some sort of modal ui *might* be generated.
+    switch (msg) {
+        case WM_LBUTTONUP:
+        case WM_RBUTTONUP:
+        case WM_MBUTTONUP:
+        case WM_LBUTTONDOWN:
+        case WM_RBUTTONDOWN:
+        case WM_MBUTTONDOWN:
+        case WM_CONTEXTMENU:
+            return true;
+    }
+    return false;
+}
+
+static bool
+IsMouseInputEvent(UINT msg)
+{
+    switch (msg) {
+        case WM_MOUSEMOVE:
+        case WM_LBUTTONUP:
+        case WM_RBUTTONUP:
+        case WM_MBUTTONUP:
+        case WM_LBUTTONDOWN:
+        case WM_RBUTTONDOWN:
+        case WM_MBUTTONDOWN:
+        case WM_LBUTTONDBLCLK:
+        case WM_MBUTTONDBLCLK:
+        case WM_RBUTTONDBLCLK:
+            return true;
+    }
+    return false;
+}
+
+int16_t
+PluginInstanceChild::WinlessHandleEvent(NPEvent& event)
+{
+    if (!mPluginIface->event)
+        return false;
+
+    // Winless Silverlight quirk: winposchanged events are not used in
+    // determining the position of the plugin within the parent window,
+    // NPP_SetWindow values are used instead. Due to shared memory dib
+    // rendering, the origin of NPP_SetWindow is 0x0, so we trap
+    // winposchanged events here and do the translation internally for
+    // mouse input events.
+    if (mQuirks & QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION) {
+        if (event.event == WM_WINDOWPOSCHANGED && event.lParam) {
+            WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(event.lParam);
+            mPluginOffset.x = pos->x;
+            mPluginOffset.y = pos->y;
+        }
+        else if (IsMouseInputEvent(event.event)) {
+            event.lParam =
+                MAKELPARAM((GET_X_LPARAM(event.lParam) - mPluginOffset.x),
+                           (GET_Y_LPARAM(event.lParam) - mPluginOffset.y));
+        }
+    }
+
+    if (!NeedsNestedEventCoverage(event.event)) {
+        return mPluginIface->event(&mData, reinterpret_cast<void*>(&event));
+    }
+
+    // Events that might generate nested event dispatch loops need
+    // special handling during delivery.
+    int16_t handled;
+
+    mNestedEventLevelDepth++;
+    PLUGIN_LOG_DEBUG(("WinlessHandleEvent start depth: %i", mNestedEventLevelDepth));
+
+    // On the first, non-reentrant call, setup our modal ui detection hook.
+    if (mNestedEventLevelDepth == 1) {
+        NS_ASSERTION(!gTempChildPointer, "valid gTempChildPointer here?");
+        gTempChildPointer = this;
+        SetNestedInputEventHook();
+    }
+
+    // TrackPopupMenu will fail if the parent window is not associated with
+    // our ui thread. So we hook TrackPopupMenu so we can hand in a surrogate
+    // parent created in the child process.
+    if ((mQuirks & QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default?
+          (event.event == WM_RBUTTONDOWN || // flash
+           event.event == WM_RBUTTONUP)) {  // silverlight
+      sWinlessPopupSurrogateHWND = mWinlessPopupSurrogateHWND;
+    }
+
+    bool old_state = MessageLoop::current()->NestableTasksAllowed();
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+    handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&event));
+    MessageLoop::current()->SetNestableTasksAllowed(old_state);
+
+    gTempChildPointer = NULL;
+    sWinlessPopupSurrogateHWND = NULL;
+
+    mNestedEventLevelDepth--;
+    PLUGIN_LOG_DEBUG(("WinlessHandleEvent end depth: %i", mNestedEventLevelDepth));
+
+    NS_ASSERTION(!(mNestedEventLevelDepth < 0), "mNestedEventLevelDepth < 0?");
+    if (mNestedEventLevelDepth <= 0) {
+        ResetNestedEventHook();
+        InternalCallSetNestedEventState(false);
+    }
+    return handled;
+}
+
+/* windowless drawing helpers */
+
+bool
+PluginInstanceChild::SharedSurfaceSetWindow(const NPRemoteWindow& aWindow)
+{
+    // If the surfaceHandle is empty, parent is telling us we can reuse our cached
+    // memory surface and hdc. Otherwise, we need to reset, usually due to a
+    // expanding plugin port size.
+    if (!aWindow.surfaceHandle) {
+        if (!mSharedSurfaceDib.IsValid()) {
+            return false;
+        }
+    }
+    else {
+        // Attach to the new shared surface parent handed us.
+        if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle,
+                                               aWindow.width, aWindow.height, 32)))
+          return false;
+        // Free any alpha extraction resources if needed. This will be reset
+        // the next time it's used.
+        AlphaExtractCacheRelease();
+    }
+      
+    // NPRemoteWindow's origin is the origin of our shared dib.
+    mWindow.x      = 0;
+    mWindow.y      = 0;
+    mWindow.width  = aWindow.width;
+    mWindow.height = aWindow.height;
+    mWindow.type   = aWindow.type;
+
+    mWindow.window = reinterpret_cast<void*>(mSharedSurfaceDib.GetHDC());
+
+    if (mPluginIface->setwindow)
+        mPluginIface->setwindow(&mData, &mWindow);
+
+    return true;
+}
+
+void
+PluginInstanceChild::SharedSurfaceRelease()
+{
+    mSharedSurfaceDib.Close();
+    AlphaExtractCacheRelease();
+}
+
+/* double pass cache buffer - (rarely) used in cases where alpha extraction
+ * occurs for windowless plugins. */
+ 
+bool
+PluginInstanceChild::AlphaExtractCacheSetup()
+{
+    AlphaExtractCacheRelease();
+
+    mAlphaExtract.hdc = ::CreateCompatibleDC(NULL);
+
+    if (!mAlphaExtract.hdc)
+        return false;
+
+    BITMAPINFOHEADER bmih;
+    memset((void*)&bmih, 0, sizeof(BITMAPINFOHEADER));
+    bmih.biSize        = sizeof(BITMAPINFOHEADER);
+    bmih.biWidth       = mWindow.width;
+    bmih.biHeight      = mWindow.height;
+    bmih.biPlanes      = 1;
+    bmih.biBitCount    = 32;
+    bmih.biCompression = BI_RGB;
+
+    void* ppvBits = nsnull;
+    mAlphaExtract.bmp = ::CreateDIBSection(mAlphaExtract.hdc,
+                                           (BITMAPINFO*)&bmih,
+                                           DIB_RGB_COLORS,
+                                           (void**)&ppvBits,
+                                           NULL,
+                                           (unsigned long)sizeof(BITMAPINFOHEADER));
+    if (!mAlphaExtract.bmp)
+      return false;
+
+    DeleteObject(::SelectObject(mAlphaExtract.hdc, mAlphaExtract.bmp));
+    return true;
+}
+
+void
+PluginInstanceChild::AlphaExtractCacheRelease()
+{
+    if (mAlphaExtract.bmp)
+        ::DeleteObject(mAlphaExtract.bmp);
+
+    if (mAlphaExtract.hdc)
+        ::DeleteObject(mAlphaExtract.hdc);
+
+    mAlphaExtract.bmp = NULL;
+    mAlphaExtract.hdc = NULL;
+}
+
+void
+PluginInstanceChild::UpdatePaintClipRect(RECT* aRect)
+{
+    if (aRect) {
+        // Update the clip rect on our internal hdc
+        HRGN clip = ::CreateRectRgnIndirect(aRect);
+        ::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip);
+        ::DeleteObject(clip);
+    }
+}
+
+int16_t
+PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
+{
+    if (!mPluginIface->event)
+        return false;
+
+    RECT* pRect = reinterpret_cast<RECT*>(evcopy.lParam);
+
+    switch(mAlphaExtract.doublePass) {
+        case RENDER_NATIVE:
+            // pass the internal hdc to the plugin
+            UpdatePaintClipRect(pRect);
+            evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
+            return mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
+        break;
+        case RENDER_BACK_ONE:
+              // Handle a double pass render used in alpha extraction for transparent
+              // plugins. (See nsObjectFrame and gfxWindowsNativeDrawing for details.)
+              // We render twice, once to the shared dib, and once to a cache which
+              // we copy back on a second paint. These paints can't be spread across
+              // multiple rpc messages as delays cause animation frame changes.
+              if (!mAlphaExtract.bmp && !AlphaExtractCacheSetup()) {
+                  mAlphaExtract.doublePass = RENDER_NATIVE;
+                  return false;
+              }
+
+              // See gfxWindowsNativeDrawing, color order doesn't have to match.
+              ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+              UpdatePaintClipRect(pRect);
+              evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
+              if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
+                  mAlphaExtract.doublePass = RENDER_NATIVE;
+                  return false;
+              }
+
+              // Copy to cache. We render to shared dib so we don't have to call
+              // setwindow between calls (flash issue).  
+              ::BitBlt(mAlphaExtract.hdc,
+                       pRect->left,
+                       pRect->top,
+                       pRect->right - pRect->left,
+                       pRect->bottom - pRect->top,
+                       mSharedSurfaceDib.GetHDC(),
+                       pRect->left,
+                       pRect->top,
+                       SRCCOPY);
+
+              ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
+              if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
+                  mAlphaExtract.doublePass = RENDER_NATIVE;
+                  return false;
+              }
+              mAlphaExtract.doublePass = RENDER_BACK_TWO;
+              return true;
+        break;
+        case RENDER_BACK_TWO:
+              // copy our cached surface back
+              ::BitBlt(mSharedSurfaceDib.GetHDC(),
+                       pRect->left,
+                       pRect->top,
+                       pRect->right - pRect->left,
+                       pRect->bottom - pRect->top,
+                       mAlphaExtract.hdc,
+                       pRect->left,
+                       pRect->top,
+                       SRCCOPY);
+              mAlphaExtract.doublePass = RENDER_NATIVE;
+              return true;
+        break;
+    }
+    return false;
+}
+
+#endif // OS_WIN
+
+bool
+PluginInstanceChild::AnswerSetPluginFocus()
+{
+    PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s", FULLFUNCTION));
+
+#if defined(OS_WIN)
+    // Parent is letting us know something set focus to the plugin.
+    if (::GetFocus() == mPluginWindowHWND)
+        return true;
+    ::SetFocus(mPluginWindowHWND);
+    return true;
+#else
+    NS_NOTREACHED("PluginInstanceChild::AnswerSetPluginFocus not implemented!");
+    return false;
+#endif
+}
+
+bool
+PluginInstanceChild::AnswerUpdateWindow()
+{
+    PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s", FULLFUNCTION));
+
+#if defined(OS_WIN)
+    if (mPluginWindowHWND)
+      UpdateWindow(mPluginWindowHWND);
+    return true;
+#else
+    NS_NOTREACHED("PluginInstanceChild::AnswerUpdateWindow not implemented!");
+    return false;
+#endif
+}
+
+PPluginScriptableObjectChild*
+PluginInstanceChild::AllocPPluginScriptableObject()
+{
+    AssertPluginThread();
+    return new PluginScriptableObjectChild(Proxy);
+}
+
+bool
+PluginInstanceChild::DeallocPPluginScriptableObject(
+    PPluginScriptableObjectChild* aObject)
+{
+    AssertPluginThread();
+    delete aObject;
+    return true;
+}
+
+bool
+PluginInstanceChild::RecvPPluginScriptableObjectConstructor(
+                                           PPluginScriptableObjectChild* aActor)
+{
+    AssertPluginThread();
+
+    // This is only called in response to the parent process requesting the
+    // creation of an actor. This actor will represent an NPObject that is
+    // created by the browser and returned to the plugin.
+    PluginScriptableObjectChild* actor =
+        static_cast<PluginScriptableObjectChild*>(aActor);
+    NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
+
+    actor->InitializeProxy();
+    NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
+
+    return true;
+}
+
+bool
+PluginInstanceChild::AnswerPBrowserStreamConstructor(
+    PBrowserStreamChild* aActor,
+    const nsCString& url,
+    const uint32_t& length,
+    const uint32_t& lastmodified,
+    PStreamNotifyChild* notifyData,
+    const nsCString& headers,
+    const nsCString& mimeType,
+    const bool& seekable,
+    NPError* rv,
+    uint16_t* stype)
+{
+    AssertPluginThread();
+    *rv = static_cast<BrowserStreamChild*>(aActor)
+          ->StreamConstructed(mimeType, seekable, stype);
+    return true;
+}
+
+PBrowserStreamChild*
+PluginInstanceChild::AllocPBrowserStream(const nsCString& url,
+                                         const uint32_t& length,
+                                         const uint32_t& lastmodified,
+                                         PStreamNotifyChild* notifyData,
+                                         const nsCString& headers,
+                                         const nsCString& mimeType,
+                                         const bool& seekable,
+                                         NPError* rv,
+                                         uint16_t *stype)
+{
+    AssertPluginThread();
+    return new BrowserStreamChild(this, url, length, lastmodified,
+                                  static_cast<StreamNotifyChild*>(notifyData),
+                                  headers, mimeType, seekable, rv, stype);
+}
+
+bool
+PluginInstanceChild::DeallocPBrowserStream(PBrowserStreamChild* stream)
+{
+    AssertPluginThread();
+    delete stream;
+    return true;
+}
+
+PPluginStreamChild*
+PluginInstanceChild::AllocPPluginStream(const nsCString& mimeType,
+                                        const nsCString& target,
+                                        NPError* result)
+{
+    NS_RUNTIMEABORT("not callable");
+    return NULL;
+}
+
+bool
+PluginInstanceChild::DeallocPPluginStream(PPluginStreamChild* stream)
+{
+    AssertPluginThread();
+    delete stream;
+    return true;
+}
+
+PStreamNotifyChild*
+PluginInstanceChild::AllocPStreamNotify(const nsCString& url,
+                                        const nsCString& target,
+                                        const bool& post,
+                                        const nsCString& buffer,
+                                        const bool& file,
+                                        NPError* result)
+{
+    AssertPluginThread();
+    NS_RUNTIMEABORT("not reached");
+    return NULL;
+}
+
+void
+StreamNotifyChild::ActorDestroy(ActorDestroyReason why)
+{
+    if (AncestorDeletion == why && mBrowserStream) {
+        NS_ERROR("Pending NPP_URLNotify not called when closing an instance.");
+
+        // reclaim responsibility for deleting ourself
+        mBrowserStream->mStreamNotify = NULL;
+        mBrowserStream = NULL;
+    }
+}
+
+
+void
+StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs)
+{
+    NS_ASSERTION(bs, "Shouldn't be null");
+    NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?");
+
+    mBrowserStream = bs;
+}
+
+bool
+StreamNotifyChild::Recv__delete__(const NPReason& reason)
+{
+    AssertPluginThread();
+
+    if (mBrowserStream)
+        mBrowserStream->NotifyPending();
+    else
+        NPP_URLNotify(reason);
+
+    return true;
+}
+
+void
+StreamNotifyChild::NPP_URLNotify(NPReason reason)
+{
+    PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
+
+    if (mClosure)
+        instance->mPluginIface->urlnotify(instance->GetNPP(), mURL.get(),
+                                          reason, mClosure);
+}
+
+bool
+PluginInstanceChild::DeallocPStreamNotify(PStreamNotifyChild* notifyData)
+{
+    AssertPluginThread();
+
+    if (!static_cast<StreamNotifyChild*>(notifyData)->mBrowserStream)
+        delete notifyData;
+    return true;
+}
+
+PluginScriptableObjectChild*
+PluginInstanceChild::GetActorForNPObject(NPObject* aObject)
+{
+    AssertPluginThread();
+    NS_ASSERTION(aObject, "Null pointer!");
+
+    if (aObject->_class == PluginScriptableObjectChild::GetClass()) {
+        // One of ours! It's a browser-provided object.
+        ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
+        NS_ASSERTION(object->parent, "Null actor!");
+        return object->parent;
+    }
+
+    PluginScriptableObjectChild* actor =
+        PluginModuleChild::current()->GetActorForNPObject(aObject);
+    if (actor) {
+        // Plugin-provided object that we've previously wrapped.
+        return actor;
+    }
+
+    actor = new PluginScriptableObjectChild(LocalObject);
+    if (!SendPPluginScriptableObjectConstructor(actor)) {
+        NS_ERROR("Failed to send constructor message!");
+        return nsnull;
+    }
+
+    actor->InitializeLocal(aObject);
+    return actor;
+}
+
+NPError
+PluginInstanceChild::NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow,
+                                   NPStream** aStream)
+{
+    AssertPluginThread();
+
+    PluginStreamChild* ps = new PluginStreamChild();
+
+    NPError result;
+    CallPPluginStreamConstructor(ps, nsDependentCString(aMIMEType),
+                                 NullableString(aWindow), &result);
+    if (NPERR_NO_ERROR != result) {
+        *aStream = NULL;
+        PPluginStreamChild::Call__delete__(ps, NPERR_GENERIC_ERROR, true);
+        return result;
+    }
+
+    *aStream = &ps->mStream;
+    return NPERR_NO_ERROR;
+}
+
+void
+PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
+{
+    NS_ASSERTION(aInvalidRect, "Null pointer!");
+
+#ifdef OS_WIN
+    // Invalidate and draw locally for windowed plugins.
+    if (mWindow.type == NPWindowTypeWindow) {
+      NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!");
+      RECT rect = { aInvalidRect->left, aInvalidRect->top,
+                    aInvalidRect->right, aInvalidRect->bottom };
+      ::InvalidateRect(mPluginWindowHWND, &rect, FALSE);
+      return;
+    }
+#endif
+
+    SendNPN_InvalidateRect(*aInvalidRect);
+}
+
+static PLDHashOperator
+InvalidateObject(DeletingObjectEntry* e, void* userArg)
+{
+    NPObject* o = e->GetKey();
+    if (!e->mDeleted && o->_class && o->_class->invalidate)
+        o->_class->invalidate(o);
+
+    return PL_DHASH_NEXT;
+}
+
+static PLDHashOperator
+DeleteObject(DeletingObjectEntry* e, void* userArg)
+{
+    NPObject* o = e->GetKey();
+    if (!e->mDeleted) {
+        e->mDeleted = true;
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+        {
+            int32_t refcnt = o->referenceCount;
+            while (refcnt) {
+                --refcnt;
+                NS_LOG_RELEASE(o, refcnt, "NPObject");
+            }
+        }
+#endif
+
+        PluginModuleChild::DeallocNPObject(o);
+    }
+
+    return PL_DHASH_NEXT;
+}
+
+bool
+PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
+{
+    PLUGIN_LOG_DEBUG_METHOD;
+    AssertPluginThread();
+
+    nsTArray<PBrowserStreamChild*> streams;
+    ManagedPBrowserStreamChild(streams);
+
+    // First make sure none of these streams become deleted
+    for (PRUint32 i = 0; i < streams.Length(); ) {
+        if (static_cast<BrowserStreamChild*>(streams[i])->InstanceDying())
+            ++i;
+        else
+            streams.RemoveElementAt(i);
+    }
+    for (PRUint32 i = 0; i < streams.Length(); ++i)
+        static_cast<BrowserStreamChild*>(streams[i])->FinishDelivery();
+
+    for (PRUint32 i = 0; i < mPendingAsyncCalls.Length(); ++i)
+        mPendingAsyncCalls[i]->Cancel();
+    mPendingAsyncCalls.TruncateLength(0);
+
+    PluginModuleChild::current()->NPP_Destroy(this);
+    mData.ndata = 0;
+
+    mDeletingHash = new nsTHashtable<DeletingObjectEntry>;
+    mDeletingHash->Init();
+    PluginModuleChild::current()->FindNPObjectsForInstance(this);
+
+    mDeletingHash->EnumerateEntries(InvalidateObject, NULL);
+    mDeletingHash->EnumerateEntries(DeleteObject, NULL);
+
+    // Null out our cached actors as they should have been killed in the
+    // PluginInstanceDestroyed call above.
+    mCachedWindowActor = nsnull;
+    mCachedElementActor = nsnull;
+
+#if defined(OS_WIN)
+    SharedSurfaceRelease();
+    ResetNestedEventHook();
+    DestroyWinlessPopupSurrogate();
+#endif
+
+    return true;
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginInstanceChild.h
@@ -0,0 +1,317 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@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 dom_plugins_PluginInstanceChild_h
+#define dom_plugins_PluginInstanceChild_h 1
+
+#include "mozilla/plugins/PPluginInstanceChild.h"
+#include "mozilla/plugins/PluginScriptableObjectChild.h"
+#include "mozilla/plugins/StreamNotifyChild.h"
+#if defined(OS_WIN)
+#include "mozilla/gfx/SharedDIBWin.h"
+#endif
+
+#include "npfunctions.h"
+#include "nsAutoPtr.h"
+#include "nsTArray.h"
+#include "ChildAsyncCall.h"
+#include "nsRect.h"
+#include "nsTHashtable.h"
+
+namespace mozilla {
+namespace plugins {
+
+class PBrowserStreamChild;
+class BrowserStreamChild;
+class StreamNotifyChild;
+
+class PluginInstanceChild : public PPluginInstanceChild
+{
+    friend class BrowserStreamChild;
+    friend class PluginStreamChild;
+    friend class StreamNotifyChild; 
+
+#ifdef OS_WIN
+    friend LRESULT CALLBACK PluginWindowProc(HWND hWnd,
+                                             UINT message,
+                                             WPARAM wParam,
+                                             LPARAM lParam);
+#endif
+
+protected:
+    virtual bool AnswerNPP_SetWindow(const NPRemoteWindow& window);
+
+    virtual bool
+    AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(bool* needs, NPError* rv);
+    virtual bool
+    AnswerNPP_GetValue_NPPVpluginScriptableNPObject(PPluginScriptableObjectChild** value,
+                                                    NPError* result);
+
+    virtual bool
+    AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value, NPError* result);
+
+    virtual bool
+    AnswerNPP_HandleEvent(const NPRemoteEvent& event, int16_t* handled);
+
+    NS_OVERRIDE
+    virtual bool
+    AnswerPaint(const NPRemoteEvent& event, int16_t* handled)
+    {
+        return AnswerNPP_HandleEvent(event, handled);
+    }
+
+    NS_OVERRIDE
+    virtual bool
+    RecvWindowPosChanged(const NPRemoteEvent& event);
+
+    virtual bool
+    AnswerNPP_Destroy(NPError* result);
+
+    virtual PPluginScriptableObjectChild*
+    AllocPPluginScriptableObject();
+
+    virtual bool
+    DeallocPPluginScriptableObject(PPluginScriptableObjectChild* aObject);
+
+    NS_OVERRIDE virtual bool
+    RecvPPluginScriptableObjectConstructor(PPluginScriptableObjectChild* aActor);
+
+    virtual PBrowserStreamChild*
+    AllocPBrowserStream(const nsCString& url,
+                        const uint32_t& length,
+                        const uint32_t& lastmodified,
+                        PStreamNotifyChild* notifyData,
+                        const nsCString& headers,
+                        const nsCString& mimeType,
+                        const bool& seekable,
+                        NPError* rv,
+                        uint16_t *stype);
+
+    virtual bool
+    AnswerPBrowserStreamConstructor(
+            PBrowserStreamChild* aActor,
+            const nsCString& url,
+            const uint32_t& length,
+            const uint32_t& lastmodified,
+            PStreamNotifyChild* notifyData,
+            const nsCString& headers,
+            const nsCString& mimeType,
+            const bool& seekable,
+            NPError* rv,
+            uint16_t* stype);
+        
+    virtual bool
+    DeallocPBrowserStream(PBrowserStreamChild* stream);
+
+    virtual PPluginStreamChild*
+    AllocPPluginStream(const nsCString& mimeType,
+                       const nsCString& target,
+                       NPError* result);
+
+    virtual bool
+    DeallocPPluginStream(PPluginStreamChild* stream);
+
+    virtual PStreamNotifyChild*
+    AllocPStreamNotify(const nsCString& url, const nsCString& target,
+                       const bool& post, const nsCString& buffer,
+                       const bool& file,
+                       NPError* result);
+
+    NS_OVERRIDE virtual bool
+    DeallocPStreamNotify(PStreamNotifyChild* notifyData);
+
+    virtual bool
+    AnswerSetPluginFocus();
+
+    virtual bool
+    AnswerUpdateWindow();
+
+public:
+    PluginInstanceChild(const NPPluginFuncs* aPluginIface, const nsCString& aMimeType);
+
+    virtual ~PluginInstanceChild();
+
+    bool Initialize();
+
+    NPP GetNPP()
+    {
+        return &mData;
+    }
+
+    NPError
+    NPN_GetValue(NPNVariable aVariable, void* aValue);
+
+    NPError
+    NPN_SetValue(NPPVariable aVariable, void* aValue);
+
+    PluginScriptableObjectChild*
+    GetActorForNPObject(NPObject* aObject);
+
+    NPError
+    NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow,
+                  NPStream** aStream);
+
+    void InvalidateRect(NPRect* aInvalidRect);
+
+private:
+    friend class PluginModuleChild;
+
+    // Quirks mode support for various plugin mime types
+    enum PluginQuirks {
+        // Win32: Translate mouse input based on WM_WINDOWPOSCHANGED
+        // windowing events due to winless shared dib rendering. See
+        // WinlessHandleEvent for details.
+        QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION = 1,
+        // Win32: Hook TrackPopupMenu api so that we can swap out parent
+        // hwnds. The api will fail with parents not associated with our
+        // child ui thread. See WinlessHandleEvent for details.
+        QUIRK_WINLESS_TRACKPOPUP_HOOK = 2,
+    };
+
+    void InitQuirksModes(const nsCString& aMimeType);
+
+    NPError
+    InternalGetNPObjectForValue(NPNVariable aValue,
+                                NPObject** aObject);
+
+#if defined(OS_WIN)
+    static bool RegisterWindowClass();
+    bool CreatePluginWindow();
+    void DestroyPluginWindow();
+    void ReparentPluginWindow(HWND hWndParent);
+    void SizePluginWindow(int width, int height);
+    int16_t WinlessHandleEvent(NPEvent& event);
+    void SetNestedInputEventHook();
+    void ResetNestedEventHook();
+    void SetNestedInputPumpHook();
+    void ResetPumpHooks();
+    void CreateWinlessPopupSurrogate();
+    void DestroyWinlessPopupSurrogate();
+    void InitPopupMenuHook();
+    void InternalCallSetNestedEventState(bool aState);
+    static LRESULT CALLBACK DummyWindowProc(HWND hWnd,
+                                            UINT message,
+                                            WPARAM wParam,
+                                            LPARAM lParam);
+    static LRESULT CALLBACK PluginWindowProc(HWND hWnd,
+                                             UINT message,
+                                             WPARAM wParam,
+                                             LPARAM lParam);
+    static VOID CALLBACK PumpTimerProc(HWND hwnd,
+                                       UINT uMsg,
+                                       UINT_PTR idEvent,
+                                       DWORD dwTime);
+    static LRESULT CALLBACK NestedInputEventHook(int code,
+                                                 WPARAM wParam,
+                                                 LPARAM lParam);
+    static LRESULT CALLBACK NestedInputPumpHook(int code,
+                                                WPARAM wParam,
+                                                LPARAM lParam);
+    static BOOL WINAPI TrackPopupHookProc(HMENU hMenu,
+                                          UINT uFlags,
+                                          int x,
+                                          int y,
+                                          int nReserved,
+                                          HWND hWnd,
+                                          CONST RECT *prcRect);
+#endif
+
+    const NPPluginFuncs* mPluginIface;
+    NPP_t mData;
+    NPWindow mWindow;
+    int mQuirks;
+
+    // Cached scriptable actors to avoid IPC churn
+    PluginScriptableObjectChild* mCachedWindowActor;
+    PluginScriptableObjectChild* mCachedElementActor;
+
+#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
+    NPSetWindowCallbackStruct mWsInfo;
+#elif defined(OS_WIN)
+    HWND mPluginWindowHWND;
+    WNDPROC mPluginWndProc;
+    HWND mPluginParentHWND;
+    HHOOK mNestedEventHook;
+    int mNestedEventLevelDepth;
+    bool mNestedEventState;
+    HWND mCachedWinlessPluginHWND;
+    HWND mWinlessPopupSurrogateHWND;
+    nsIntPoint mPluginSize;
+    nsIntPoint mPluginOffset;
+#endif
+
+    friend class ChildAsyncCall;
+    nsTArray<ChildAsyncCall*> mPendingAsyncCalls;
+
+    /**
+     * During destruction we enumerate all remaining scriptable objects and
+     * invalidate/delete them. Enumeration can re-enter, so maintain a
+     * hash separate from PluginModuleChild.mObjectMap.
+     */
+    nsAutoPtr< nsTHashtable<DeletingObjectEntry> > mDeletingHash;
+
+#if defined(OS_WIN)
+private:
+    // Shared dib rendering management for windowless plugins.
+    bool SharedSurfaceSetWindow(const NPRemoteWindow& aWindow);
+    int16_t SharedSurfacePaint(NPEvent& evcopy);
+    void SharedSurfaceRelease();
+    bool AlphaExtractCacheSetup();
+    void AlphaExtractCacheRelease();
+    void UpdatePaintClipRect(RECT* aRect);
+
+private:
+    enum {
+      RENDER_NATIVE,
+      RENDER_BACK_ONE,
+      RENDER_BACK_TWO 
+    };
+    gfx::SharedDIBWin mSharedSurfaceDib;
+    struct {
+      PRUint32        doublePassEvent;
+      PRUint16        doublePass;
+      HDC             hdc;
+      HBITMAP         bmp;
+    } mAlphaExtract;
+#endif // defined(OS_WIN)
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // ifndef dom_plugins_PluginInstanceChild_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginInstanceParent.cpp
@@ -0,0 +1,1136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jim Mathies <jmathies@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 ***** */
+
+#include "PluginInstanceParent.h"
+
+#include "BrowserStreamParent.h"
+#include "PluginModuleParent.h"
+#include "PluginStreamParent.h"
+#include "StreamNotifyParent.h"
+#include "npfunctions.h"
+#include "nsAutoPtr.h"
+
+#if defined(OS_WIN)
+#include <windowsx.h>
+
+// Plugin focus event for widget.
+extern const PRUnichar* kOOPPPluginFocusEventId;
+UINT gOOPPPluginFocusEvent =
+    RegisterWindowMessage(kOOPPPluginFocusEventId);
+UINT gOOPPSpinNativeLoopEvent =
+    RegisterWindowMessage(L"SyncChannel Spin Inner Loop Message");
+UINT gOOPPStopNativeLoopEvent =
+    RegisterWindowMessage(L"SyncChannel Stop Inner Loop Message");
+#elif defined(MOZ_WIDGET_GTK2)
+#include <gdk/gdk.h>
+#endif
+
+using namespace mozilla::plugins;
+
+PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
+                                           NPP npp,
+                                           const NPNetscapeFuncs* npniface)
+  : mParent(parent)
+    , mNPP(npp)
+    , mNPNIface(npniface)
+    , mWindowType(NPWindowTypeWindow)
+#if defined(OS_WIN)
+    , mPluginHWND(NULL)
+    , mPluginWndProc(NULL)
+    , mNestedEventState(false)
+#endif // defined(XP_WIN)
+{
+}
+
+PluginInstanceParent::~PluginInstanceParent()
+{
+    if (mNPP)
+        mNPP->pdata = NULL;
+
+#if defined(OS_WIN)
+    NS_ASSERTION(!(mPluginHWND || mPluginWndProc),
+        "Subclass was not reset correctly before the dtor was reached!");
+#endif
+}
+
+bool
+PluginInstanceParent::Init()
+{
+    return !!mScriptableObjects.Init();
+}
+
+namespace {
+
+PLDHashOperator
+ActorCollect(const void* aKey,
+             PluginScriptableObjectParent* aData,
+             void* aUserData)
+{
+    nsTArray<PluginScriptableObjectParent*>* objects =
+        reinterpret_cast<nsTArray<PluginScriptableObjectParent*>*>(aUserData);
+    return objects->AppendElement(aData) ? PL_DHASH_NEXT : PL_DHASH_STOP;
+}
+
+} // anonymous namespace
+
+void
+PluginInstanceParent::ActorDestroy(ActorDestroyReason why)
+{
+#if defined(OS_WIN)
+    if (why == AbnormalShutdown) {
+        // If the plugin process crashes, this is the only
+        // chance we get to destroy resources.
+        SharedSurfaceRelease();
+        UnsubclassPluginWindow();
+        // If we crashed in a modal loop in the child, reset
+        // the rpc event spin loop state.
+        if (mNestedEventState) {
+            mNestedEventState = false;
+            PostThreadMessage(GetCurrentThreadId(),
+                              gOOPPStopNativeLoopEvent,
+                              0, 0);
+        }
+    }
+#endif
+}
+
+NPError
+PluginInstanceParent::Destroy()
+{
+    NPError retval;
+    if (!CallNPP_Destroy(&retval))
+        retval = NPERR_GENERIC_ERROR;
+
+#if defined(OS_WIN)
+    SharedSurfaceRelease();
+    UnsubclassPluginWindow();
+    if (mNestedEventState) {
+        mNestedEventState = false;
+        PostThreadMessage(GetCurrentThreadId(),
+                          gOOPPStopNativeLoopEvent,
+                          0, 0);
+    }
+#endif
+
+    return retval;
+}
+
+PBrowserStreamParent*
+PluginInstanceParent::AllocPBrowserStream(const nsCString& url,
+                                          const uint32_t& length,
+                                          const uint32_t& lastmodified,
+                                          PStreamNotifyParent* notifyData,
+                                          const nsCString& headers,
+                                          const nsCString& mimeType,
+                                          const bool& seekable,
+                                          NPError* rv,
+                                          uint16_t *stype)
+{
+    NS_RUNTIMEABORT("Not reachable");
+    return NULL;
+}
+
+bool
+PluginInstanceParent::DeallocPBrowserStream(PBrowserStreamParent* stream)
+{
+    delete stream;
+    return true;
+}
+
+PPluginStreamParent*
+PluginInstanceParent::AllocPPluginStream(const nsCString& mimeType,
+                                         const nsCString& target,
+                                         NPError* result)
+{
+    return new PluginStreamParent(this, mimeType, target, result);
+}
+
+bool
+PluginInstanceParent::DeallocPPluginStream(PPluginStreamParent* stream)
+{
+    delete stream;
+    return true;
+}
+
+#ifdef MOZ_X11
+static Display* GetXDisplay() {
+#  ifdef MOZ_WIDGET_GTK2
+        return GDK_DISPLAY();
+#  elif defined(MOZ_WIDGET_QT)
+        return QX11Info::display();
+#  endif
+}
+#endif
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_NPNVjavascriptEnabledBool(
+                                                       bool* value,
+                                                       NPError* result)
+{
+    NPBool v;
+    *result = mNPNIface->getvalue(mNPP, NPNVjavascriptEnabledBool, &v);
+    *value = v;
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_NPNVisOfflineBool(bool* value,
+                                                           NPError* result)
+{
+    NPBool v;
+    *result = mNPNIface->getvalue(mNPP, NPNVisOfflineBool, &v);
+    *value = v;
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
+                                                            NPError* result)
+{
+#ifdef XP_WIN
+    HWND id;
+#elif defined(MOZ_X11)
+    XID id;
+#else
+    return false;
+#endif
+
+    *result = mNPNIface->getvalue(mNPP, NPNVnetscapeWindow, &id);
+    *value = id;
+    return true;
+}
+
+bool
+PluginInstanceParent::InternalGetValueForNPObject(
+                                         NPNVariable aVariable,
+                                         PPluginScriptableObjectParent** aValue,
+                                         NPError* aResult)
+{
+    NPObject* npobject;
+    NPError result = mNPNIface->getvalue(mNPP, aVariable, (void*)&npobject);
+    if (result == NPERR_NO_ERROR) {
+        NS_ASSERTION(npobject, "Shouldn't return null and NPERR_NO_ERROR!");
+
+        PluginScriptableObjectParent* actor = GetActorForNPObject(npobject);
+        mNPNIface->releaseobject(npobject);
+        if (actor) {
+            *aValue = actor;
+            *aResult = NPERR_NO_ERROR;
+            return true;
+        }
+
+        NS_ERROR("Failed to get actor!");
+        result = NPERR_GENERIC_ERROR;
+    }
+
+    *aValue = nsnull;
+    *aResult = result;
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_NPNVWindowNPObject(
+                                         PPluginScriptableObjectParent** aValue,
+                                         NPError* aResult)
+{
+    return InternalGetValueForNPObject(NPNVWindowNPObject, aValue, aResult);
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_NPNVPluginElementNPObject(
+                                         PPluginScriptableObjectParent** aValue,
+                                         NPError* aResult)
+{
+    return InternalGetValueForNPObject(NPNVPluginElementNPObject, aValue,
+                                       aResult);
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValue_NPNVprivateModeBool(bool* value,
+                                                             NPError* result)
+{
+    NPBool v;
+    *result = mNPNIface->getvalue(mNPP, NPNVprivateModeBool, &v);
+    *value = v;
+    return true;
+}
+
+
+bool
+PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
+    const bool& windowed, NPError* result)
+{
+    NPBool isWindowed = windowed;
+    *result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
+                                  (void*)isWindowed);
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginTransparent(
+    const bool& transparent, NPError* result)
+{
+    NPBool isTransparent = transparent;
+    *result = mNPNIface->setvalue(mNPP, NPPVpluginTransparentBool,
+                                  (void*)isTransparent);
+    return true;
+}
+
+
+bool
+PluginInstanceParent::AnswerNPN_GetURL(const nsCString& url,
+                                       const nsCString& target,
+                                       NPError* result)
+{
+    *result = mNPNIface->geturl(mNPP,
+                                NullableStringGet(url),
+                                NullableStringGet(target));
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_PostURL(const nsCString& url,
+                                        const nsCString& target,
+                                        const nsCString& buffer,
+                                        const bool& file,
+                                        NPError* result)
+{
+    *result = mNPNIface->posturl(mNPP, url.get(), NullableStringGet(target),
+                                 buffer.Length(), buffer.get(), file);
+    return true;
+}
+
+PStreamNotifyParent*
+PluginInstanceParent::AllocPStreamNotify(const nsCString& url,
+                                         const nsCString& target,
+                                         const bool& post,
+                                         const nsCString& buffer,
+                                         const bool& file,
+                                         NPError* result)
+{
+    return new StreamNotifyParent();
+}
+
+bool
+PluginInstanceParent::AnswerPStreamNotifyConstructor(PStreamNotifyParent* actor,
+                                                     const nsCString& url,
+                                                     const nsCString& target,
+                                                     const bool& post,
+                                                     const nsCString& buffer,
+                                                     const bool& file,
+                                                     NPError* result)
+{
+    bool streamDestroyed = false;
+    static_cast<StreamNotifyParent*>(actor)->
+        SetDestructionFlag(&streamDestroyed);
+
+    if (!post) {
+        *result = mNPNIface->geturlnotify(mNPP,
+                                          NullableStringGet(url),
+                                          NullableStringGet(target),
+                                          actor);
+    }
+    else {
+        *result = mNPNIface->posturlnotify(mNPP,
+                                           NullableStringGet(url),
+                                           NullableStringGet(target),
+                                           buffer.Length(),
+                                           NullableStringGet(buffer),
+                                           file, actor);
+    }
+
+    if (!streamDestroyed) {
+        static_cast<StreamNotifyParent*>(actor)->ClearDestructionFlag();
+        if (*result != NPERR_NO_ERROR)
+            PStreamNotifyParent::Send__delete__(actor, NPERR_GENERIC_ERROR);
+    }
+
+    return true;
+}
+
+bool
+PluginInstanceParent::DeallocPStreamNotify(PStreamNotifyParent* notifyData)
+{
+    delete notifyData;
+    return true;
+}
+
+bool
+PluginInstanceParent::RecvNPN_InvalidateRect(const NPRect& rect)
+{
+    mNPNIface->invalidaterect(mNPP, const_cast<NPRect*>(&rect));
+    return true;
+}
+
+NPError
+PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
+{
+    PLUGIN_LOG_DEBUG(("%s (aWindow=%p)", FULLFUNCTION, (void*) aWindow));
+
+    NS_ENSURE_TRUE(aWindow, NPERR_GENERIC_ERROR);
+
+    NPRemoteWindow window;
+    mWindowType = aWindow->type;
+
+#if defined(OS_WIN)
+    // On windowless controls, reset the shared memory surface as needed.
+    if (mWindowType == NPWindowTypeDrawable) {
+        // SharedSurfaceSetWindow will take care of NPRemoteWindow.
+        if (!SharedSurfaceSetWindow(aWindow, window)) {
+          return NPERR_OUT_OF_MEMORY_ERROR;
+        }
+    }
+    else {
+        SubclassPluginWindow(reinterpret_cast<HWND>(aWindow->window));
+
+        window.window = reinterpret_cast<unsigned long>(aWindow->window);
+        window.x = aWindow->x;
+        window.y = aWindow->y;
+        window.width = aWindow->width;
+        window.height = aWindow->height;
+        window.type = aWindow->type;
+    }
+#else
+    window.window = reinterpret_cast<unsigned long>(aWindow->window);
+    window.x = aWindow->x;
+    window.y = aWindow->y;
+    window.width = aWindow->width;
+    window.height = aWindow->height;
+    window.clipRect = aWindow->clipRect; // MacOS specific
+    window.type = aWindow->type;
+#endif
+
+#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
+    const NPSetWindowCallbackStruct* ws_info =
+      static_cast<NPSetWindowCallbackStruct*>(aWindow->ws_info);
+    window.visualID = ws_info->visual ? ws_info->visual->visualid : None;
+    window.colormap = ws_info->colormap;
+#endif
+
+    if (!CallNPP_SetWindow(window))
+        return NPERR_GENERIC_ERROR;
+
+    return NPERR_NO_ERROR;
+}
+
+NPError
+PluginInstanceParent::NPP_GetValue(NPPVariable aVariable,
+                                   void* _retval)
+{
+    switch (aVariable) {
+
+#ifdef MOZ_X11
+    case NPPVpluginNeedsXEmbed: {
+        bool needsXEmbed;
+        NPError rv;
+
+        if (!CallNPP_GetValue_NPPVpluginNeedsXEmbed(&needsXEmbed, &rv)) {
+            return NPERR_GENERIC_ERROR;
+        }
+
+        if (NPERR_NO_ERROR != rv) {
+            return rv;
+        }
+
+        (*(NPBool*)_retval) = needsXEmbed;
+        return NPERR_NO_ERROR;
+    }
+#endif
+
+    case NPPVpluginScriptableNPObject: {
+        PPluginScriptableObjectParent* actor;
+        NPError rv;
+        if (!CallNPP_GetValue_NPPVpluginScriptableNPObject(&actor, &rv)) {
+            return NPERR_GENERIC_ERROR;
+        }
+
+        if (NPERR_NO_ERROR != rv) {
+            return rv;
+        }
+
+        if (!actor) {
+            NS_ERROR("NPPVpluginScriptableNPObject succeeded but null.");
+            return NPERR_GENERIC_ERROR;
+        }
+
+        const NPNetscapeFuncs* npn = mParent->GetNetscapeFuncs();
+        if (!npn) {
+            NS_WARNING("No netscape functions?!");
+            return NPERR_GENERIC_ERROR;
+        }
+
+        NPObject* object =
+            static_cast<PluginScriptableObjectParent*>(actor)->GetObject(true);
+        NS_ASSERTION(object, "This shouldn't ever be null!");
+
+        (*(NPObject**)_retval) = npn->retainobject(object);
+        return NPERR_NO_ERROR;
+    }
+
+    default:
+        PR_LOG(gPluginLog, PR_LOG_WARNING,
+               ("In PluginInstanceParent::NPP_GetValue: Unhandled NPPVariable %i (%s)",
+                (int) aVariable, NPPVariableToString(aVariable)));
+        return NPERR_GENERIC_ERROR;
+    }
+}
+
+NPError
+PluginInstanceParent::NPP_SetValue(NPNVariable variable, void* value)
+{
+    switch (variable) {
+    case NPNVprivateModeBool:
+        NPError result;
+        if (!CallNPP_SetValue_NPNVprivateModeBool(*static_cast<NPBool*>(value),
+                                                  &result))
+            return NPERR_GENERIC_ERROR;
+
+        return result;
+
+    default:
+        NS_ERROR("Unhandled NPNVariable in NPP_SetValue");
+        PR_LOG(gPluginLog, PR_LOG_WARNING,
+               ("In PluginInstanceParent::NPP_SetValue: Unhandled NPNVariable %i (%s)",
+                (int) variable, NPNVariableToString(variable)));
+        return NPERR_GENERIC_ERROR;
+    }
+}
+
+int16_t
+PluginInstanceParent::NPP_HandleEvent(void* event)
+{
+    PLUGIN_LOG_DEBUG_FUNCTION;
+
+    NPEvent* npevent = reinterpret_cast<NPEvent*>(event);
+    NPRemoteEvent npremoteevent;
+    npremoteevent.event = *npevent;
+    int16_t handled = 0;
+
+#if defined(OS_WIN)
+    if (mWindowType == NPWindowTypeDrawable) {
+        switch(npevent->event) {
+            case WM_PAINT:
+            {
+                RECT rect;
+                SharedSurfaceBeforePaint(rect, npremoteevent);
+                CallPaint(npremoteevent, &handled);
+                SharedSurfaceAfterPaint(npevent);
+                return handled;
+            }
+            break;
+
+            case WM_KILLFOCUS:
+            {
+              // When the user selects fullscreen mode in Flash video players,
+              // WM_KILLFOCUS will be delayed by deferred event processing:
+              // WM_LBUTTONUP results in a call to CreateWindow within Flash,
+              // which fires WM_KILLFOCUS. Delayed delivery causes Flash to
+              // misinterpret the event, dropping back out of fullscreen. Trap
+              // this event and drop it.
+              PRUnichar szClass[26];
+              HWND hwnd = GetForegroundWindow();
+              if (hwnd && hwnd != mPluginHWND &&
+                  GetClassNameW(hwnd, szClass,
+                                sizeof(szClass)/sizeof(PRUnichar)) &&
+                  !wcscmp(szClass, L"ShockwaveFlashFullScreen")) {
+                  return 0;
+              }
+            }
+            break;
+
+            case WM_WINDOWPOSCHANGED:
+            {
+                // We send this in nsObjectFrame just before painting
+                SendWindowPosChanged(npremoteevent);
+                // nsObjectFrame doesn't care whether we handle this
+                // or not, just returning 1 for good hygiene
+                return 1;
+            }
+            break;
+        }
+    }
+#endif
+
+#if defined(MOZ_X11)
+    switch (npevent->type) {
+    case GraphicsExpose:
+        PLUGIN_LOG_DEBUG(("  schlepping drawable 0x%lx across the pipe\n",
+                          npevent->xgraphicsexpose.drawable));
+        // Make sure the X server has created the Drawable and completes any
+        // drawing before the plugin draws on top.
+        //
+        // XSync() waits for the X server to complete.  Really this parent
+        // process does not need to wait; the child is the process that needs
+        // to wait.  A possibly-slightly-better alternative would be to send
+        // an X event to the child that the child would wait for.
+        XSync(GetXDisplay(), False);
+        break;
+    case ButtonPress:
+        // Release any active pointer grab so that the plugin X client can
+        // grab the pointer if it wishes.
+        Display *dpy = GetXDisplay();
+#  ifdef MOZ_WIDGET_GTK2
+        // GDK attempts to (asynchronously) track whether there is an active
+        // grab so ungrab through GDK.
+        gdk_pointer_ungrab(npevent->xbutton.time);
+#  else
+        XUngrabPointer(dpy, npevent->xbutton.time);
+#  endif
+        // Wait for the ungrab to complete.
+        XSync(dpy, False);
+        break;
+
+        return CallPaint(npremoteevent, &handled) ? handled : 0;
+    }
+#endif
+
+    if (!CallNPP_HandleEvent(npremoteevent, &handled))
+        return 0; // no good way to handle errors here...
+
+    return handled;
+}
+
+NPError
+PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream,
+                                    NPBool seekable, uint16_t* stype)
+{
+    PLUGIN_LOG_DEBUG(("%s (type=%s, stream=%p, seekable=%i)",
+                      FULLFUNCTION, (char*) type, (void*) stream, (int) seekable));
+
+    BrowserStreamParent* bs = new BrowserStreamParent(this, stream);
+
+    NPError err;
+    if (!CallPBrowserStreamConstructor(bs,
+                                       NullableString(stream->url),
+                                       stream->end,
+                                       stream->lastmodified,
+                                       static_cast<PStreamNotifyParent*>(stream->notifyData),
+                                       NullableString(stream->headers),
+                                       NullableString(type), seekable,
+                                       &err, stype))
+        return NPERR_GENERIC_ERROR;
+
+    if (NPERR_NO_ERROR != err)
+        PBrowserStreamParent::Send__delete__(bs);
+
+    return err;
+}
+
+NPError
+PluginInstanceParent::NPP_DestroyStream(NPStream* stream, NPReason reason)
+{
+    PLUGIN_LOG_DEBUG(("%s (stream=%p, reason=%i)",
+                      FULLFUNCTION, (void*) stream, (int) reason));
+
+    AStream* s = static_cast<AStream*>(stream->pdata);
+    if (s->IsBrowserStream()) {
+        BrowserStreamParent* sp =
+            static_cast<BrowserStreamParent*>(s);
+        if (sp->mNPP != this)
+            NS_RUNTIMEABORT("Mismatched plugin data");
+
+        sp->NPP_DestroyStream(reason);
+        return NPERR_NO_ERROR;
+    }
+    else {
+        PluginStreamParent* sp =
+            static_cast<PluginStreamParent*>(s);
+        if (sp->mInstance != this)
+            NS_RUNTIMEABORT("Mismatched plugin data");
+
+        PPluginStreamParent::Call__delete__(sp, reason, false);
+        return NPERR_NO_ERROR;
+    }
+}
+
+void
+PluginInstanceParent::NPP_Print(NPPrint* platformPrint)
+{
+    // TODO: implement me
+    NS_ERROR("Not implemented");
+}
+
+PPluginScriptableObjectParent*
+PluginInstanceParent::AllocPPluginScriptableObject()
+{
+    return new PluginScriptableObjectParent(Proxy);
+}
+
+#ifdef DEBUG
+namespace {
+
+struct ActorSearchData
+{
+    PluginScriptableObjectParent* actor;
+    bool found;
+};
+
+PLDHashOperator
+ActorSearch(const void* aKey,
+            PluginScriptableObjectParent* aData,
+            void* aUserData)
+{
+    ActorSearchData* asd = reinterpret_cast<ActorSearchData*>(aUserData);
+    if (asd->actor == aData) {
+        asd->found = true;
+        return PL_DHASH_STOP;
+    }
+    return PL_DHASH_NEXT;
+}
+
+} // anonymous namespace
+#endif // DEBUG
+
+bool
+PluginInstanceParent::DeallocPPluginScriptableObject(
+                                         PPluginScriptableObjectParent* aObject)
+{
+    PluginScriptableObjectParent* actor =
+        static_cast<PluginScriptableObjectParent*>(aObject);
+
+    NPObject* object = actor->GetObject(false);
+    if (object) {
+        NS_ASSERTION(mScriptableObjects.Get(object, nsnull),
+                     "NPObject not in the hash!");
+        mScriptableObjects.Remove(object);
+    }
+#ifdef DEBUG
+    else {
+        ActorSearchData asd = { actor, false };
+        mScriptableObjects.EnumerateRead(ActorSearch, &asd);
+        NS_ASSERTION(!asd.found, "Actor in the hash with a null NPObject!");
+    }
+#endif
+
+    delete actor;
+    return true;
+}
+
+bool
+PluginInstanceParent::RecvPPluginScriptableObjectConstructor(
+                                          PPluginScriptableObjectParent* aActor)
+{
+    // This is only called in response to the child process requesting the
+    // creation of an actor. This actor will represent an NPObject that is
+    // created by the plugin and returned to the browser.
+    PluginScriptableObjectParent* actor =
+        static_cast<PluginScriptableObjectParent*>(aActor);
+    NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
+
+    actor->InitializeProxy();
+    NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
+
+    return true;
+}
+
+void
+PluginInstanceParent::NPP_URLNotify(const char* url, NPReason reason,
+                                    void* notifyData)
+{
+    PLUGIN_LOG_DEBUG(("%s (%s, %i, %p)",
+                      FULLFUNCTION, url, (int) reason, notifyData));
+
+    PStreamNotifyParent* streamNotify =
+        static_cast<PStreamNotifyParent*>(notifyData);
+    PStreamNotifyParent::Send__delete__(streamNotify, reason);
+}
+
+bool
+PluginInstanceParent::RegisterNPObjectForActor(
+                                           NPObject* aObject,
+                                           PluginScriptableObjectParent* aActor)
+{
+    NS_ASSERTION(aObject && aActor, "Null pointers!");
+    NS_ASSERTION(mScriptableObjects.IsInitialized(), "Hash not initialized!");
+    NS_ASSERTION(!mScriptableObjects.Get(aObject, nsnull), "Duplicate entry!");
+    return !!mScriptableObjects.Put(aObject, aActor);
+}
+
+void
+PluginInstanceParent::UnregisterNPObject(NPObject* aObject)
+{
+    NS_ASSERTION(aObject, "Null pointer!");
+    NS_ASSERTION(mScriptableObjects.IsInitialized(), "Hash not initialized!");
+    NS_ASSERTION(mScriptableObjects.Get(aObject, nsnull), "Unknown entry!");
+    mScriptableObjects.Remove(aObject);
+}
+
+PluginScriptableObjectParent*
+PluginInstanceParent::GetActorForNPObject(NPObject* aObject)
+{
+    NS_ASSERTION(aObject, "Null pointer!");
+
+    if (aObject->_class == PluginScriptableObjectParent::GetClass()) {
+        // One of ours!
+        ParentNPObject* object = static_cast<ParentNPObject*>(aObject);
+        NS_ASSERTION(object->parent, "Null actor!");
+        return object->parent;
+    }
+
+    PluginScriptableObjectParent* actor;
+    if (mScriptableObjects.Get(aObject, &actor)) {
+        return actor;
+    }
+
+    actor = new PluginScriptableObjectParent(LocalObject);
+    if (!actor) {
+        NS_ERROR("Out of memory!");
+        return nsnull;
+    }
+
+    if (!SendPPluginScriptableObjectConstructor(actor)) {
+        NS_WARNING("Failed to send constructor message!");
+        return nsnull;
+    }
+
+    actor->InitializeLocal(aObject);
+    return actor;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_PushPopupsEnabledState(const bool& aState,
+                                                       bool* aSuccess)
+{
+    *aSuccess = mNPNIface->pushpopupsenabledstate(mNPP, aState ? 1 : 0);
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_PopPopupsEnabledState(bool* aSuccess)
+{
+    *aSuccess = mNPNIface->poppopupsenabledstate(mNPP);
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetValueForURL(const NPNURLVariable& variable,
+                                               const nsCString& url,
+                                               nsCString* value,
+                                               NPError* result)
+{
+    char* v;
+    uint32_t len;
+
+    *result = mNPNIface->getvalueforurl(mNPP, (NPNURLVariable) variable,
+                                        url.get(), &v, &len);
+    if (NPERR_NO_ERROR == *result)
+        value->Adopt(v, len);
+
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_SetValueForURL(const NPNURLVariable& variable,
+                                               const nsCString& url,
+                                               const nsCString& value,
+                                               NPError* result)
+{
+    *result = mNPNIface->setvalueforurl(mNPP, (NPNURLVariable) variable,
+                                        url.get(), value.get(),
+                                        value.Length());
+    return true;
+}
+
+bool
+PluginInstanceParent::AnswerNPN_GetAuthenticationInfo(const nsCString& protocol,
+                                                      const nsCString& host,
+                                                      const int32_t& port,
+                                                      const nsCString& scheme,
+                                                      const nsCString& realm,
+                                                      nsCString* username,
+                                                      nsCString* password,
+                                                      NPError* result)
+{
+    char* u;
+    uint32_t ulen;
+    char* p;
+    uint32_t plen;
+
+    *result = mNPNIface->getauthenticationinfo(mNPP, protocol.get(),
+                                               host.get(), port,
+                                               scheme.get(), realm.get(),
+                                               &u, &ulen, &p, &plen);
+    if (NPERR_NO_ERROR == *result) {
+        username->Adopt(u, ulen);
+        password->Adopt(p, plen);
+    }
+    return true;
+}
+
+#if defined(OS_WIN)
+
+/*
+  plugin focus changes between processes
+
+  focus from dom -> child:
+    Focs manager calls on widget to set the focus on the window.
+    We pick up the resulting wm_setfocus event here, and forward
+    that over ipc to the child which calls set focus on itself. 
+
+  focus from child -> focus manager:
+    Child picks up the local wm_setfocus and sends it via ipc over
+    here. We then post a custom event to widget/src/windows/nswindow
+    which fires off a gui event letting the browser know.
+*/
+
+static const PRUnichar kPluginInstanceParentProperty[] =
+                         L"PluginInstanceParentProperty";
+
+// static
+LRESULT CALLBACK
+PluginInstanceParent::PluginWindowHookProc(HWND hWnd,
+                                           UINT message,
+                                           WPARAM wParam,
+                                           LPARAM lParam)
+{
+    PluginInstanceParent* self = reinterpret_cast<PluginInstanceParent*>(
+        ::GetPropW(hWnd, kPluginInstanceParentProperty));
+    if (!self) {
+        NS_NOTREACHED("PluginInstanceParent::PluginWindowHookProc null this ptr!");
+        return DefWindowProc(hWnd, message, wParam, lParam);
+    }
+
+    NS_ASSERTION(self->mPluginHWND == hWnd, "Wrong window!");
+
+    switch (message) {
+        case WM_SETFOCUS:
+        // Let the child plugin window know it should take focus.
+        self->CallSetPluginFocus();
+        break;
+
+        case WM_CLOSE:
+        self->UnsubclassPluginWindow();
+        break;
+    }
+
+    return ::CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
+                            lParam);
+}
+
+void
+PluginInstanceParent::SubclassPluginWindow(HWND aWnd)
+{
+    NS_ASSERTION(!(mPluginHWND && aWnd != mPluginHWND),
+      "PluginInstanceParent::SubclassPluginWindow hwnd is not our window!");
+
+    if (!mPluginHWND) {
+        mPluginHWND = aWnd;
+        mPluginWndProc = 
+            (WNDPROC)::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
+                         reinterpret_cast<LONG>(PluginWindowHookProc));
+        bool bRes = ::SetPropW(mPluginHWND, kPluginInstanceParentProperty, this);
+        NS_ASSERTION(mPluginWndProc,
+          "PluginInstanceParent::SubclassPluginWindow failed to set subclass!");
+        NS_ASSERTION(bRes,
+          "PluginInstanceParent::SubclassPluginWindow failed to set prop!");
+   }
+}
+
+void
+PluginInstanceParent::UnsubclassPluginWindow()
+{
+    if (mPluginHWND && mPluginWndProc) {
+        ::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
+                            reinterpret_cast<LONG>(mPluginWndProc));
+
+        ::RemovePropW(mPluginHWND, kPluginInstanceParentProperty);
+
+        mPluginWndProc = NULL;
+        mPluginHWND = NULL;
+    }
+}
+
+/* windowless drawing helpers */
+
+/*
+ * Origin info:
+ *
+ * windowless, offscreen:
+ *
+ * WM_WINDOWPOSCHANGED: origin is relative to container 
+ * setwindow: origin is 0,0
+ * WM_PAINT: origin is 0,0
+ *
+ * windowless, native:
+ *
+ * WM_WINDOWPOSCHANGED: origin is relative to container 
+ * setwindow: origin is relative to container
+ * WM_PAINT: origin is relative to container
+ *
+ * PluginInstanceParent:
+ *
+ * painting: mPluginPort (nsIntRect, saved in SetWindow)
+ */
+
+void
+PluginInstanceParent::SharedSurfaceRelease()
+{
+    mSharedSurfaceDib.Close();
+}
+
+bool
+PluginInstanceParent::SharedSurfaceSetWindow(const NPWindow* aWindow,
+                                             NPRemoteWindow& aRemoteWindow)
+{
+    aRemoteWindow.window = nsnull;
+    aRemoteWindow.x      = 0;
+    aRemoteWindow.y      = 0;
+    aRemoteWindow.width  = aWindow->width;
+    aRemoteWindow.height = aWindow->height;
+    aRemoteWindow.type   = aWindow->type;
+
+    nsIntRect newPort(aWindow->x, aWindow->y, aWindow->width, aWindow->height);
+
+    // save the the rect location within the browser window.
+    mPluginPort = newPort;
+
+    // move the port to our shared surface origin
+    newPort.MoveTo(0,0);
+
+    // check to see if we have the room in shared surface
+    if (mSharedSurfaceDib.IsValid() && mSharedSize.Contains(newPort)) {
+      // ok to paint
+      aRemoteWindow.surfaceHandle = 0;
+      return true;
+    }
+
+    // allocate a new shared surface
+    SharedSurfaceRelease();
+    if (NS_FAILED(mSharedSurfaceDib.Create(reinterpret_cast<HDC>(aWindow->window),
+                                           newPort.width, newPort.height, 32)))
+      return false;
+
+    // save the new shared surface size we just allocated
+    mSharedSize = newPort;
+
+    base::SharedMemoryHandle handle;
+    if (NS_FAILED(mSharedSurfaceDib.ShareToProcess(mParent->ChildProcessHandle(), &handle)))
+      return false;
+
+    aRemoteWindow.surfaceHandle = handle;
+
+    return true;
+}
+
+void
+PluginInstanceParent::SharedSurfaceBeforePaint(RECT& rect,
+                                               NPRemoteEvent& npremoteevent)
+{
+    RECT* dr = (RECT*)npremoteevent.event.lParam;
+    HDC parentHdc = (HDC)npremoteevent.event.wParam;
+
+    nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top);
+    dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y); // should always be smaller than dirtyRect
+
+    ::BitBlt(mSharedSurfaceDib.GetHDC(),
+             dirtyRect.x,
+             dirtyRect.y,
+             dirtyRect.width,
+             dirtyRect.height,
+             parentHdc,
+             dr->left,
+             dr->top,
+             SRCCOPY);
+
+    // setup the translated dirty rect we'll send to the child
+    rect.left   = dirtyRect.x;
+    rect.top    = dirtyRect.y;
+    rect.right  = dirtyRect.x + dirtyRect.width;
+    rect.bottom = dirtyRect.y + dirtyRect.height;
+
+    npremoteevent.event.wParam = WPARAM(0);
+    npremoteevent.event.lParam = LPARAM(&rect);
+}
+
+void
+PluginInstanceParent::SharedSurfaceAfterPaint(NPEvent* npevent)
+{
+    RECT* dr = (RECT*)npevent->lParam;
+    HDC parentHdc = (HDC)npevent->wParam;
+
+    nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top);
+    dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y);
+
+    // src copy the shared dib into the parent surface we are handed.
+    ::BitBlt(parentHdc,
+             dr->left,
+             dr->top,
+             dirtyRect.width,
+             dirtyRect.height,
+             mSharedSurfaceDib.GetHDC(),
+             dirtyRect.x,
+             dirtyRect.y,
+             SRCCOPY);
+}
+
+#endif // defined(OS_WIN)
+
+bool
+PluginInstanceParent::AnswerPluginGotFocus()
+{
+    PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
+
+    // Currently only in use on windows - an rpc event we receive from the
+    // child when it's plugin window (or one of it's children) receives keyboard
+    // focus. We forward the event down to widget so the dom/focus manager can
+    // be updated.
+#if defined(OS_WIN)
+    ::SendMessage(mPluginHWND, gOOPPPluginFocusEvent, 0, 0);
+    return true;
+#else
+    NS_NOTREACHED("PluginInstanceParent::AnswerPluginGotFocus not implemented!");
+    return false;
+#endif
+}
+
+bool
+PluginInstanceParent::RecvSetNestedEventState(const bool& aState)
+{
+    PLUGIN_LOG_DEBUG(("%s state=%i", FULLFUNCTION, (int)aState));
+#if defined(OS_WIN)
+    PostThreadMessage(GetCurrentThreadId(), aState ?
+        gOOPPSpinNativeLoopEvent : gOOPPStopNativeLoopEvent, 0, 0);
+    mNestedEventState = aState;
+    return true;
+#else
+    NS_NOTREACHED(
+        "PluginInstanceParent::AnswerSetNestedEventState not implemented!");
+    return false;
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginInstanceParent.h
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 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 Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@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 dom_plugins_PluginInstanceParent_h
+#define dom_plugins_PluginInstanceParent_h 1
+
+#include "mozilla/plugins/PPluginInstanceParent.h"
+#include "mozilla/plugins/PluginScriptableObjectParent.h"
+#if defined(OS_WIN)
+#include "mozilla/gfx/SharedDIBWin.h"
+#endif
+
+#include "npfunctions.h"
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+#include "nsRect.h"
+
+namespace mozilla {
+namespace plugins {
+
+class PBrowserStreamParent;
+class PluginModuleParent;
+
+class PluginInstanceParent : public PPluginInstanceParent
+{
+    friend class PluginModuleParent;
+    friend class BrowserStreamParent;
+    friend class PluginStreamParent;
+
+public:
+    PluginInstanceParent(PluginModuleParent* parent,
+                         NPP npp,
+                         const NPNetscapeFuncs* npniface);
+
+    virtual ~PluginInstanceParent();
+
+    bool Init();
+    NPError Destroy();
+
+    NS_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why);
+
+    virtual PPluginScriptableObjectParent*
+    AllocPPluginScriptableObject();
+
+    NS_OVERRIDE virtual bool
+    RecvPPluginScriptableObjectConstructor(PPluginScriptableObjectParent* aActor);
+
+    virtual bool
+    DeallocPPluginScriptableObject(PPluginScriptableObjectParent* aObject);
+    virtual PBrowserStreamParent*
+    AllocPBrowserStream(const nsCString& url,
+                        const uint32_t& length,
+                        const uint32_t& lastmodified,
+                        PStreamNotifyParent* notifyData,
+                        const nsCString& headers,
+                        const nsCString& mimeType,
+                        const bool& seekable,
+                        NPError* rv,
+                        uint16_t *stype);
+    virtual bool
+    DeallocPBrowserStream(PBrowserStreamParent* stream);
+
+    virtual PPluginStreamParent*
+    AllocPPluginStream(const nsCString& mimeType,
+                       const nsCString& target,
+                       NPError* result);
+    virtual bool
+    DeallocPPluginStream(PPluginStreamParent* stream);
+
+    virtual bool
+    AnswerNPN_GetValue_NPNVjavascriptEnabledBool(bool* value, NPError* result);
+    virtual bool
+    AnswerNPN_GetValue_NPNVisOfflineBool(bool* value, NPError* result);
+    virtual bool
+    AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
+                                          NPError* result);
+    virtual bool
+    AnswerNPN_GetValue_NPNVWindowNPObject(
+                                       PPluginScriptableObjectParent** value,
+                                       NPError* result);
+    virtual bool
+    AnswerNPN_GetValue_NPNVPluginElementNPObject(
+                                       PPluginScriptableObjectParent** value,
+                                       NPError* result);
+    virtual bool
+    AnswerNPN_GetValue_NPNVprivateModeBool(bool* value, NPError* result);
+
+    virtual bool
+    AnswerNPN_SetValue_NPPVpluginWindow(const bool& windowed, NPError* result);
+    virtual bool
+    AnswerNPN_SetValue_NPPVpluginTransparent(const bool& transparent,
+                                             NPError* result);
+
+    virtual bool
+    AnswerNPN_GetURL(const nsCString& url, const nsCString& target,
+                     NPError *result);
+
+    virtual bool
+    AnswerNPN_PostURL(const nsCString& url, const nsCString& target,
+                      const nsCString& buffer, const bool& file,
+                      NPError* result);
+
+    virtual PStreamNotifyParent*
+    AllocPStreamNotify(const nsCString& url, const nsCString& target,
+                       const bool& post, const nsCString& buffer,
+                       const bool& file,
+                       NPError* result);
+
+    NS_OVERRIDE virtual bool
+    AnswerPStreamNotifyConstructor(PStreamNotifyParent* actor,
+                                   const nsCString& url,
+                                   const nsCString& target,
+                                   const bool& post, const nsCString& buffer,
+                                   const bool& file,
+                                   NPError* result);
+
+    virtual bool
+    DeallocPStreamNotify(PStreamNotifyParent* notifyData);
+
+    virtual bool
+    RecvNPN_InvalidateRect(const NPRect& rect);
+
+    virtual bool
+    AnswerNPN_PushPopupsEnabledState(const bool& aState,
+                                     bool* aSuccess);
+
+    virtual bool
+    AnswerNPN_PopPopupsEnabledState(bool* aSuccess);
+
+    NS_OVERRIDE virtual bool
+    AnswerNPN_GetValueForURL(const NPNURLVariable& variable,
+                             const nsCString& url,
+                             nsCString* value, NPError* result);
+
+    NS_OVERRIDE virtual bool
+    AnswerNPN_SetValueForURL(const NPNURLVariable& variable,
+                             const nsCString& url,
+                             const nsCString& value, NPError* result);
+
+    NS_OVERRIDE virtual bool
+    AnswerNPN_GetAuthenticationInfo(const nsCString& protocol,
+                                    const nsCString& host,
+                                    const int32_t& port,
+                                    const nsCString& scheme,
+                                    const nsCString& realm,
+                                    nsCString* username,
+                                    nsCString* password,
+                                    NPError* result);
+
+    NPError NPP_SetWindow(const NPWindow* aWindow);
+
+    NPError NPP_GetValue(NPPVariable variable, void* retval);
+    NPError NPP_SetValue(NPNVariable variable, void* value);
+
+    NPError NPP_NewStream(NPMIMEType type, NPStream* stream,
+                          NPBool seekable, uint16_t* stype);
+    NPError NPP_DestroyStream(NPStream* stream, NPReason reason);
+
+    void NPP_Print(NPPrint* platformPrint);
+
+    int16_t NPP_HandleEvent(void* event);
+
+    void NPP_URLNotify(const char* url, NPReason reason, void* notifyData);
+
+    PluginModuleParent* Module()
+    {
+        return mParent;
+    }
+
+    const NPNetscapeFuncs* GetNPNIface()
+    {
+        return mNPNIface;
+    }
+
+    bool
+    RegisterNPObjectForActor(NPObject* aObject,
+                             PluginScriptableObjectParent* aActor);
+
+    void
+    UnregisterNPObject(NPObject* aObject);
+
+    PluginScriptableObjectParent*
+    GetActorForNPObject(NPObject* aObject);
+
+    NPP
+    GetNPP()
+    {
+      return mNPP;
+    }
+
+    virtual bool
+    AnswerPluginGotFocus();
+
+    virtual bool
+    RecvSetNestedEventState(const bool& aState);
+
+private:
+    bool InternalGetValueForNPObject(NPNVariable aVariable,
+                                     PPluginScriptableObjectParent** aValue,
+                                     NPError* aResult);
+
+private:
+    PluginModuleParent* mParent;
+    NPP mNPP;
+    const NPNetscapeFuncs* mNPNIface;
+    NPWindowType mWindowType;
+
+    nsDataHashtable<nsVoidPtrHashKey, PluginScriptableObjectParent*> mScriptableObjects;
+
+#if defined(OS_WIN)
+private:
+    // Used in rendering windowless plugins in other processes.
+    bool SharedSurfaceSetWindow(const NPWindow* aWindow, NPRemoteWindow& aRemoteWindow);
+    void SharedSurfaceBeforePaint(RECT &rect, NPRemoteEvent& npremoteevent);
+    void SharedSurfaceAfterPaint(NPEvent* npevent);
+    void SharedSurfaceRelease();
+    // Used in handling parent/child forwarding of events.
+    static LRESULT CALLBACK PluginWindowHookProc(HWND hWnd, UINT message,
+                                                 WPARAM wParam, LPARAM lParam);
+    void SubclassPluginWindow(HWND aWnd);
+    void UnsubclassPluginWindow();
+
+private:
+    gfx::SharedDIBWin  mSharedSurfaceDib;
+    nsIntRect          mPluginPort;
+    nsIntRect          mSharedSize;
+    HWND               mPluginHWND;
+    WNDPROC            mPluginWndProc;
+    bool               mNestedEventState;
+#endif // defined(XP_WIN)
+};
+
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // ifndef dom_plugins_PluginInstanceParent_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/PluginLibrary.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=4 ts=4 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 Foundation.
+ *
+ * The Initial Developer of the Original Code is
+ *   Josh Aas <josh@mozilla.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 th