Merge in bug 461444: remove cases of excessive recursion in makefiles r=ted
authorDave Townsend <dtownsend@oxymoronical.com>
Wed, 27 Jan 2010 11:45:36 -0800
changeset 37565 86498b1cb1c0e082fba5c944ba48974d4e143b35
parent 37563 3d6a406c0067d9bbeec975e0d3a84d1e6662369a (current diff)
parent 37564 54db542b6748f9a9d4571f987535aafe598b72fe (diff)
child 37566 c456003251352236ac3e2520a4b4a12960472acd
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs461444
milestone1.9.3a1pre
Merge in bug 461444: remove cases of excessive recursion in makefiles r=ted
toolkit/mozapps/downloads/DownloadLastDir.jsm
toolkit/mozapps/downloads/DownloadUtils.jsm
toolkit/mozapps/downloads/Makefile.in
toolkit/mozapps/downloads/nsHelperAppDlg.js
toolkit/mozapps/extensions/LightweightThemeManager.jsm
toolkit/mozapps/extensions/Makefile.in
toolkit/mozapps/extensions/nsAddonRepository.js
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/nsExtensionManager.js
toolkit/mozapps/extensions/nsIAddonRepository.idl
toolkit/mozapps/extensions/nsIExtensionManager.idl
toolkit/mozapps/handling/nsContentDispatchChooser.js
toolkit/mozapps/shared/CertUtils.jsm
toolkit/mozapps/shared/FileUtils.jsm
--- a/accessible/src/base/nsAccEvent.cpp
+++ b/accessible/src/base/nsAccEvent.cpp
@@ -85,17 +85,17 @@ nsAccEvent::nsAccEvent(PRUint32 aEventTy
 {
   CaptureIsFromUserInput(aIsFromUserInput);
 }
 
 nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
                        PRBool aIsAsync, EIsFromUserInput aIsFromUserInput,
                        EEventRule aEventRule) :
   mEventType(aEventType), mEventRule(aEventRule), mIsAsync(aIsAsync),
-  mDOMNode(aDOMNode)
+  mNode(do_QueryInterface(aDOMNode))
 {
   CaptureIsFromUserInput(aIsFromUserInput);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccEvent: nsIAccessibleEvent
 
 NS_IMETHODIMP
@@ -133,23 +133,29 @@ nsAccEvent::GetAccessible(nsIAccessible 
 }
 
 NS_IMETHODIMP
 nsAccEvent::GetDOMNode(nsIDOMNode **aDOMNode)
 {
   NS_ENSURE_ARG_POINTER(aDOMNode);
   *aDOMNode = nsnull;
 
-  if (!mDOMNode) {
+  if (!mNode) {
     nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(mAccessible));
     NS_ENSURE_TRUE(accessNode, NS_ERROR_FAILURE);
-    accessNode->GetDOMNode(getter_AddRefs(mDOMNode));
+
+    nsCOMPtr<nsIDOMNode> DOMNode;
+    accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+
+    mNode = do_QueryInterface(DOMNode);
   }
 
-  NS_IF_ADDREF(*aDOMNode = mDOMNode);
+  if (mNode)
+    CallQueryInterface(mNode, aDOMNode);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccEvent::GetAccessibleDocument(nsIAccessibleDocument **aDocAccessible)
 {
   NS_ENSURE_ARG_POINTER(aDocAccessible);
   *aDocAccessible = nsnull;
@@ -170,37 +176,41 @@ nsAccEvent::GetAccessibleDocument(nsIAcc
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccEvent: protected methods
 
 already_AddRefed<nsIAccessible>
 nsAccEvent::GetAccessibleByNode()
 {
-  if (!mDOMNode)
+  if (!mNode)
     return nsnull;
 
   nsCOMPtr<nsIAccessibilityService> accService = 
     do_GetService("@mozilla.org/accessibilityService;1");
   if (!accService)
     return nsnull;
 
+  nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mNode));
+
   nsCOMPtr<nsIAccessible> accessible;
-  accService->GetAccessibleFor(mDOMNode, getter_AddRefs(accessible));
+  accService->GetAccessibleFor(DOMNode, getter_AddRefs(accessible));
 
 #ifdef MOZ_XUL
   // hack for xul tree table. We need a better way for firing delayed event
   // against xul tree table. see bug 386821.
   // There will be problem if some day we want to fire delayed event against
   // the xul tree itself or an unselected treeitem.
-  nsAutoString localName;
-  mDOMNode->GetLocalName(localName);
-  if (localName.EqualsLiteral("tree")) {
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mNode));
+  if (content && content->NodeInfo()->Equals(nsAccessibilityAtoms::tree,
+                                             kNameSpaceID_XUL)) {
+
     nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
-      do_QueryInterface(mDOMNode);
+      do_QueryInterface(mNode);
+
     if (multiSelect) {
       PRInt32 treeIndex = -1;
       multiSelect->GetCurrentIndex(&treeIndex);
       if (treeIndex >= 0) {
         nsRefPtr<nsXULTreeAccessible> treeAcc =
           nsAccUtils::QueryAccessibleTree(accessible);
         if (treeAcc)
           treeAcc->GetTreeItemAccessible(treeIndex, getter_AddRefs(accessible));
@@ -249,170 +259,16 @@ nsAccEvent::CaptureIsFromUserInput(EIsFr
   if (!esm) {
     NS_NOTREACHED("There should always be an ESM for an event");
     return;
   }
 
   mIsFromUserInput = esm->IsHandlingUserInputExternal();
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEvent: static methods
-
-/* static */
-void
-nsAccEvent::ApplyEventRules(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire)
-{
-  PRUint32 numQueuedEvents = aEventsToFire.Length();
-  PRInt32 tail = numQueuedEvents - 1;
-
-  nsAccEvent* tailEvent = aEventsToFire[tail];
-  switch(tailEvent->mEventRule) {
-    case nsAccEvent::eCoalesceFromSameSubtree:
-    {
-      for (PRInt32 index = 0; index < tail; index ++) {
-        nsAccEvent* thisEvent = aEventsToFire[index];
-        if (thisEvent->mEventType != tailEvent->mEventType)
-          continue; // Different type
-
-        if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
-            thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
-          continue; //  Do not need to check
-
-        if (thisEvent->mDOMNode == tailEvent->mDOMNode) {
-          if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
-            CoalesceReorderEventsFromSameSource(thisEvent, tailEvent);
-            continue;
-          }
-
-          // Dupe
-          thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
-          continue;
-        }
-        if (nsCoreUtils::IsAncestorOf(tailEvent->mDOMNode,
-                                      thisEvent->mDOMNode)) {
-          // thisDOMNode is a descendant of tailDOMNode
-          if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
-            CoalesceReorderEventsFromSameTree(tailEvent, thisEvent);
-            continue;
-          }
-
-          // Do not emit thisEvent, also apply this result to sibling
-          // nodes of thisDOMNode.
-          thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
-          ApplyToSiblings(aEventsToFire, 0, index, thisEvent->mEventType,
-                          thisEvent->mDOMNode, nsAccEvent::eDoNotEmit);
-          continue;
-        }
-        if (nsCoreUtils::IsAncestorOf(thisEvent->mDOMNode,
-                                      tailEvent->mDOMNode)) {
-          // tailDOMNode is a descendant of thisDOMNode
-          if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
-            CoalesceReorderEventsFromSameTree(thisEvent, tailEvent);
-            continue;
-          }
-
-          // Do not emit tailEvent, also apply this result to sibling
-          // nodes of tailDOMNode.
-          tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
-          ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
-                          tailEvent->mDOMNode, nsAccEvent::eDoNotEmit);
-          break;
-        }
-      } // for (index)
-
-      if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
-        // Not in another event node's subtree, and no other event is in
-        // this event node's subtree.
-        // This event should be emitted
-        // Apply this result to sibling nodes of tailDOMNode
-        ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
-                        tailEvent->mDOMNode, nsAccEvent::eAllowDupes);
-      }
-    } break; // case eCoalesceFromSameSubtree
-
-    case nsAccEvent::eRemoveDupes:
-    {
-      // Check for repeat events.
-      for (PRInt32 index = 0; index < tail; index ++) {
-        nsAccEvent* accEvent = aEventsToFire[index];
-        if (accEvent->mEventType == tailEvent->mEventType &&
-            accEvent->mEventRule == tailEvent->mEventRule &&
-            accEvent->mDOMNode == tailEvent->mDOMNode) {
-          accEvent->mEventRule = nsAccEvent::eDoNotEmit;
-        }
-      }
-    } break; // case eRemoveDupes
-
-    default:
-      break; // case eAllowDupes, eDoNotEmit
-  } // switch
-}
-
-/* static */
-void
-nsAccEvent::ApplyToSiblings(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire,
-                            PRUint32 aStart, PRUint32 aEnd,
-                            PRUint32 aEventType, nsIDOMNode* aDOMNode,
-                            EEventRule aEventRule)
-{
-  for (PRUint32 index = aStart; index < aEnd; index ++) {
-    nsAccEvent* accEvent = aEventsToFire[index];
-    if (accEvent->mEventType == aEventType &&
-        accEvent->mEventRule != nsAccEvent::eDoNotEmit &&
-        nsCoreUtils::AreSiblings(accEvent->mDOMNode, aDOMNode)) {
-      accEvent->mEventRule = aEventRule;
-    }
-  }
-}
-
-/* static */
-void
-nsAccEvent::CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
-                                                nsAccEvent *aAccEvent2)
-{
-  // Do not emit event2 if event1 is unconditional.
-  nsCOMPtr<nsAccReorderEvent> reorderEvent1 = do_QueryInterface(aAccEvent1);
-  if (reorderEvent1->IsUnconditionalEvent()) {
-    aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
-    return;
-  }
-
-  // Do not emit event1 if event2 is unconditional.
-  nsCOMPtr<nsAccReorderEvent> reorderEvent2 = do_QueryInterface(aAccEvent2);
-  if (reorderEvent2->IsUnconditionalEvent()) {
-    aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
-    return;
-  }
-
-  // Do not emit event2 if event1 is valid, otherwise do not emit event1.
-  if (reorderEvent1->HasAccessibleInReasonSubtree())
-    aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
-  else
-    aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
-}
-
-void
-nsAccEvent::CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
-                                              nsAccEvent *aDescendantAccEvent)
-{
-  // Do not emit descendant event if this event is unconditional.
-  nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(aAccEvent);
-  if (reorderEvent->IsUnconditionalEvent()) {
-    aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
-    return;
-  }
-
-  // Do not emit descendant event if this event is valid otherwise do not emit
-  // this event.
-  if (reorderEvent->HasAccessibleInReasonSubtree())
-    aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
-  else
-    aAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
-}
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccReorderEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsAccReorderEvent, nsAccEvent,
                              nsAccReorderEvent)
 
--- a/accessible/src/base/nsAccEvent.h
+++ b/accessible/src/base/nsAccEvent.h
@@ -133,58 +133,20 @@ protected:
   void CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput);
 
   PRBool mIsFromUserInput;
 
   PRUint32 mEventType;
   EEventRule mEventRule;
   PRPackedBool mIsAsync;
   nsCOMPtr<nsIAccessible> mAccessible;
-  nsCOMPtr<nsIDOMNode> mDOMNode;
+  nsCOMPtr<nsINode> mNode;
   nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
 
-public:
-
-  /**
-   * Apply event rules to pending events, this method is called in
-   * FlushingPendingEvents().
-   * Result of this method:
-   *   Event rule of filtered events will be set to eDoNotEmit.
-   *   Events with other event rule are good to emit.
-   */
-  static void ApplyEventRules(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire);
-
-private:
-  /**
-   * Apply aEventRule to same type event that from sibling nodes of aDOMNode.
-   * @param aEventsToFire    array of pending events
-   * @param aStart           start index of pending events to be scanned
-   * @param aEnd             end index to be scanned (not included)
-   * @param aEventType       target event type
-   * @param aDOMNode         target are siblings of this node
-   * @param aEventRule       the event rule to be applied
-   *                         (should be eDoNotEmit or eAllowDupes)
-   */
-  static void ApplyToSiblings(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire,
-                              PRUint32 aStart, PRUint32 aEnd,
-                              PRUint32 aEventType, nsIDOMNode* aDOMNode,
-                              EEventRule aEventRule);
-
-  /**
-   * Do not emit one of two given reorder events fired for the same DOM node.
-   */
-  static void CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
-                                                  nsAccEvent *aAccEvent2);
-
-  /**
-   * Do not emit one of two given reorder events fired for DOM nodes in the case
-   * when one DOM node is in parent chain of second one.
-   */
-  static void CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
-                                                nsAccEvent *aDescendantAccEvent);
+  friend class nsAccEventQueue;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsAccEvent, NS_ACCEVENT_IMPL_CID)
 
 
 #define NS_ACCREORDEREVENT_IMPL_CID                     \
 {  /* f2629eb8-2458-4358-868c-3912b15b767a */           \
   0xf2629eb8,                                           \
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -70,19 +70,17 @@
 
 /* For documentation of the accessibility architecture, 
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
  */
 
 nsIStringBundle *nsAccessNode::gStringBundle = 0;
 nsIStringBundle *nsAccessNode::gKeyStringBundle = 0;
 nsIDOMNode *nsAccessNode::gLastFocusedNode = 0;
-#ifdef DEBUG
-PRBool nsAccessNode::gIsAccessibilityActive = PR_FALSE;
-#endif
+
 PRBool nsAccessNode::gIsCacheDisabled = PR_FALSE;
 PRBool nsAccessNode::gIsFormFillEnabled = PR_FALSE;
 nsAccessNodeHashtable nsAccessNode::gGlobalDocAccessibleCache;
 
 nsApplicationAccessibleWrap *nsAccessNode::gApplicationAccessible = nsnull;
 
 nsIAccessibilityService*
 nsAccessNode::GetAccService()
@@ -225,17 +223,18 @@ NS_IMETHODIMP nsAccessNode::GetOwnerWind
   if (!docAccessible)
     return NS_ERROR_FAILURE; // This node or doc accessible is shut down
   return docAccessible->GetWindowHandle(aWindow);
 }
 
 already_AddRefed<nsApplicationAccessibleWrap>
 nsAccessNode::GetApplicationAccessible()
 {
-  NS_ASSERTION(gIsAccessibilityActive, "Accessibility wasn't initialized!");
+  NS_ASSERTION(!nsAccessibilityService::gIsShutdown,
+               "Accessibility wasn't initialized!");
 
   if (!gApplicationAccessible) {
     nsApplicationAccessibleWrap::PreCreate();
 
     gApplicationAccessible = new nsApplicationAccessibleWrap();
     if (!gApplicationAccessible)
       return nsnull;
 
@@ -251,19 +250,16 @@ nsAccessNode::GetApplicationAccessible()
   }
 
   NS_ADDREF(gApplicationAccessible);   // Addref because we're a getter
   return gApplicationAccessible;
 }
 
 void nsAccessNode::InitXPAccessibility()
 {
-  NS_ASSERTION(!gIsAccessibilityActive,
-               "Accessibility was initialized already!");
-
   nsCOMPtr<nsIStringBundleService> stringBundleService =
     do_GetService(NS_STRINGBUNDLE_CONTRACTID);
   if (stringBundleService) {
     // Static variables are released in ShutdownAllXPAccessibility();
     stringBundleService->CreateBundle(ACCESSIBLE_BUNDLE_URL, 
                                       &gStringBundle);
     stringBundleService->CreateBundle(PLATFORM_KEYS_BUNDLE_URL, 
                                       &gKeyStringBundle);
@@ -274,19 +270,16 @@ void nsAccessNode::InitXPAccessibility()
   gGlobalDocAccessibleCache.Init(4);
 
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefBranch) {
     prefBranch->GetBoolPref("accessibility.disablecache", &gIsCacheDisabled);
     prefBranch->GetBoolPref("browser.formfill.enable", &gIsFormFillEnabled);
   }
 
-#ifdef DEBUG
-  gIsAccessibilityActive = PR_TRUE;
-#endif
   NotifyA11yInitOrShutdown(PR_TRUE);
 }
 
 void nsAccessNode::NotifyA11yInitOrShutdown(PRBool aIsInit)
 {
   nsCOMPtr<nsIObserverService> obsService =
     do_GetService("@mozilla.org/observer-service;1");
   NS_ASSERTION(obsService, "No observer service to notify of a11y init/shutdown");
@@ -299,33 +292,28 @@ void nsAccessNode::NotifyA11yInitOrShutd
 }
 
 void nsAccessNode::ShutdownXPAccessibility()
 {
   // Called by nsAccessibilityService::Shutdown()
   // which happens when xpcom is shutting down
   // at exit of program
 
-  NS_ASSERTION(gIsAccessibilityActive, "Accessibility was shutdown already!");
-
   NS_IF_RELEASE(gStringBundle);
   NS_IF_RELEASE(gKeyStringBundle);
   NS_IF_RELEASE(gLastFocusedNode);
 
   nsApplicationAccessibleWrap::Unload();
   ClearCache(gGlobalDocAccessibleCache);
 
   // Release gApplicationAccessible after everything else is shutdown
   // so we don't accidently create it again while tearing down root accessibles
   NS_IF_RELEASE(gApplicationAccessible);
   gApplicationAccessible = nsnull;  
 
-#ifdef DEBUG
-  gIsAccessibilityActive = PR_FALSE;
-#endif
   NotifyA11yInitOrShutdown(PR_FALSE);
 }
 
 PRBool
 nsAccessNode::IsDefunct()
 {
   if (!mDOMNode)
     return PR_TRUE;
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -95,21 +95,21 @@ NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODUL
       NS_ENSURE_SUCCESS_BODY(res, ret)                                    \
       return ret;                                                         \
     }                                                                     \
     if (__rv == NS_OK_DEFUNCT_OBJECT)                                     \
       return ret;                                                         \
   PR_END_MACRO
 
 #define NS_ACCESSNODE_IMPL_CID                          \
-{  /* 13555f6e-0c0f-4002-84f6-558d47b8208e */           \
-  0x13555f6e,                                           \
-  0xc0f,                                                \
-  0x4002,                                               \
-  { 0x84, 0xf6, 0x55, 0x8d, 0x47, 0xb8, 0x20, 0x8e }    \
+{  /* 2b07e3d7-00b3-4379-aa0b-ea22e2c8ffda */           \
+  0x2b07e3d7,                                           \
+  0x00b3,                                               \
+  0x4379,                                               \
+  { 0xaa, 0x0b, 0xea, 0x22, 0xe2, 0xc8, 0xff, 0xda }    \
 }
 
 class nsAccessNode: public nsIAccessNode
 {
   public: // construction, destruction
     nsAccessNode(nsIDOMNode *, nsIWeakReference* aShell);
     virtual ~nsAccessNode();
 
@@ -163,19 +163,30 @@ class nsAccessNode: public nsIAccessNode
      */
     virtual nsresult Shutdown();
 
     /**
      * Return frame for the given access node object.
      */
     virtual nsIFrame* GetFrame();
 
+  /**
+   * Return the corresponding press shell for this accessible.
+   */
+  already_AddRefed<nsIPresShell> GetPresShell();
+
+  /**
+   * Return true if the accessible still has presentation shell. Light-weight
+   * version of IsDefunct() method.
+   */
+  PRBool HasWeakShell() const { return !!mWeakShell; }
+
 protected:
     nsresult MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode);
-    already_AddRefed<nsIPresShell> GetPresShell();
+
     nsPresContext* GetPresContext();
     already_AddRefed<nsIAccessibleDocument> GetDocAccessible();
     void LastRelease();
 
     nsCOMPtr<nsIDOMNode> mDOMNode;
     nsCOMPtr<nsIWeakReference> mWeakShell;
 
 #ifdef DEBUG_A11Y
@@ -186,19 +197,16 @@ protected:
      * Notify global nsIObserver's that a11y is getting init'd or shutdown
      */
     static void NotifyA11yInitOrShutdown(PRBool aIsInit);
 
     // Static data, we do our own refcounting for our static data
     static nsIStringBundle *gStringBundle;
     static nsIStringBundle *gKeyStringBundle;
 
-#ifdef DEBUG
-    static PRBool gIsAccessibilityActive;
-#endif
     static PRBool gIsCacheDisabled;
     static PRBool gIsFormFillEnabled;
 
     static nsAccessNodeHashtable gGlobalDocAccessibleCache;
 
 private:
   static nsApplicationAccessibleWrap *gApplicationAccessible;
 };
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -148,16 +148,17 @@ ACCESSIBILITY_ATOM(thead, "thead")
 ACCESSIBILITY_ATOM(textarea, "textarea") // XForms
 ACCESSIBILITY_ATOM(textbox, "textbox")   // XUL
 ACCESSIBILITY_ATOM(toolbaritem, "toolbaritem")   // XUL
 ACCESSIBILITY_ATOM(toolbarseparator, "toolbarseparator")   // XUL
 ACCESSIBILITY_ATOM(toolbarspring, "toolbarspring")   // XUL
 ACCESSIBILITY_ATOM(toolbarspacer, "toolbarspacer")   // XUL
 ACCESSIBILITY_ATOM(tooltip, "tooltip")   // XUL
 ACCESSIBILITY_ATOM(tr, "tr")
+ACCESSIBILITY_ATOM(tree, "tree")
 ACCESSIBILITY_ATOM(ul, "ul")
 
   // Alphabetical list of attributes (DOM)
 ACCESSIBILITY_ATOM(acceltext, "acceltext")
 ACCESSIBILITY_ATOM(accesskey, "accesskey")
 ACCESSIBILITY_ATOM(alt, "alt")
 ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
 ACCESSIBILITY_ATOM(contenteditable, "contenteditable")
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -443,18 +443,18 @@ nsAccessible::GetKeyboardShortcut(nsAStr
   if (!content)
     return NS_ERROR_FAILURE;
 
   PRUint32 key = nsCoreUtils::GetAccessKeyFor(content);
   if (!key && content->IsNodeOfType(nsIContent::eELEMENT)) {
     // Copy access key from label node unless it is labeled
     // via an ancestor <label>, in which case that would be redundant
     nsCOMPtr<nsIContent> labelContent(nsCoreUtils::GetLabelContent(content));
-    nsCOMPtr<nsIDOMNode> labelNode = do_QueryInterface(labelContent);
-    if (labelNode && !nsCoreUtils::IsAncestorOf(labelNode, mDOMNode))
+    nsCOMPtr<nsINode> thisNode = do_QueryInterface(mDOMNode);
+    if (labelContent && !nsCoreUtils::IsAncestorOf(labelContent, thisNode))
       key = nsCoreUtils::GetAccessKeyFor(labelContent);
   }
 
   if (!key)
     return NS_OK;
 
   nsAutoString accesskey(key);
 
@@ -1703,21 +1703,23 @@ nsAccessible::GetState(PRUint32 *aState,
     } else {
       // Expose 'selected' state on ARIA tab if the focus is on internal element
       // of related tabpanel.
       nsCOMPtr<nsIAccessible> tabPanel = nsRelUtils::
         GetRelatedAccessible(this, nsIAccessibleRelation::RELATION_LABEL_FOR);
 
       if (nsAccUtils::Role(tabPanel) == nsIAccessibleRole::ROLE_PROPERTYPAGE) {
         nsCOMPtr<nsIAccessNode> tabPanelAccessNode(do_QueryInterface(tabPanel));
-        nsCOMPtr<nsIDOMNode> tabPanelNode;
-        tabPanelAccessNode->GetDOMNode(getter_AddRefs(tabPanelNode));
-        NS_ENSURE_STATE(tabPanelNode);
-
-        if (nsCoreUtils::IsAncestorOf(tabPanelNode, gLastFocusedNode))
+        nsCOMPtr<nsIDOMNode> tabPanelDOMNode;
+        tabPanelAccessNode->GetDOMNode(getter_AddRefs(tabPanelDOMNode));
+        NS_ENSURE_STATE(tabPanelDOMNode);
+
+        nsCOMPtr<nsINode> tabPanelNode(do_QueryInterface(tabPanelDOMNode));
+        nsCOMPtr<nsINode> lastFocusedNode(do_QueryInterface(gLastFocusedNode));
+        if (nsCoreUtils::IsAncestorOf(tabPanelNode, lastFocusedNode))
           *aState |= nsIAccessibleStates::STATE_SELECTED;
       }
     }
   }
 
   const PRUint32 kExpandCollapseStates =
     nsIAccessibleStates::STATE_COLLAPSED | nsIAccessibleStates::STATE_EXPANDED;
   if ((*aState & kExpandCollapseStates) == kExpandCollapseStates) {
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -264,17 +264,17 @@ nsCaretAccessible::NormalSelectionChange
     textAcc->GetSelectionCount(&selectionCount);   // Don't swallow similar events when selecting text
     if (!selectionCount) {
       return NS_OK;  // Swallow duplicate caret event
     }
   }
   mLastCaretOffset = caretOffset;
   mLastTextAccessible = textAcc;
 
-  nsCOMPtr<nsIAccessibleEvent> event =
+  nsRefPtr<nsAccEvent> event =
     new nsAccCaretMoveEvent(textNode);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
   return mRootAccessible->FireDelayedAccessibleEvent(event);
 }
 
 nsresult
 nsCaretAccessible::SpellcheckSelectionChanged(nsIDOMDocument *aDoc,
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -308,46 +308,36 @@ nsCoreUtils::GetRoleContent(nsIDOMNode *
       }
     }
   }
 
   return content;
 }
 
 PRBool
-nsCoreUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
-                          nsIDOMNode *aPossibleDescendantNode)
+nsCoreUtils::IsAncestorOf(nsINode *aPossibleAncestorNode,
+                          nsINode *aPossibleDescendantNode)
 {
   NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, PR_FALSE);
 
-  nsCOMPtr<nsIDOMNode> loopNode = aPossibleDescendantNode;
-  nsCOMPtr<nsIDOMNode> parentNode;
-  while (NS_SUCCEEDED(loopNode->GetParentNode(getter_AddRefs(parentNode))) &&
-         parentNode) {
-    if (parentNode == aPossibleAncestorNode) {
+  nsINode *parentNode = aPossibleDescendantNode;
+  while ((parentNode = parentNode->GetNodeParent())) {
+    if (parentNode == aPossibleAncestorNode)
       return PR_TRUE;
-    }
-    loopNode.swap(parentNode);
   }
+
   return PR_FALSE;
 }
 
 PRBool
-nsCoreUtils::AreSiblings(nsIDOMNode *aDOMNode1,
-                        nsIDOMNode *aDOMNode2)
+nsCoreUtils::AreSiblings(nsINode *aNode1, nsINode *aNode2)
 {
-  NS_ENSURE_TRUE(aDOMNode1 && aDOMNode2, PR_FALSE);
+  NS_ENSURE_TRUE(aNode1 && aNode2, PR_FALSE);
 
-  nsCOMPtr<nsIDOMNode> parentNode1, parentNode2;
-  if (NS_SUCCEEDED(aDOMNode1->GetParentNode(getter_AddRefs(parentNode1))) &&
-      NS_SUCCEEDED(aDOMNode2->GetParentNode(getter_AddRefs(parentNode2))) &&
-      parentNode1 == parentNode2) {
-    return PR_TRUE;
-  }
-  return PR_FALSE;
+  return aNode1->GetNodeParent() == aNode2->GetNodeParent();
 }
 
 nsresult
 nsCoreUtils::ScrollSubstringTo(nsIFrame *aFrame,
                                nsIDOMNode *aStartNode, PRInt32 aStartIndex,
                                nsIDOMNode *aEndNode, PRInt32 aEndIndex,
                                PRUint32 aScrollType)
 {
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -135,29 +135,33 @@ public:
    * @param aDOMNode  DOM node for the accessible that may be affected by ARIA
    * @return          the nsIContent which may have ARIA markup
    */
   static nsIContent *GetRoleContent(nsIDOMNode *aDOMNode);
 
   /**
    * Is the first passed in node an ancestor of the second?
    * Note: A node is not considered to be the ancestor of itself.
-   * @param aPossibleAncestorNode -- node to test for ancestor-ness of aPossibleDescendantNode
-   * @param aPossibleDescendantNode -- node to test for descendant-ness of aPossibleAncestorNode
-   * @return PR_TRUE if aPossibleAncestorNode is an ancestor of aPossibleDescendantNode
+   *
+   * @param  aPossibleAncestorNode   [in] node to test for ancestor-ness of
+   *                                   aPossibleDescendantNode
+   * @param  aPossibleDescendantNode [in] node to test for descendant-ness of
+   *                                   aPossibleAncestorNode
+   * @return PR_TRUE                  if aPossibleAncestorNode is an ancestor of
+   *                                   aPossibleDescendantNode
    */
-   static PRBool IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
-                              nsIDOMNode *aPossibleDescendantNode);
+   static PRBool IsAncestorOf(nsINode *aPossibleAncestorNode,
+                              nsINode *aPossibleDescendantNode);
 
   /**
    * Are the first node and the second siblings?
+   *
    * @return PR_TRUE if aDOMNode1 and aDOMNode2 have same parent
    */
-   static PRBool AreSiblings(nsIDOMNode *aDOMNode1,
-                             nsIDOMNode *aDOMNode2);
+   static PRBool AreSiblings(nsINode *aNode1, nsINode *aNode2);
 
   /**
    * Helper method to scroll range into view, used for implementation of
    * nsIAccessibleText::scrollSubstringTo().
    *
    * @param aFrame        the frame for accessible the range belongs to.
    * @param aStartNode    start node of a range
    * @param aStartOffset  an offset inside the start node
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -80,18 +80,17 @@ nsIAtom *nsDocAccessible::gLastFocusedFr
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
   nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
   mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
-  mIsLoadCompleteFired(PR_FALSE), mInFlushPendingEvents(PR_FALSE),
-  mFireEventTimerStarted(PR_FALSE)
+  mIsLoadCompleteFired(PR_FALSE)
 {
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessNodeCache.Init(kDefaultCacheSize);
 
   // For GTK+ native window, we do nothing here.
   if (!mDOMNode)
     return;
 
@@ -146,27 +145,24 @@ ElementTraverser(const void *aKey, nsIAc
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mAccessNodeCache entry");
   cb->NoteXPCOMChild(aAccessNode);
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
-  PRUint32 i, length = tmp->mEventsToFire.Length();
-  for (i = 0; i < length; ++i) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventsToFire[i]");
-    cb.NoteXPCOMChild(tmp->mEventsToFire[i].get());
-  }
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventQueue");
+  cb.NoteXPCOMChild(tmp->mEventQueue.get());
 
   tmp->mAccessNodeCache.EnumerateRead(ElementTraverser, &cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mEventsToFire)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventQueue)
   tmp->ClearCache(tmp->mAccessNodeCache);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDocAccessible)
   NS_INTERFACE_MAP_STATIC_AMBIGUOUS(nsDocAccessible)
   NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
@@ -604,63 +600,54 @@ nsDocAccessible::Init()
 
   AddEventListeners();
 
   GetParent(); // Ensure outer doc mParent accessible.
 
   nsresult rv = nsHyperTextAccessibleWrap::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Initialize event queue.
+  mEventQueue = new nsAccEventQueue(this);
+
   // Fire reorder event to notify new accessible document has been created and
   // attached to the tree.
-  nsCOMPtr<nsIAccessibleEvent> reorderEvent =
+  nsRefPtr<nsAccEvent> reorderEvent =
     new nsAccReorderEvent(mParent, PR_FALSE, PR_TRUE, mDOMNode);
   NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
 
   FireDelayedAccessibleEvent(reorderEvent);
   return NS_OK;
 }
 
 nsresult
 nsDocAccessible::Shutdown()
 {
   if (!mWeakShell) {
     return NS_OK;  // Already shutdown
   }
 
+  mEventQueue->Shutdown();
+  mEventQueue = nsnull;
+
   nsCOMPtr<nsIDocShellTreeItem> treeItem =
     nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
   ShutdownChildDocuments(treeItem);
 
   RemoveEventListeners();
 
   mWeakShell = nsnull;  // Avoid reentrancy
 
   ClearCache(mAccessNodeCache);
 
   nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
   mDocument = nsnull;
 
   nsHyperTextAccessibleWrap::Shutdown();
 
-  if (mFireEventTimer) {
-    // Doc being shut down before delayed events were processed.
-    mFireEventTimer->Cancel();
-    mFireEventTimer = nsnull;
-    mEventsToFire.Clear();
-
-    if (mFireEventTimerStarted && !mInFlushPendingEvents) {
-      // Make sure we release the kung fu death grip which is always there when
-      // fire event timer was started but FlushPendingEvents() callback wasn't
-      // triggered yet. If FlushPendingEvents() is in call stack, kung fu death
-      // grip will be released there.
-      NS_RELEASE_THIS();
-    }
-  }
-
   // Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
   // can find the doc or root accessible in the cache if they need it.
   // We don't do this during ShutdownAccessibility() because that is already clearing the cache
   if (!nsAccessibilityService::gIsShutdown)
     gGlobalDocAccessibleCache.Remove(static_cast<void*>(kungFuDeathGripDoc));
 
   return NS_OK;
 }
@@ -1096,24 +1083,24 @@ nsDocAccessible::AttributeChangedImpl(ns
 
     // Note. Checking the XUL or HTML namespace would not seem to gain us
     // anything, because disabled attribute really is going to mean the same
     // thing in any namespace.
 
     // Note. We use the attribute instead of the disabled state bit because
     // ARIA's aria-disabled does not affect the disabled state bit.
 
-    nsCOMPtr<nsIAccessibleEvent> enabledChangeEvent =
+    nsRefPtr<nsAccEvent> enabledChangeEvent =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::EXT_STATE_ENABLED,
                                 PR_TRUE);
 
     FireDelayedAccessibleEvent(enabledChangeEvent);
 
-    nsCOMPtr<nsIAccessibleEvent> sensitiveChangeEvent =
+    nsRefPtr<nsAccEvent> sensitiveChangeEvent =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::EXT_STATE_SENSITIVE,
                                 PR_TRUE);
 
     FireDelayedAccessibleEvent(sensitiveChangeEvent);
     return;
   }
 
@@ -1179,17 +1166,17 @@ nsDocAccessible::AttributeChangedImpl(ns
       }
 
       FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD,
                                  targetNode);
     }
   }
 
   if (aAttribute == nsAccessibilityAtoms::contenteditable) {
-    nsCOMPtr<nsIAccessibleEvent> editableChangeEvent =
+    nsRefPtr<nsAccEvent> editableChangeEvent =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::EXT_STATE_EDITABLE,
                                 PR_TRUE);
     FireDelayedAccessibleEvent(editableChangeEvent);
     return;
   }
 }
 
@@ -1197,26 +1184,26 @@ nsDocAccessible::AttributeChangedImpl(ns
 void
 nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
 {
   nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aContent));
   if (!targetNode)
     return;
 
   if (aAttribute == nsAccessibilityAtoms::aria_required) {
-    nsCOMPtr<nsIAccessibleEvent> event =
+    nsRefPtr<nsAccEvent> event =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::STATE_REQUIRED,
                                 PR_FALSE);
     FireDelayedAccessibleEvent(event);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::aria_invalid) {
-    nsCOMPtr<nsIAccessibleEvent> event =
+    nsRefPtr<nsAccEvent> event =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::STATE_INVALID,
                                 PR_FALSE);
     FireDelayedAccessibleEvent(event);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::aria_activedescendant) {
@@ -1240,53 +1227,53 @@ nsDocAccessible::ARIAAttributeChanged(ns
   }
 
   // The following ARIA attributes only take affect when dynamic content role is present
   if (aAttribute == nsAccessibilityAtoms::aria_checked ||
       aAttribute == nsAccessibilityAtoms::aria_pressed) {
     const PRUint32 kState = (aAttribute == nsAccessibilityAtoms::aria_checked) ?
                             nsIAccessibleStates::STATE_CHECKED : 
                             nsIAccessibleStates::STATE_PRESSED;
-    nsCOMPtr<nsIAccessibleEvent> event =
+    nsRefPtr<nsAccEvent> event =
       new nsAccStateChangeEvent(targetNode, kState, PR_FALSE);
     FireDelayedAccessibleEvent(event);
     if (targetNode == gLastFocusedNode) {
       // State changes for MIXED state currently only supported for focused item, because
       // otherwise we would need access to the old attribute value in this listener.
       // This is because we don't know if the previous value of aria-checked or aria-pressed was "mixed"
       // without caching that info.
       nsCOMPtr<nsIAccessible> accessible;
       event->GetAccessible(getter_AddRefs(accessible));
       if (accessible) {
         PRBool wasMixed = (gLastFocusedAccessiblesState & nsIAccessibleStates::STATE_MIXED) != 0;
         PRBool isMixed  =
           (nsAccUtils::State(accessible) & nsIAccessibleStates::STATE_MIXED) != 0;
         if (wasMixed != isMixed) {
-          nsCOMPtr<nsIAccessibleEvent> event =
+          nsRefPtr<nsAccEvent> event =
             new nsAccStateChangeEvent(targetNode,
                                       nsIAccessibleStates::STATE_MIXED,
                                       PR_FALSE, isMixed);
           FireDelayedAccessibleEvent(event);
         }
       }
     }
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::aria_expanded) {
-    nsCOMPtr<nsIAccessibleEvent> event =
+    nsRefPtr<nsAccEvent> event =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::STATE_EXPANDED,
                                 PR_FALSE);
     FireDelayedAccessibleEvent(event);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::aria_readonly) {
-    nsCOMPtr<nsIAccessibleEvent> event =
+    nsRefPtr<nsAccEvent> event =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::STATE_READONLY,
                                 PR_FALSE);
     FireDelayedAccessibleEvent(event);
     return;
   }
 
   // Fire value change event whenever aria-valuetext is changed, or
@@ -1442,20 +1429,20 @@ nsDocAccessible::GetParent()
 
 void
 nsDocAccessible::FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldAccessible)
 {
   if (nsAccUtils::Role(aPossibleTextFieldAccessible) != nsIAccessibleRole::ROLE_ENTRY)
     return;
 
   // Dependent value change event for text changes in textfields
-  nsCOMPtr<nsIAccessibleEvent> valueChangeEvent =
+  nsRefPtr<nsAccEvent> valueChangeEvent =
     new nsAccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aPossibleTextFieldAccessible,
                    PR_FALSE, eAutoDetect, nsAccEvent::eRemoveDupes);
-  FireDelayedAccessibleEvent(valueChangeEvent );
+  FireDelayedAccessibleEvent(valueChangeEvent);
 }
 
 void
 nsDocAccessible::FireTextChangeEventForText(nsIContent *aContent,
                                             CharacterDataChangeInfo* aInfo,
                                             PRBool aIsInserted)
 {
   if (!mIsContentLoaded || !mDocument) {
@@ -1540,23 +1527,28 @@ nsDocAccessible::CreateTextChangeEventFo
     // A span-level object or something else without an accessible is being removed, where
     // it has no accessible but it has descendant content which is aggregated as text
     // into the parent hypertext.
     // In this case, accessibleToBeRemoved may just be the first
     // accessible that is removed, which affects the text in the hypertext container
     if (!changeAccessible) {
       return nsnull; // No descendant content that represents any text in the hypertext parent
     }
+
+    nsCOMPtr<nsINode> changeNode(do_QueryInterface(aChangeNode));
     nsCOMPtr<nsIAccessible> child = changeAccessible;
     while (PR_TRUE) {
       nsCOMPtr<nsIAccessNode> childAccessNode =
         do_QueryInterface(changeAccessible);
-      nsCOMPtr<nsIDOMNode> childNode;
-      childAccessNode->GetDOMNode(getter_AddRefs(childNode));
-      if (!nsCoreUtils::IsAncestorOf(aChangeNode, childNode)) {
+
+      nsCOMPtr<nsIDOMNode> childDOMNode;
+      childAccessNode->GetDOMNode(getter_AddRefs(childDOMNode));
+
+      nsCOMPtr<nsINode> childNode(do_QueryInterface(childDOMNode));
+      if (!nsCoreUtils::IsAncestorOf(changeNode, childNode)) {
         break;  // We only want accessibles with DOM nodes as children of this node
       }
       length += nsAccUtils::TextLength(child);
       child->GetNextSibling(getter_AddRefs(changeAccessible));
       if (!changeAccessible) {
         break;
       }
       child.swap(changeAccessible);
@@ -1596,281 +1588,189 @@ nsDocAccessible::CreateTextChangeEventFo
 // nsDocAccessible public member
 nsresult
 nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType,
                                             nsIDOMNode *aDOMNode,
                                             nsAccEvent::EEventRule aAllowDupes,
                                             PRBool aIsAsynch,
                                             EIsFromUserInput aIsFromUserInput)
 {
-  nsCOMPtr<nsIAccessibleEvent> event =
+  nsRefPtr<nsAccEvent> event =
     new nsAccEvent(aEventType, aDOMNode, aIsAsynch, aIsFromUserInput, aAllowDupes);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
   return FireDelayedAccessibleEvent(event);
 }
 
 // nsDocAccessible public member
 nsresult
-nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent)
+nsDocAccessible::FireDelayedAccessibleEvent(nsAccEvent *aEvent)
 {
   NS_ENSURE_ARG(aEvent);
 
-  nsRefPtr<nsAccEvent> accEvent = nsAccUtils::QueryObject<nsAccEvent>(aEvent);
-  mEventsToFire.AppendElement(accEvent);
-
-  // Filter events.
-  nsAccEvent::ApplyEventRules(mEventsToFire);
-
-  // Process events.
-  return PreparePendingEventsFlush();
-}
-
-nsresult
-nsDocAccessible::PreparePendingEventsFlush()
-{
-  nsresult rv = NS_OK;
+  if (mEventQueue)
+    mEventQueue->Push(aEvent);
 
-  // Create timer if we don't have it yet.
-  if (!mFireEventTimer) {
-    mFireEventTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // If there are delayed events in the queue and event timer wasn't started
-  // then initialize the timer so that delayed event will be processed in
-  // FlushPendingEvents.
-  if (mEventsToFire.Length() > 0 && !mFireEventTimerStarted) {
-
-    rv = mFireEventTimer->InitWithFuncCallback(FlushEventsCallback,
-                                               this, 0,
-                                               nsITimer::TYPE_ONE_SHOT);
-
-    if (NS_SUCCEEDED(rv)) {
-      // Kung fu death grip to prevent crash in callback.
-      NS_ADDREF_THIS();
-
-      mFireEventTimerStarted = PR_TRUE;
-    }
-  }
-
-  return rv;
+  return NS_OK;
 }
 
 void
-nsDocAccessible::FlushPendingEvents()
-{
-  mInFlushPendingEvents = PR_TRUE;
+nsDocAccessible::ProcessPendingEvent(nsAccEvent *aEvent)
+{  
+  nsCOMPtr<nsIAccessible> accessible;
+  aEvent->GetAccessible(getter_AddRefs(accessible));
+
+  nsCOMPtr<nsIDOMNode> domNode;
+  aEvent->GetDOMNode(getter_AddRefs(domNode));
+
+  PRUint32 eventType = aEvent->GetEventType();
+  EIsFromUserInput isFromUserInput =
+    aEvent->IsFromUserInput() ? eFromUserInput : eNoUserInput;
+
+  PRBool isAsync = aEvent->IsAsync();
 
-  PRUint32 length = mEventsToFire.Length();
-  NS_ASSERTION(length, "How did we get here without events to fire?");
-  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-  if (!presShell)
-    length = 0; // The doc is now shut down, don't fire events in it anymore
-  else {
-    // Flush layout so that all the frame construction, reflow, and styles are
-    // up-to-date. This will ensure we can get frames for the related nodes, as
-    // well as get the most current information for calculating things like
-    // visibility. We don't flush the display because we don't care about
-    // painting. If no flush is necessary the method will simple return.
-    presShell->FlushPendingNotifications(Flush_Layout);
+  if (domNode == gLastFocusedNode && isAsync &&
+      (eventType == nsIAccessibleEvent::EVENT_SHOW ||
+       eventType == nsIAccessibleEvent::EVENT_HIDE)) {
+    // If frame type didn't change for this event, then we don't actually need to invalidate
+    // However, we only keep track of the old frame type for the focus, where it's very
+    // important not to destroy and recreate the accessible for minor style changes,
+    // such as a:focus { overflow: scroll; }
+    nsCOMPtr<nsIContent> focusContent(do_QueryInterface(domNode));
+    if (focusContent) {
+      nsIFrame *focusFrame = focusContent->GetPrimaryFrame();
+      nsIAtom *newFrameType =
+        (focusFrame && focusFrame->GetStyleVisibility()->IsVisible()) ?
+        focusFrame->GetType() : nsnull;
+
+      if (newFrameType == gLastFocusedFrameType) {
+        // Don't need to invalidate this current accessible, but can
+        // just invalidate the children instead
+        FireShowHideEvents(domNode, PR_TRUE, eventType, eNormalEvent,
+                           isAsync, isFromUserInput); 
+        return;
+      }
+      gLastFocusedFrameType = newFrameType;
+    }
   }
 
-  // Process only currently queued events. In the meantime, newly appended
-  // events will not be processed.
-  for (PRUint32 index = 0; index < length; index ++) {
-  
-    // No presshell means the document was shut down duiring event handling
-    // by AT.
-    if (!mWeakShell)
-      break;
+  if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
 
-    nsAccEvent *accEvent = mEventsToFire[index];
+    nsCOMPtr<nsIAccessible> containerAccessible;
+    if (accessible)
+      accessible->GetParent(getter_AddRefs(containerAccessible));
 
-    if (accEvent->GetEventRule() == nsAccEvent::eDoNotEmit)
-      continue;
-
-    nsCOMPtr<nsIAccessible> accessible;
-    accEvent->GetAccessible(getter_AddRefs(accessible));
+    if (!containerAccessible) {
+      GetAccessibleInParentChain(domNode, PR_TRUE,
+                                 getter_AddRefs(containerAccessible));
+      if (!containerAccessible)
+        containerAccessible = this;
+    }
 
-    nsCOMPtr<nsIDOMNode> domNode;
-    accEvent->GetDOMNode(getter_AddRefs(domNode));
-
-    PRUint32 eventType = accEvent->GetEventType();
-    EIsFromUserInput isFromUserInput =
-      accEvent->IsFromUserInput() ? eFromUserInput : eNoUserInput;
+    if (isAsync) {
+      // For asynch show, delayed invalidatation of parent's children
+      nsRefPtr<nsAccessible> containerAcc =
+        nsAccUtils::QueryAccessible(containerAccessible);
+      if (containerAcc)
+        containerAcc->InvalidateChildren();
 
-    PRBool isAsync = accEvent->IsAsync();
+      // Some show events in the subtree may have been removed to 
+      // avoid firing redundant events. But, we still need to make sure any
+      // accessibles parenting those shown nodes lose their child references.
+      InvalidateChildrenInSubtree(domNode);
+    }
 
-    if (domNode == gLastFocusedNode && isAsync &&
-        (eventType == nsIAccessibleEvent::EVENT_SHOW ||
-         eventType == nsIAccessibleEvent::EVENT_HIDE)) {
-      // If frame type didn't change for this event, then we don't actually need to invalidate
-      // However, we only keep track of the old frame type for the focus, where it's very
-      // important not to destroy and recreate the accessible for minor style changes,
-      // such as a:focus { overflow: scroll; }
-      nsCOMPtr<nsIContent> focusContent(do_QueryInterface(domNode));
-      if (focusContent) {
-        nsIFrame *focusFrame = focusContent->GetPrimaryFrame();
-        nsIAtom *newFrameType =
-          (focusFrame && focusFrame->GetStyleVisibility()->IsVisible()) ?
-          focusFrame->GetType() : nsnull;
-
-        if (newFrameType == gLastFocusedFrameType) {
-          // Don't need to invalidate this current accessible, but can
-          // just invalidate the children instead
-          FireShowHideEvents(domNode, PR_TRUE, eventType, eNormalEvent,
-                             isAsync, isFromUserInput); 
-          continue;
-        }
-        gLastFocusedFrameType = newFrameType;
+    // Also fire text changes if the node being created could affect the text in an nsIAccessibleText parent.
+    // When a node is being made visible or is inserted, the text in an ancestor hyper text will gain characters
+    // At this point we now have the frame and accessible for this node if there is one. That is why we
+    // wait to fire this here, instead of in InvalidateCacheSubtree(), where we wouldn't be able to calculate
+    // the offset, length and text for the text change.
+    if (domNode && domNode != mDOMNode) {
+      nsRefPtr<nsAccEvent> textChangeEvent =
+        CreateTextChangeEventForNode(containerAccessible, domNode, accessible,
+                                     PR_TRUE, PR_TRUE, isFromUserInput);
+      if (textChangeEvent) {
+        // XXX Queue them up and merge the text change events
+        // XXX We need a way to ignore SplitNode and JoinNode() when they
+        // do not affect the text within the hypertext
+        nsEventShell::FireEvent(textChangeEvent);
       }
     }
 
-    if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
-
-      nsCOMPtr<nsIAccessible> containerAccessible;
-      if (accessible)
-        accessible->GetParent(getter_AddRefs(containerAccessible));
-
-      if (!containerAccessible) {
-        GetAccessibleInParentChain(domNode, PR_TRUE,
-                                   getter_AddRefs(containerAccessible));
-        if (!containerAccessible)
-          containerAccessible = this;
-      }
+    // Fire show/create events for this node or first accessible descendants of it
+    FireShowHideEvents(domNode, PR_FALSE, eventType, eNormalEvent, isAsync,
+                       isFromUserInput); 
+    return;
+  }
 
-      if (isAsync) {
-        // For asynch show, delayed invalidatation of parent's children
-        nsRefPtr<nsAccessible> containerAcc =
-          nsAccUtils::QueryAccessible(containerAccessible);
-        if (containerAcc)
-          containerAcc->InvalidateChildren();
-
-        // Some show events in the subtree may have been removed to 
-        // avoid firing redundant events. But, we still need to make sure any
-        // accessibles parenting those shown nodes lose their child references.
-        InvalidateChildrenInSubtree(domNode);
-      }
+  if (accessible) {
+    if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
+      nsRefPtr<nsDocAccessible> docAcc =
+        nsAccUtils::QueryAccessibleDocument(accessible);
+      NS_ASSERTION(docAcc, "No doc accessible for doc load event");
 
-      // Also fire text changes if the node being created could affect the text in an nsIAccessibleText parent.
-      // When a node is being made visible or is inserted, the text in an ancestor hyper text will gain characters
-      // At this point we now have the frame and accessible for this node if there is one. That is why we
-      // wait to fire this here, instead of in InvalidateCacheSubtree(), where we wouldn't be able to calculate
-      // the offset, length and text for the text change.
-      if (domNode && domNode != mDOMNode) {
-        nsRefPtr<nsAccEvent> textChangeEvent =
-          CreateTextChangeEventForNode(containerAccessible, domNode, accessible,
-                                       PR_TRUE, PR_TRUE, isFromUserInput);
-        if (textChangeEvent) {
-          // XXX Queue them up and merge the text change events
-          // XXX We need a way to ignore SplitNode and JoinNode() when they
-          // do not affect the text within the hypertext
-          nsEventShell::FireEvent(textChangeEvent);
-        }
-      }
-
-      // Fire show/create events for this node or first accessible descendants of it
-      FireShowHideEvents(domNode, PR_FALSE, eventType, eNormalEvent, isAsync,
-                         isFromUserInput); 
-      continue;
+      if (docAcc)
+        docAcc->FireDocLoadEvents(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
     }
-
-    if (accessible) {
-      if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
-        nsRefPtr<nsDocAccessible> docAcc =
-          nsAccUtils::QueryAccessibleDocument(accessible);
-        NS_ASSERTION(docAcc, "No doc accessible for doc load event");
-
-        if (docAcc)
-          docAcc->FireDocLoadEvents(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
-      }
-      else if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
-        nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryInterface(accessible);
-        PRInt32 caretOffset;
-        if (accessibleText && NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
+    else if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
+      nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryInterface(accessible);
+      PRInt32 caretOffset;
+      if (accessibleText && NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
 #ifdef DEBUG_A11Y
-          PRUnichar chAtOffset;
-          accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
-          printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
+        PRUnichar chAtOffset;
+        accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
+        printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
 #endif
 #ifdef DEBUG_CARET
-          // Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
-          // line-number object attribute on it
-          nsCOMPtr<nsIAccessible> accForFocus;
-          GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
-          nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
+        // Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
+        // line-number object attribute on it
+        nsCOMPtr<nsIAccessible> accForFocus;
+        GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
+        nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
 #endif
-          nsRefPtr<nsAccEvent> caretMoveEvent =
-            new nsAccCaretMoveEvent(accessible, caretOffset);
-          if (!caretMoveEvent)
-            break; // Out of memory, break out to release kung fu death grip
+        nsRefPtr<nsAccEvent> caretMoveEvent =
+          new nsAccCaretMoveEvent(accessible, caretOffset);
+        if (!caretMoveEvent)
+          return;
 
-          nsEventShell::FireEvent(caretMoveEvent);
+        nsEventShell::FireEvent(caretMoveEvent);
 
-          PRInt32 selectionCount;
-          accessibleText->GetSelectionCount(&selectionCount);
-          if (selectionCount) {  // There's a selection so fire selection change as well
-            nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
-                                    accessible, PR_TRUE);
-          }
-        } 
+        PRInt32 selectionCount;
+        accessibleText->GetSelectionCount(&selectionCount);
+        if (selectionCount) {  // There's a selection so fire selection change as well
+          nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
+                                  accessible, PR_TRUE);
+        }
+      } 
+    }
+    else if (eventType == nsIAccessibleEvent::EVENT_REORDER) {
+      // Fire reorder event if it's unconditional (see InvalidateCacheSubtree
+      // method) or if changed node (that is the reason of this reorder event)
+      // is accessible or has accessible children.
+      nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(aEvent);
+      if (reorderEvent->IsUnconditionalEvent() ||
+          reorderEvent->HasAccessibleInReasonSubtree()) {
+        nsEventShell::FireEvent(aEvent);
       }
-      else if (eventType == nsIAccessibleEvent::EVENT_REORDER) {
-        // Fire reorder event if it's unconditional (see InvalidateCacheSubtree
-        // method) or if changed node (that is the reason of this reorder event)
-        // is accessible or has accessible children.
-        nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(accEvent);
-        if (reorderEvent->IsUnconditionalEvent() ||
-            reorderEvent->HasAccessibleInReasonSubtree()) {
-          nsEventShell::FireEvent(accEvent);
-        }
-      }
-      else {
-        nsEventShell::FireEvent(accEvent);
+    }
+    else {
+      nsEventShell::FireEvent(aEvent);
 
-        // Post event processing
-        if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
-          // Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in
-          // this subtree.
-          nsCOMPtr<nsIDOMNode> hidingNode;
-          accEvent->GetDOMNode(getter_AddRefs(hidingNode));
-          if (hidingNode) {
-            RefreshNodes(hidingNode); // Will this bite us with asynch events
-          }
+      // Post event processing
+      if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
+        // Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in
+        // this subtree.
+        nsCOMPtr<nsIDOMNode> hidingNode;
+        aEvent->GetDOMNode(getter_AddRefs(hidingNode));
+        if (hidingNode) {
+          RefreshNodes(hidingNode); // Will this bite us with asynch events
         }
       }
     }
   }
-
-  // Mark we are ready to start event processing timer again.
-  mFireEventTimerStarted = PR_FALSE;
-
-  // If the document accessible is alive then remove processed events from the
-  // queue (otherwise they were removed on shutdown already) and reinitialize
-  // queue processing callback if necessary (new events might occur duiring
-  // delayed event processing).
-  if (mWeakShell) {
-    mEventsToFire.RemoveElementsAt(0, length);
-    PreparePendingEventsFlush();
-  }
-
-  mInFlushPendingEvents = PR_FALSE;
-  NS_RELEASE_THIS(); // Release kung fu death grip.
-}
-
-void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
-{
-  nsDocAccessible *accessibleDoc = static_cast<nsDocAccessible*>(aClosure);
-  NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
-  if (accessibleDoc) {
-    // A lot of crashes were happening here, so now we're reffing the doc
-    // now until the events are flushed
-    accessibleDoc->FlushPendingEvents();
-  }
 }
 
 void nsDocAccessible::InvalidateChildrenInSubtree(nsIDOMNode *aStartNode)
 {
   nsCOMPtr<nsIAccessNode> accessNode;
   GetCachedAccessNode(aStartNode, getter_AddRefs(accessNode));
   nsRefPtr<nsAccessible> acc(nsAccUtils::QueryAccessible(accessNode));
   if (acc)
@@ -2188,17 +2088,17 @@ nsDocAccessible::InvalidateCacheSubtree(
   // changed node (because its frame might not be constructed yet). In this case
   // we fire a conditional reorder event, so that we will later check whether
   // the changed node is accessible or has accessible children.
   // Filtering/coalescing of these events happens during the queue flush.
 
   PRBool isUnconditionalEvent = childAccessible ||
     aChild && nsAccUtils::HasAccessibleChildren(childNode);
 
-  nsCOMPtr<nsIAccessibleEvent> reorderEvent =
+  nsRefPtr<nsAccEvent> reorderEvent =
     new nsAccReorderEvent(containerAccessible, isAsynch,
                           isUnconditionalEvent,
                           aChild ? childNode.get() : nsnull);
   NS_ENSURE_TRUE(reorderEvent,);
 
   FireDelayedAccessibleEvent(reorderEvent);
 }
 
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -51,21 +51,21 @@
 #include "nsCOMArray.h"
 #include "nsIDocShellTreeNode.h"
 
 class nsIScrollableView;
 
 const PRUint32 kDefaultCacheSize = 256;
 
 #define NS_DOCACCESSIBLE_IMPL_CID                       \
-{  /* 11d54d4f-f135-4b1b-80e4-6425a64f703c */           \
-  0x11d54d4f,                                           \
-  0xf135,                                               \
-  0x4b1b,                                               \
-  { 0x80, 0xe4, 0x64, 0x25, 0xa6, 0x4f, 0x70, 0x3c }    \
+{  /* 5641921c-a093-4292-9dca-0b51813db57d */           \
+  0x5641921c,                                           \
+  0xa093,                                               \
+  0x4292,                                               \
+  { 0x9d, 0xca, 0x0b, 0x51, 0x81, 0x3d, 0xb5, 0x7d }    \
 }
 
 class nsDocAccessible : public nsHyperTextAccessibleWrap,
                         public nsIAccessibleDocument,
                         public nsIDocumentObserver,
                         public nsIObserver,
                         public nsIScrollPositionListener,
                         public nsSupportsWeakReference
@@ -130,17 +130,17 @@ public:
                                       PRBool aIsAsynch = PR_FALSE,
                                       EIsFromUserInput aIsFromUserInput = eAutoDetect);
 
   /**
    * Fire accessible event after timeout.
    *
    * @param aEvent  [in] the event to fire
    */
-  nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent);
+  nsresult FireDelayedAccessibleEvent(nsAccEvent *aEvent);
 
   /**
    * Find the accessible object in the accessibility cache that corresponds to
    * the given node or the first ancestor of it that has an accessible object
    * associated with it. Clear that accessible object's parent's cache of
    * accessible children and remove the accessible object and any descendants
    * from the accessible cache. Fires proper events. New accessible objects will
    * be created and cached again on demand.
@@ -167,19 +167,20 @@ public:
   /**
    * Fire document load events.
    *
    * @param  aEventType  [in] nsIAccessibleEvent constant
    */
   virtual void FireDocLoadEvents(PRUint32 aEventType);
 
   /**
-   * Used to flush pending events, called after timeout. See FlushPendingEvents.
+   * Process the event when the queue of pending events is untwisted. Fire
+   * accessible events as result of the processing.
    */
-  static void FlushEventsCallback(nsITimer *aTimer, void *aClosure);
+  void ProcessPendingEvent(nsAccEvent* aEvent);
 
 protected:
   /**
    * Iterates through sub documents and shut them down.
    */
   void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);
 
     virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
@@ -209,26 +210,16 @@ protected:
     /**
      * Fires accessible events when ARIA attribute is changed.
      *
      * @param aContent - node that attribute is changed for
      * @param aAttribute - changed attribute
      */
     void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
 
-  /**
-   * Process delayed (pending) events resulted in normal events firing.
-   */
-  void FlushPendingEvents();
-
-  /**
-   * Start the timer to flush delayed (pending) events.
-   */
-  nsresult PreparePendingEventsFlush();
-
     /**
      * Fire text changed event for character data changed. The method is used
      * from nsIMutationObserver methods.
      *
      * @param aContent     the text node holding changed data
      * @param aInfo        info structure describing how the data was changed
      * @param aIsInserted  the flag pointed whether removed or inserted
      *                     characters should be cause of event
@@ -288,26 +279,23 @@ protected:
      * If the given accessible object is a ROLE_ENTRY, fire a value change event for it
      */
     void FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldAccessible);
 
     nsAccessNodeHashtable mAccessNodeCache;
     void *mWnd;
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
-    nsCOMPtr<nsITimer> mFireEventTimer;
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     PRPackedBool mIsLoadCompleteFired;
 
 protected:
 
-  PRBool mInFlushPendingEvents;
-  PRBool mFireEventTimerStarted;
-  nsTArray<nsRefPtr<nsAccEvent> > mEventsToFire;
+  nsRefPtr<nsAccEventQueue> mEventQueue;
 
     static PRUint32 gLastFocusedAccessiblesState;
     static nsIAtom *gLastFocusedFrameType;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,
                               NS_DOCACCESSIBLE_IMPL_CID)
 
--- a/accessible/src/base/nsEventShell.cpp
+++ b/accessible/src/base/nsEventShell.cpp
@@ -33,17 +33,17 @@
  * 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 "nsEventShell.h"
 
-#include "nsAccessible.h"
+#include "nsDocAccessible.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsEventShell
 ////////////////////////////////////////////////////////////////////////////////
 
 void
 nsEventShell::FireEvent(nsAccEvent *aEvent)
 {
@@ -90,8 +90,318 @@ nsEventShell::GetEventAttributes(nsIDOMN
                                                NS_LITERAL_STRING("false"));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsEventShell: private
 
 PRBool nsEventShell::sEventFromUserInput = PR_FALSE;
 nsCOMPtr<nsIDOMNode> nsEventShell::sEventTargetNode;
+
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccEventQueue
+////////////////////////////////////////////////////////////////////////////////
+
+nsAccEventQueue::nsAccEventQueue(nsDocAccessible *aDocument):
+  mProcessingStarted(PR_FALSE), mDocument(aDocument)
+{
+}
+
+nsAccEventQueue::~nsAccEventQueue()
+{
+  NS_ASSERTION(mDocument, "Queue wasn't shut down!");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccEventQueue: nsISupports and cycle collection
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccEventQueue)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAccEventQueue)
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocument");
+  cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mDocument.get()));
+
+  PRUint32 i, length = tmp->mEvents.Length();
+  for (i = 0; i < length; ++i) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvents[i]");
+    cb.NoteXPCOMChild(tmp->mEvents[i].get());
+  }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAccEventQueue)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mEvents)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAccEventQueue)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAccEventQueue)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccEventQueue: public
+
+void
+nsAccEventQueue::Push(nsAccEvent *aEvent)
+{
+  mEvents.AppendElement(aEvent);
+  
+  // Filter events.
+  CoalesceEvents();
+  
+  // Process events.
+  PrepareFlush();
+}
+
+void
+nsAccEventQueue::Shutdown()
+{
+  mDocument = nsnull;
+  mEvents.Clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccEventQueue: private
+
+void
+nsAccEventQueue::PrepareFlush()
+{
+  // If there are pending events in the queue and events flush isn't planed
+  // yet start events flush asyncroniously.
+  if (mEvents.Length() > 0 && !mProcessingStarted) {
+    NS_DISPATCH_RUNNABLEMETHOD(Flush, this)
+    mProcessingStarted = PR_TRUE;
+  }
+}
+
+void
+nsAccEventQueue::Flush()
+{
+  // If the document accessible is now shut down, don't fire events in it
+  // anymore.
+  if (!mDocument)
+    return;
+
+  nsCOMPtr<nsIPresShell> presShell = mDocument->GetPresShell();
+  if (!presShell)
+    return;
+
+  // Flush layout so that all the frame construction, reflow, and styles are
+  // up-to-date. This will ensure we can get frames for the related nodes, as
+  // well as get the most current information for calculating things like
+  // visibility. We don't flush the display because we don't care about
+  // painting. If no flush is necessary the method will simple return.
+  presShell->FlushPendingNotifications(Flush_Layout);
+
+  // Process only currently queued events. Newly appended events duiring events
+  // flusing won't be processed.
+  PRUint32 length = mEvents.Length();
+  NS_ASSERTION(length, "How did we get here without events to fire?");
+
+  for (PRUint32 index = 0; index < length; index ++) {
+
+    // No presshell means the document was shut down duiring event handling
+    // by AT.
+    if (!mDocument || !mDocument->HasWeakShell())
+      break;
+
+    nsAccEvent *accEvent = mEvents[index];
+    if (accEvent->mEventRule != nsAccEvent::eDoNotEmit)
+      mDocument->ProcessPendingEvent(accEvent);
+  }
+
+  // Mark we are ready to start event processing again.
+  mProcessingStarted = PR_FALSE;
+
+  // If the document accessible is alive then remove processed events from the
+  // queue (otherwise they were removed on shutdown already) and reinitialize
+  // queue processing callback if necessary (new events might occur duiring
+  // delayed event processing).
+  if (mDocument && mDocument->HasWeakShell()) {
+    mEvents.RemoveElementsAt(0, length);
+    PrepareFlush();
+  }
+}
+
+void
+nsAccEventQueue::CoalesceEvents()
+{
+  PRUint32 numQueuedEvents = mEvents.Length();
+  PRInt32 tail = numQueuedEvents - 1;
+
+  nsAccEvent* tailEvent = mEvents[tail];
+  switch(tailEvent->mEventRule) {
+    case nsAccEvent::eCoalesceFromSameSubtree:
+    {
+      for (PRInt32 index = 0; index < tail; index ++) {
+        nsAccEvent* thisEvent = mEvents[index];
+        if (thisEvent->mEventType != tailEvent->mEventType)
+          continue; // Different type
+
+        if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
+            thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
+          continue; //  Do not need to check
+
+        if (thisEvent->mNode == tailEvent->mNode) {
+          if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
+            CoalesceReorderEventsFromSameSource(thisEvent, tailEvent);
+            continue;
+          }
+
+          // Dupe
+          thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
+          continue;
+        }
+
+        // More older show event target (thisNode) can't be contained by recent
+        // show event target (tailNode), i.e be a descendant of tailNode.
+        // XXX: target of older show event caused by DOM node appending can be
+        // contained by target of recent show event caused by style change.
+        // XXX: target of older show event caused by style change can be
+        // contained by target of recent show event caused by style change.
+        PRBool thisCanBeDescendantOfTail =
+          tailEvent->mEventType != nsIAccessibleEvent::EVENT_SHOW ||
+          tailEvent->mIsAsync;
+
+        if (thisCanBeDescendantOfTail &&
+            nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
+          // thisNode is a descendant of tailNode.
+
+          if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
+            CoalesceReorderEventsFromSameTree(tailEvent, thisEvent);
+            continue;
+          }
+
+          // Do not emit thisEvent, also apply this result to sibling nodes of
+          // thisNode.
+          thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
+          ApplyToSiblings(0, index, thisEvent->mEventType,
+                          thisEvent->mNode, nsAccEvent::eDoNotEmit);
+          continue;
+        }
+
+#ifdef DEBUG
+        if (!thisCanBeDescendantOfTail &&
+            nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
+          NS_NOTREACHED("Older event target is a descendant of recent event target!");
+        }
+#endif
+
+        // More older hide event target (thisNode) can't contain recent hide
+        // event target (tailNode), i.e. be ancestor of tailNode.
+        if (tailEvent->mEventType != nsIAccessibleEvent::EVENT_HIDE &&
+            nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
+          // tailNode is a descendant of thisNode
+
+          if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
+            CoalesceReorderEventsFromSameTree(thisEvent, tailEvent);
+            continue;
+          }
+
+          // Do not emit tailEvent, also apply this result to sibling nodes of
+          // tailNode.
+          tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
+          ApplyToSiblings(0, tail, tailEvent->mEventType,
+                          tailEvent->mNode, nsAccEvent::eDoNotEmit);
+          break;
+        }
+
+#ifdef DEBUG
+        if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE &&
+            nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
+          NS_NOTREACHED("More older hide event target is an ancestor of recent hide event target!");
+        }
+#endif
+
+      } // for (index)
+
+      if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
+        // Not in another event node's subtree, and no other event is in this
+        // event node's subtree. This event should be emitted. Apply this result
+        // to sibling nodes of tailNode.
+
+        // We should do this in all cases even when tailEvent is hide event and
+        // it's caused by DOM node removal because the rule can applied for
+        // sibling event targets caused by style changes.
+        ApplyToSiblings(0, tail, tailEvent->mEventType,
+                        tailEvent->mNode, nsAccEvent::eAllowDupes);
+      }
+    } break; // case eCoalesceFromSameSubtree
+
+    case nsAccEvent::eRemoveDupes:
+    {
+      // Check for repeat events.
+      for (PRInt32 index = 0; index < tail; index ++) {
+        nsAccEvent* accEvent = mEvents[index];
+        if (accEvent->mEventType == tailEvent->mEventType &&
+            accEvent->mEventRule == tailEvent->mEventRule &&
+            accEvent->mNode == tailEvent->mNode) {
+          accEvent->mEventRule = nsAccEvent::eDoNotEmit;
+        }
+      }
+    } break; // case eRemoveDupes
+
+    default:
+      break; // case eAllowDupes, eDoNotEmit
+  } // switch
+}
+
+void
+nsAccEventQueue::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
+                                 PRUint32 aEventType, nsINode* aNode,
+                                 nsAccEvent::EEventRule aEventRule)
+{
+  for (PRUint32 index = aStart; index < aEnd; index ++) {
+    nsAccEvent* accEvent = mEvents[index];
+    if (accEvent->mEventType == aEventType &&
+        accEvent->mEventRule != nsAccEvent::eDoNotEmit &&
+        nsCoreUtils::AreSiblings(accEvent->mNode, aNode)) {
+      accEvent->mEventRule = aEventRule;
+    }
+  }
+}
+
+void
+nsAccEventQueue::CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
+                                                     nsAccEvent *aAccEvent2)
+{
+  // Do not emit event2 if event1 is unconditional.
+  nsCOMPtr<nsAccReorderEvent> reorderEvent1 = do_QueryInterface(aAccEvent1);
+  if (reorderEvent1->IsUnconditionalEvent()) {
+    aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
+    return;
+  }
+
+  // Do not emit event1 if event2 is unconditional.
+  nsCOMPtr<nsAccReorderEvent> reorderEvent2 = do_QueryInterface(aAccEvent2);
+  if (reorderEvent2->IsUnconditionalEvent()) {
+    aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
+    return;
+  }
+
+  // Do not emit event2 if event1 is valid, otherwise do not emit event1.
+  if (reorderEvent1->HasAccessibleInReasonSubtree())
+    aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
+  else
+    aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
+}
+
+void
+nsAccEventQueue::CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
+                                                   nsAccEvent *aDescendantAccEvent)
+{
+  // Do not emit descendant event if this event is unconditional.
+  nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(aAccEvent);
+  if (reorderEvent->IsUnconditionalEvent()) {
+    aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
+    return;
+  }
+
+  // Do not emit descendant event if this event is valid otherwise do not emit
+  // this event.
+  if (reorderEvent->HasAccessibleInReasonSubtree())
+    aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
+  else
+    aAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
+}
--- a/accessible/src/base/nsEventShell.h
+++ b/accessible/src/base/nsEventShell.h
@@ -34,18 +34,22 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsEventShell_H_
 #define _nsEventShell_H_
 
+#include "nsCoreUtils.h"
 #include "nsAccEvent.h"
 
+/**
+ * Used for everything about events.
+ */
 class nsEventShell
 {
 public:
 
   /**
    * Fire the accessible event.
    */
   static void FireEvent(nsAccEvent *aEvent);
@@ -72,9 +76,84 @@ public:
   static void GetEventAttributes(nsIDOMNode *aNode,
                                  nsIPersistentProperties *aAttributes);
 
 private:
   static nsCOMPtr<nsIDOMNode> sEventTargetNode;
   static PRBool sEventFromUserInput;
 };
 
+
+/**
+ * Event queue.
+ */
+class nsAccEventQueue : public nsISupports
+{
+public:
+  nsAccEventQueue(nsDocAccessible *aDocument);
+  ~nsAccEventQueue();
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
+
+  /**
+   * Push event to queue, coalesce it if necessary. Start pending processing.
+   */
+  void Push(nsAccEvent *aEvent);
+
+  /**
+   * Shutdown the queue.
+   */
+  void Shutdown();
+
+private:
+
+  /**
+   * Start pending events procesing asyncroniously.
+   */
+  void PrepareFlush();
+  
+  /**
+   * Process pending events. It calls nsDocAccessible::ProcessPendingEvent()
+   * where the real event processing is happen.
+   */
+  void Flush();
+
+  NS_DECL_RUNNABLEMETHOD(nsAccEventQueue, Flush)
+
+  /**
+   * Coalesce redurant events from the queue.
+   */
+  void CoalesceEvents();
+
+  /**
+   * Apply aEventRule to same type event that from sibling nodes of aDOMNode.
+   * @param aEventsToFire    array of pending events
+   * @param aStart           start index of pending events to be scanned
+   * @param aEnd             end index to be scanned (not included)
+   * @param aEventType       target event type
+   * @param aDOMNode         target are siblings of this node
+   * @param aEventRule       the event rule to be applied
+   *                         (should be eDoNotEmit or eAllowDupes)
+   */
+  void ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
+                       PRUint32 aEventType, nsINode* aNode,
+                       nsAccEvent::EEventRule aEventRule);
+
+  /**
+   * Do not emit one of two given reorder events fired for the same DOM node.
+   */
+  void CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
+                                           nsAccEvent *aAccEvent2);
+
+  /**
+   * Do not emit one of two given reorder events fired for DOM nodes in the case
+   * when one DOM node is in parent chain of second one.
+   */
+  void CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
+                                         nsAccEvent *aDescendantAccEvent);
+
+  PRBool mProcessingStarted;
+  nsRefPtr<nsDocAccessible> mDocument;
+  nsTArray<nsRefPtr<nsAccEvent> > mEvents;
+};
+
 #endif
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -484,17 +484,17 @@ nsRootAccessible::FireAccessibleFocusEve
                                     menuBarAccessible, PR_FALSE,
                                     aIsFromUserInput);
           }
         }
       }
     }
   }
   else if (mCurrentARIAMenubar) {
-    nsCOMPtr<nsIAccessibleEvent> menuEndEvent =
+    nsRefPtr<nsAccEvent> menuEndEvent =
       new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
                      PR_FALSE, aIsFromUserInput, nsAccEvent::eAllowDupes);
     if (menuEndEvent) {
       FireDelayedAccessibleEvent(menuEndEvent);
     }
     mCurrentARIAMenubar = nsnull;
   }
 
@@ -1136,18 +1136,21 @@ nsresult
 nsRootAccessible::HandlePopupHidingEvent(nsIDOMNode *aNode,
                                          nsIAccessible *aAccessible)
 {
   // If accessible focus was on or inside popup that closes, then restore it
   // to true current focus. This is the case when we've been getting
   // DOMMenuItemActive events inside of a combo box that closes. The real focus
   // is on the combo box. It's also the case when a popup gets focus in ATK --
   // when it closes we need to fire an event to restore focus to where it was.
+  nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
+  nsCOMPtr<nsINode> lastFocusedNode(do_QueryInterface(gLastFocusedNode));
+
   if (gLastFocusedNode &&
-      nsCoreUtils::IsAncestorOf(aNode, gLastFocusedNode)) {
+      nsCoreUtils::IsAncestorOf(node, lastFocusedNode)) {
     // Focus was on or inside of a popup that's being hidden
     FireCurrentFocusEvent();
   }
 
   // Fire expanded state change event for comboboxes and autocompletes.
   if (!aAccessible)
     return NS_OK;
 
@@ -1163,17 +1166,16 @@ nsRootAccessible::HandlePopupHidingEvent
   if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
       comboboxRole == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
     nsRefPtr<nsAccEvent> event =
       new nsAccStateChangeEvent(comboboxAcc,
                                 nsIAccessibleStates::STATE_EXPANDED,
                                 PR_FALSE, PR_FALSE);
     NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
-    nsRefPtr<nsAccessible> acc(nsAccUtils::QueryAccessible(comboboxAcc));
     nsEventShell::FireEvent(event);
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 #ifdef MOZ_XUL
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -1597,21 +1597,23 @@ NS_IMETHODIMP nsHyperTextAccessible::Set
  */
 NS_IMETHODIMP
 nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
 {
   *aCaretOffset = -1;
 
   // No caret if the focused node is not inside this DOM node and this DOM node
   // is not inside of focused node.
+  nsCOMPtr<nsINode> thisNode(do_QueryInterface(mDOMNode));
+  nsCOMPtr<nsINode> lastFocusedNode(do_QueryInterface(gLastFocusedNode));
   PRBool isInsideOfFocusedNode =
-    nsCoreUtils::IsAncestorOf(gLastFocusedNode, mDOMNode);
+    nsCoreUtils::IsAncestorOf(lastFocusedNode, thisNode);
 
   if (!isInsideOfFocusedNode && mDOMNode != gLastFocusedNode &&
-      !nsCoreUtils::IsAncestorOf(mDOMNode, gLastFocusedNode))
+      !nsCoreUtils::IsAncestorOf(thisNode, lastFocusedNode))
     return NS_OK;
 
   // Turn the focus node and offset of the selection into caret hypretext
   // offset.
   nsCOMPtr<nsISelection> domSel;
   nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
                               nsnull, getter_AddRefs(domSel));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1622,20 +1624,22 @@ nsHyperTextAccessible::GetCaretOffset(PR
 
   PRInt32 focusOffset;
   rv = domSel->GetFocusOffset(&focusOffset);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // No caret if this DOM node is inside of focused node but the selection's
   // focus point is not inside of this DOM node.
   if (isInsideOfFocusedNode) {
-    nsCOMPtr<nsIDOMNode> resultNode =
+    nsCOMPtr<nsIDOMNode> resultDOMNode =
       nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
-    if (resultNode != mDOMNode &&
-        !nsCoreUtils::IsAncestorOf(mDOMNode, resultNode))
+
+    nsCOMPtr<nsINode> resultNode(do_QueryInterface(resultDOMNode));
+    if (resultNode != thisNode &&
+        !nsCoreUtils::IsAncestorOf(thisNode, resultNode))
       return NS_OK;
   }
 
   return DOMPointToHypertextOffset(focusNode, focusOffset, aCaretOffset);
 }
 
 PRInt32 nsHyperTextAccessible::GetCaretLineNumber()
 {
@@ -1648,17 +1652,18 @@ PRInt32 nsHyperTextAccessible::GetCaretL
   NS_ENSURE_TRUE(privateSelection, -1);
   nsCOMPtr<nsFrameSelection> frameSelection;
   privateSelection->GetFrameSelection(getter_AddRefs(frameSelection));
   NS_ENSURE_TRUE(frameSelection, -1);
 
   nsCOMPtr<nsIDOMNode> caretNode;
   domSel->GetFocusNode(getter_AddRefs(caretNode));
   nsCOMPtr<nsIContent> caretContent = do_QueryInterface(caretNode);
-  if (!caretContent || !nsCoreUtils::IsAncestorOf(mDOMNode, caretNode)) {
+  nsCOMPtr<nsINode> thisNode(do_QueryInterface(mDOMNode));
+  if (!caretContent || !nsCoreUtils::IsAncestorOf(thisNode, caretContent)) {
     return -1;
   }
 
   PRInt32 caretOffset, returnOffsetUnused;
   domSel->GetFocusOffset(&caretOffset);
   nsFrameSelection::HINT hint = frameSelection->GetHint();
   nsIFrame *caretFrame = frameSelection->GetFrameForNodeOffset(caretContent, caretOffset,
                                                                hint, &returnOffsetUnused);
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -588,19 +588,16 @@ nsAccessNodeWrap::get_localInterface(
   *localInterface = static_cast<nsIAccessNode*>(this);
   NS_ADDREF_THIS();
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
  
 void nsAccessNodeWrap::InitAccessibility()
 {
-  NS_ASSERTION(!gIsAccessibilityActive,
-               "Accessibility was initialized already!");
-
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefBranch) {
     prefBranch->GetBoolPref("accessibility.disableenumvariant", &gIsEnumVariantSupportDisabled);
   }
 
   if (!gmUserLib) {
     gmUserLib =::LoadLibraryW(L"USER32.DLL");
   }
@@ -617,18 +614,16 @@ void nsAccessNodeWrap::InitAccessibility
   nsAccessNode::InitXPAccessibility();
 }
 
 void nsAccessNodeWrap::ShutdownAccessibility()
 {
   NS_IF_RELEASE(gTextEvent);
   ::DestroyCaret();
 
-  NS_ASSERTION(gIsAccessibilityActive, "Accessibility was shutdown already!");
-
   nsAccessNode::ShutdownXPAccessibility();
 }
 
 int nsAccessNodeWrap::FilterA11yExceptions(unsigned int aCode, EXCEPTION_POINTERS *aExceptionInfo)
 {
   if (aCode == EXCEPTION_ACCESS_VIOLATION) {
 #ifdef MOZ_CRASHREPORTER
     // MSAA swallows crashes (because it is COM-based)
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -899,17 +899,17 @@ 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
 
-pref("dom.ipc.plugins.enabled", false);
+pref("dom.ipc.plugins.enabled", true);
 
 #ifdef XP_WIN
 #ifndef WINCE
 pref("browser.taskbar.previews.enable", true);
 pref("browser.taskbar.previews.max", 20);
 pref("browser.taskbar.previews.cachetime", 20);
 pref("browser.taskbar.lists.enabled", true);
 pref("browser.taskbar.lists.frequent.enabled", true);
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -72,20 +72,16 @@
       <menuitem id="context-copyemail"
                 label="&copyEmailCmd.label;"
                 accesskey="&copyEmailCmd.accesskey;"
                 oncommand="gContextMenu.copyEmail();"/>
       <menuitem id="context-copylink"
                 label="&copyLinkCmd.label;"
                 accesskey="&copyLinkCmd.accesskey;"
                 oncommand="goDoCommand('cmd_copyLink');"/>
-      <menuitem id="context-copylinktext"
-                label="&copyLinkText2Cmd.label;"
-                accesskey="&copyLinkText2Cmd.accesskey;"
-                oncommand="gContextMenu.copyLinkText();"/>
       <menuseparator id="context-sep-copylink"/>
       <menuitem id="context-media-play"
                 label="&mediaPlay.label;"
                 accesskey="&mediaPlay.accesskey;"
                 oncommand="gContextMenu.mediaCommand('play');"/>
       <menuitem id="context-media-pause"
                 label="&mediaPause.label;"
                 accesskey="&mediaPause.accesskey;"
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -433,18 +433,16 @@ nsContextMenu.prototype = {
     // nsDocumentViewer.cpp has code to determine whether we're
     // on a link or an image. we really ought to be using that...
 
     // Copy email link depends on whether we're on an email link.
     this.showItem("context-copyemail", this.onMailtoLink);
 
     // Copy link location depends on whether we're on a non-mailto link.
     this.showItem("context-copylink", this.onLink && !this.onMailtoLink);
-    this.showItem("context-copylinktext",
-                  this.onLink && !this.onImage && !this.isTextSelected);
     this.showItem("context-sep-copylink", this.onLink &&
                   (this.onImage || this.onVideo || this.onAudio));
 
 #ifdef CONTEXT_COPY_IMAGE_CONTENTS
     // Copy image contents depends on whether we're on an image.
     this.showItem("context-copyimage-contents", this.onImage);
 #endif
     // Copy image location depends on whether we're on an image.
@@ -1175,24 +1173,16 @@ nsContextMenu.prototype = {
       // Do nothing.
     }
 
     var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
                     getService(Ci.nsIClipboardHelper);
     clipboard.copyString(addresses);
   },
 
-  copyLinkText: function() {
-    let text = this.linkText();
-
-    let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
-                    getService(Ci.nsIClipboardHelper);
-    clipboard.copyString(text);
-  },
-
   ///////////////
   // Utilities //
   ///////////////
 
   // Show/hide one item (specified via name or the item element itself).
   showItem: function(aItemOrId, aShow) {
     var item = aItemOrId.constructor == String ?
       document.getElementById(aItemOrId) : aItemOrId;
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -168,26 +168,24 @@ function runTest(testNum) {
     case 3:
         // Context menu for text link
         checkContextMenu(["context-openlink",      true,
                           "context-openlinkintab", true,
                           "---",                   null,
                           "context-bookmarklink",  true,
                           "context-savelink",      true,
                           "context-sendlink",      true,
-                          "context-copylink",      true,
-                          "context-copylinktext",  true]);
+                          "context-copylink",      true]);
         closeContextMenu();
         openContextMenuFor(mailto); // Invoke context menu for next test.
         break;
 
     case 4:
         // Context menu for text mailto-link
-        checkContextMenu(["context-copyemail",    true,
-                          "context-copylinktext", true]);
+        checkContextMenu(["context-copyemail", true]);
         closeContextMenu();
         openContextMenuFor(input); // Invoke context menu for next test.
         break;
 
     case 5:
         // Context menu for text input field
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -35,16 +35,17 @@
 @BINPATH@/dictionaries/*
 #ifdef XP_WIN32
 #ifndef WINCE
 @BINPATH@/uninstall/helper.exe
 #endif
 #endif
 
 [xpcom]
+@BINPATH@/dependentlibs.list
 @BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
 #ifdef XP_MACOSX
 @BINPATH@/XUL
 #else
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -799,17 +799,16 @@ components/xuldoc.xpt
 components/xultmpl.xpt
 components/zipwriter.xpt
 components/firefox.xpt
 greprefs/all.js
 greprefs/security-prefs.js
 greprefs/xpinstall.js
 run-mozilla.sh
 firefox
-dependentlibs.list
 components/nsProgressDialog.js
 libwidget.rsrc
 #endif
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
 readme.txt
 chrome/icons/default/default.xpm
 dictionaries/PL.dic
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -303,18 +303,16 @@
 <!ENTITY sendImageCmd.label           "Send Image…">
 <!ENTITY sendImageCmd.accesskey       "n">
 <!ENTITY sendVideoCmd.label           "Send Video…">
 <!ENTITY sendVideoCmd.accesskey       "n">
 <!ENTITY sendAudioCmd.label           "Send Audio…">
 <!ENTITY sendAudioCmd.accesskey       "n">
 <!ENTITY copyLinkCmd.label            "Copy Link Location">
 <!ENTITY copyLinkCmd.accesskey        "a">
-<!ENTITY copyLinkText2Cmd.label       "Copy Link Text">
-<!ENTITY copyLinkText2Cmd.accesskey   "x">
 <!ENTITY copyImageCmd.label           "Copy Image Location">
 <!ENTITY copyImageCmd.accesskey       "o">
 <!ENTITY copyImageContentsCmd.label   "Copy Image">
 <!ENTITY copyImageContentsCmd.accesskey  "y"> 
 <!ENTITY copyVideoURLCmd.label        "Copy Video Location">
 <!ENTITY copyVideoURLCmd.accesskey    "o">
 <!ENTITY copyAudioURLCmd.label        "Copy Audio Location">
 <!ENTITY copyAudioURLCmd.accesskey    "o">
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -490,30 +490,30 @@ user_pref("camino.use_system_proxy_setti
       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 > 0:
+        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 = self.wintypes.DWORD()
+      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):
--- a/build/leaktest.py.in
+++ b/build/leaktest.py.in
@@ -75,10 +75,12 @@ if __name__ == '__main__':
     automation.initializeProfile(PROFILE_DIRECTORY)
     browserEnv = automation.environment()
 
     if not "XPCOM_DEBUG_BREAK" in browserEnv:
         browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
     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/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2372,18 +2372,21 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
       }
       break;
     case nsIDataType::VTYPE_VOID:
     case nsIDataType::VTYPE_EMPTY:
       // Makes us act as if !aBody, don't upload anything
       break;
     default:
       // try variant string
-      rv = aBody->GetAsWString(getter_Copies(serial));
+      PRUnichar* data = nsnull;
+      PRUint32 len = 0;
+      rv = aBody->GetAsWStringWithSize(&len, &data);
       NS_ENSURE_SUCCESS(rv, rv);
+      serial.Adopt(data, len);
       break;
     }
 
     if (serial) {
       // Convert to a byte stream
       nsCOMPtr<nsIScriptableUnicodeConverter> converter =
         do_CreateInstance("@mozilla.org/intl/scriptableunicodeconverter", &rv);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -332,16 +332,18 @@ include $(topsrcdir)/config/rules.mk
 		file_bug503481.sjs \
 		test_bug503481b.html \
 		file_bug503481b_inner.html \
 		test_viewport_scroll.html \
 		test_CSP.html \
 		file_CSP.sjs \
 		file_CSP_main.html \
 		file_CSP_main.js \
+		test_bug540854.html \
+		bug540854.sjs \
 		$(NULL)
 
 # Disabled; see bug 492181
 #		test_plugin_freezing.html
 
 # Disabled for now. Mochitest isn't reliable enough for these.
 # test_bug444546.html \
 # bug444546.sjs \
new file mode 100644
--- /dev/null
+++ b/content/base/test/bug540854.sjs
@@ -0,0 +1,19 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+                             "nsIBinaryInputStream",
+                             "setInputStream");
+
+function handleRequest(request, response)
+{
+  response.setHeader("Content-Type", "text/plain", false);
+
+  var body = new BinaryInputStream(request.bodyInputStream);
+
+  var avail;
+  var bytes = [];
+  while ((avail = body.available()) > 0)
+    Array.prototype.push.apply(bytes, body.readByteArray(avail));
+
+  var data = String.fromCharCode.apply(null, bytes);
+  response.bodyOutputStream.write(data, data.length);
+}
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug540854.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=540854
+-->
+<head>
+  <title>Test for Bug 540854</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=540854">Mozilla Bug 540854</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 540854 **/
+
+
+  var x;
+
+  function getUTF8() {
+    return unescape(encodeURIComponent('\0foo'));
+  }
+
+  function xload() {
+    is(this.responseText, getUTF8(), "Unexpected responseText!");
+    SimpleTest.finish();
+  }
+
+  function runTest() {
+    x = new XMLHttpRequest();
+    x.open("POST", "bug540854.sjs")
+    x.onload = xload;
+    x.send(getUTF8());
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  addLoadEvent(runTest);
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -203,17 +203,17 @@ nsICanvasRenderingContextWebGL_TexImage2
     nsresult rv;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
     JSAutoTempValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
-    if (argc < 3 || (argc > 3 && argc < 9))
+    if (argc < 3)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
     int32 intargs[8];
 
     // convert the first two args, they must be ints
     for (jsuint i = 0; i < 2; ++i) {
--- a/content/media/nsMediaStream.cpp
+++ b/content/media/nsMediaStream.cpp
@@ -190,28 +190,33 @@ nsMediaChannelStream::OnStartRequest(nsI
     }
 
     nsCAutoString ranges;
     hc->GetResponseHeader(NS_LITERAL_CSTRING("Accept-Ranges"),
                           ranges);
     PRBool acceptsRanges = ranges.EqualsLiteral("bytes");
 
     if (mOffset == 0) {
-      // Look for duration headers from known Ogg content systems. In the case
-      // of multiple options for obtaining the duration the order of precedence is;
+      // Look for duration headers from known Ogg content systems.
+      // In the case of multiple options for obtaining the duration
+      // the order of precedence is:
       // 1) The Media resource metadata if possible (done by the decoder itself).
-      // 2) X-Content-Duration.
-      // 3) x-amz-meta-content-duration.
-      // 4) Perform a seek in the decoder to find the value.
+      // 2) Content-Duration message header.
+      // 3) X-AMZ-Meta-Content-Duration.
+      // 4) X-Content-Duration.
+      // 5) Perform a seek in the decoder to find the value.
       nsCAutoString durationText;
       PRInt32 ec = 0;
-      rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-Content-Duration"), durationText);
+      rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("Content-Duration"), durationText);
       if (NS_FAILED(rv)) {
         rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-AMZ-Meta-Content-Duration"), durationText);
       }
+      if (NS_FAILED(rv)) {
+        rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-Content-Duration"), durationText);
+      }
 
       if (NS_SUCCEEDED(rv)) {
         float duration = durationText.ToFloat(&ec);
         if (ec == NS_OK && duration >= 0) {
           mDecoder->SetDuration(PRInt64(NS_round(duration*1000)));
         }
       }
     }
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -188,16 +188,17 @@ ifdef MOZ_OGG
 		test_bug495319.html \
 		test_closing_connections.html \
 		test_contentDuration1.html \
 		test_contentDuration2.html \
 		test_contentDuration3.html \
 		test_contentDuration4.html \
 		test_contentDuration5.html \
 		test_contentDuration6.html \
+		test_contentDuration7.html \
 		test_delay_load.html \
 		test_duration1.html \
 		test_ended1.html \
 		test_ended2.html \
 		test_error_on_404.html \
 		test_info_leak.html \
 		test_onloadedmetadata.html \
 		test_load_candidates.html \
@@ -212,16 +213,17 @@ ifdef MOZ_OGG
 		test_timeupdate2.html \
 		redirect.sjs \
 		contentDuration1.sjs \
 		contentDuration2.sjs \
 		contentDuration3.sjs \
 		contentDuration4.sjs \
 		contentDuration5.sjs \
 		contentDuration6.sjs \
+		contentDuration7.sjs \
 		$(NULL)
 # These tests disabled until we figure out random failures.
 # Bug 492821:
 # test_videoDocumentTitle.html
 # Bug 493692:
 # test_autobuffer2.html
 ifneq ($(OS_ARCH),WINNT)
 # These tests are disabled on windows until we
--- a/content/media/test/contentDuration1.sjs
+++ b/content/media/test/contentDuration1.sjs
@@ -10,14 +10,14 @@ function handleRequest(request, response
   var paths = "tests/content/media/test/320x240.ogv";
   var split = paths.split("/");
   for(var i = 0; i < split.length; ++i) {
     file.append(split[i]);
   }
   fis.init(file, -1, -1, false);
   bis.setInputStream(fis);
   var bytes = bis.readBytes(bis.available());
-  response.setHeader("X-Content-Duration", "0.233", false);
+  response.setHeader("Content-Duration", "0.233", false);
   response.setHeader("Content-Length", ""+bytes.length, false);
   response.setHeader("Content-Type", "video/ogg", false);
   response.write(bytes, bytes.length);
   bis.close();
 }
--- a/content/media/test/contentDuration4.sjs
+++ b/content/media/test/contentDuration4.sjs
@@ -11,14 +11,14 @@ function handleRequest(request, response
   var split = paths.split("/");
   for(var i = 0; i < split.length; ++i) {
     file.append(split[i]);
   }
   fis.init(file, -1, -1, false);
   bis.setInputStream(fis);
   var bytes = bis.readBytes(bis.available());
   response.setStatusLine(request.httpVersion, 200, "Content Follows");
-  response.setHeader("X-Content-Duration", "-5", false);
+  response.setHeader("Content-Duration", "-5", false);
   response.setHeader("Content-Length", ""+bytes.length, false);
   response.setHeader("Content-Type", "video/ogg", false);
   response.write(bytes, bytes.length);
   bis.close();
 }
--- a/content/media/test/contentDuration5.sjs
+++ b/content/media/test/contentDuration5.sjs
@@ -11,13 +11,13 @@ function handleRequest(request, response
   var split = paths.split("/");
   for(var i = 0; i < split.length; ++i) {
     file.append(split[i]);
   }
   fis.init(file, -1, -1, false);
   bis.setInputStream(fis);
   var bytes = bis.readBytes(bis.available());
   response.setStatusLine(request.httpVersion, 200, "Content Follows");
-  response.setHeader("X-Content-Duration", "-6", false);
+  response.setHeader("Content-Duration", "-6", false);
   response.setHeader("Content-Length", ""+bytes.length, false);
   response.setHeader("Content-Type", "video/ogg", false);
   response.write(bytes, bytes.length);
 }
--- a/content/media/test/contentDuration6.sjs
+++ b/content/media/test/contentDuration6.sjs
@@ -11,14 +11,14 @@ function handleRequest(request, response
   var split = paths.split("/");
   for(var i = 0; i < split.length; ++i) {
     file.append(split[i]);
   }
   fis.init(file, -1, -1, false);
   bis.setInputStream(fis);
   var bytes = bis.readBytes(bis.available());
   response.setStatusLine(request.httpVersion, 200, "Content Follows");
-  response.setHeader("X-Content-Duration", "Invalid Float Value", false);
+  response.setHeader("Content-Duration", "Invalid Float Value", false);
   response.setHeader("Content-Length", ""+bytes.length, false);
   response.setHeader("Content-Type", "video/ogg", false);
   response.write(bytes, bytes.length);
   bis.close();
 }
new file mode 100644
--- /dev/null
+++ b/content/media/test/contentDuration7.sjs
@@ -0,0 +1,23 @@
+function handleRequest(request, response)
+{
+  var file = Components.classes["@mozilla.org/file/directory_service;1"].
+                        getService(Components.interfaces.nsIProperties).
+                        get("CurWorkD", Components.interfaces.nsILocalFile);
+  var fis  = Components.classes['@mozilla.org/network/file-input-stream;1'].
+                        createInstance(Components.interfaces.nsIFileInputStream);
+  var bis  = Components.classes["@mozilla.org/binaryinputstream;1"].
+                        createInstance(Components.interfaces.nsIBinaryInputStream);
+  var paths = "tests/content/media/test/320x240.ogv";
+  var split = paths.split("/");
+  for(var i = 0; i < split.length; ++i) {
+    file.append(split[i]);
+  }
+  fis.init(file, -1, -1, false);
+  bis.setInputStream(fis);
+  var bytes = bis.readBytes(bis.available());
+  response.setHeader("X-Content-Duration", "0.233", false);
+  response.setHeader("Content-Length", ""+bytes.length, false);
+  response.setHeader("Content-Type", "video/ogg", false);
+  response.write(bytes, bytes.length);
+  bis.close();
+}
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -8,17 +8,17 @@ var gSmallTests = [
   { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
   { name:"320x240.ogv", type:"video/ogg", width:320, height:240 },
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
 // Used by test_mozLoadFrom.  Need one test file per decoder backend, plus
 // anything for testing clone-specific bugs.
 var gCloneTests = gSmallTests.concat([
-  // Actual duration is ~200ms, we have X-Content-Duration lie about it.
+  // Actual duration is ~200ms, we have Content-Duration lie about it.
   { name:"bug520908.ogv", type:"video/ogg", duration:9000 },
 ]);
 
 // These are files that we want to make sure we can play through.  We can
 // also check metadata.  Put files of the same type together in this list so if
 // something crashes we have some idea of which backend is responsible.
 // Used by test_playback, which expects no error event and one ended event.
 var gPlayTests = [
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_contentDuration7.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Media test: X-Content-Duration</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function on_metadataloaded() {
+  var v = document.getElementById('v');
+  var d = Math.round(v.duration*1000);
+  ok(d == 233, "Checking duration: " + d);
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+<video id='v'
+       src='contentDuration7.sjs'
+       onloadedmetadata='on_metadataloaded();'></video>
+</body>
+</html>
--- a/content/svg/content/src/nsSVGAngle.cpp
+++ b/content/svg/content/src/nsSVGAngle.cpp
@@ -218,21 +218,21 @@ GetValueFromString(const nsAString &aVal
 }
 
 float
 nsSVGAngle::GetUnitScaleFactor() const
 {
   switch (mSpecifiedUnitType) {
   case nsIDOMSVGAngle::SVG_ANGLETYPE_UNSPECIFIED:
   case nsIDOMSVGAngle::SVG_ANGLETYPE_DEG:
-    return static_cast<float>(180.0 / M_PI);
+    return 1;
   case nsIDOMSVGAngle::SVG_ANGLETYPE_RAD:
-    return 1;
+    return static_cast<float>(M_PI / 180.0);
   case nsIDOMSVGAngle::SVG_ANGLETYPE_GRAD:
-    return static_cast<float>(100.0 / M_PI);
+    return 100.0f / 180.0f;
   default:
     NS_NOTREACHED("Unknown unit type");
     return 0;
   }
 }
 
 void
 nsSVGAngle::SetBaseValueInSpecifiedUnits(float aValue,
--- a/content/svg/content/test/test_dataTypes.html
+++ b/content/svg/content/test/test_dataTypes.html
@@ -73,29 +73,29 @@ function runTests()
   is(convolve.targetX.baseVal, 12, "integer baseVal");
   is(convolve.targetX.animVal, 12, "integer animVal");
   convolve.targetX.baseVal = 7;
   is(convolve.targetX.animVal, 7, "integer animVal");
   is(convolve.getAttribute("targetX"), "7", "integer attribute");
 
   // angle attribute
 
-  marker.setAttribute("orient", "0.5rad");
-  is(marker.orientAngle.baseVal.value, 0.5, "angle baseVal");
-  is(marker.orientAngle.animVal.value, 0.5, "angle animVal");
-  
+  marker.setAttribute("orient", "90deg");
+  is(marker.orientAngle.baseVal.value, 90, "angle baseVal");
+  is(marker.orientAngle.animVal.value, 90, "angle animVal");
+
   var baseAngle = marker.orientAngle.baseVal;
   var animAngle = marker.orientAngle.animVal;
-  marker.setAttribute("orient", "0.75rad");
-  is(baseAngle.value, 0.75, "angle baseVal");
-  is(animAngle.value, 0.75, "angle animVal");
+  marker.setAttribute("orient", "45deg");
+  is(baseAngle.value, 45, "angle baseVal");
+  is(animAngle.value, 45, "angle animVal");
 
-  marker.orientAngle.baseVal.value = 0.25;
-  is(marker.orientAngle.animVal.value, 0.25, "angle animVal");
-  is(marker.getAttribute("orient"), "0.25rad", "angle attribute");
+  marker.orientAngle.baseVal.value = 30;
+  is(marker.orientAngle.animVal.value, 30, "angle animVal");
+  is(marker.getAttribute("orient"), "30deg", "angle attribute");
 
   // boolean attribute
 
   convolve.setAttribute("preserveAlpha", "false");
   is(convolve.preserveAlpha.baseVal, false, "boolean baseVal");
   is(convolve.preserveAlpha.animVal, false, "boolean animVal");
   convolve.preserveAlpha.baseVal = true;
   is(convolve.preserveAlpha.animVal, true, "boolean animVal");
@@ -128,17 +128,17 @@ function runTests()
   is(marker.preserveAspectRatio.animVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
   marker.preserveAspectRatio.baseVal.align = 3;
   is(marker.preserveAspectRatio.animVal.align, 3, "preserveAspectRatio animVal");
   is(marker.preserveAspectRatio.animVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
   marker.preserveAspectRatio.baseVal.meetOrSlice = 1;
   is(marker.preserveAspectRatio.animVal.align, 3, "preserveAspectRatio animVal");
   is(marker.preserveAspectRatio.animVal.meetOrSlice, 1, "preserveAspectRatio.meetOrSlice animVal");
   is(marker.getAttribute("preserveAspectRatio"), "xMidYMin meet", "preserveAspectRatio attribute");
-  
+
   var basePreserveAspectRatio = marker.preserveAspectRatio.baseVal;
   var animPreserveAspectRatio = marker.preserveAspectRatio.animVal;
   marker.setAttribute("preserveAspectRatio", "xMaxYMid slice");
   is(basePreserveAspectRatio.align, 7, "preserveAspectRatio.align baseVal");
   is(animPreserveAspectRatio.align, 7, "preserveAspectRatio.align animVal");
   is(basePreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice baseVal");
   is(animPreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
 
--- a/dom/plugins/BrowserStreamChild.cpp
+++ b/dom/plugins/BrowserStreamChild.cpp
@@ -82,16 +82,17 @@ BrowserStreamChild::StreamConstructed(
             PStreamNotifyChild* notifyData,
             const nsCString& headers,
             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)
     mClosed = true;
 
   return rv;
 }
--- a/dom/plugins/PPluginInstance.ipdl
+++ b/dom/plugins/PPluginInstance.ipdl
@@ -156,12 +156,18 @@ child:
     returns (NPError rv,
              uint16_t stype);
 
 parent:
   /* NPN_NewStream */
   rpc PPluginStream(nsCString mimeType,
                     nsCString target)
     returns (NPError result);
+
+parent:
+  rpc PluginGotFocus();
+child:
+  rpc SetPluginFocus();
+  rpc UpdateWindow();
 };
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -679,16 +679,28 @@ PluginInstanceChild::PluginWindowProc(HW
         GetProp(hWnd, kPluginInstanceChildProperty));
     if (!self) {
         NS_NOTREACHED("Badness!");
         return 0;
     }
 
     NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!");
 
+    // 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);
@@ -867,16 +879,48 @@ PluginInstanceChild::SharedSurfacePaint(
               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
--- a/dom/plugins/PluginInstanceChild.h
+++ b/dom/plugins/PluginInstanceChild.h
@@ -140,16 +140,22 @@ protected:
     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);
 
     virtual ~PluginInstanceChild();
 
     bool Initialize();
 
     NPP GetNPP()
--- a/dom/plugins/PluginInstanceParent.cpp
+++ b/dom/plugins/PluginInstanceParent.cpp
@@ -43,27 +43,36 @@
 #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);
 #endif
 
 using namespace mozilla::plugins;
 
 PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
                                            NPP npp,
                                            const NPNetscapeFuncs* npniface)
-  : mParent(parent),
-    mNPP(npp),
-    mNPNIface(npniface),
-    mWindowType(NPWindowTypeWindow)
+  : mParent(parent)
+    , mNPP(npp)
+    , mNPNIface(npniface)
+    , mWindowType(NPWindowTypeWindow)
+#if defined(OS_WIN)
+    , mPluginHWND(NULL)
+    , mPluginWndProc(NULL)
+#endif // defined(XP_WIN)
 {
 }
 
 PluginInstanceParent::~PluginInstanceParent()
 {
     if (mNPP)
         mNPP->pdata = NULL;
 }
@@ -94,16 +103,17 @@ PluginInstanceParent::Destroy()
     NPError retval;
     if (!CallNPP_Destroy(&retval)) {
         NS_WARNING("Failed to send message!");
         return NPERR_GENERIC_ERROR;
     }
 
 #if defined(OS_WIN)
     SharedSurfaceRelease();
+    UnsubclassPluginWindow();
 #endif
 
     return retval;
 }
 
 PBrowserStreamParent*
 PluginInstanceParent::AllocPBrowserStream(const nsCString& url,
                                           const uint32_t& length,
@@ -355,16 +365,18 @@ PluginInstanceParent::NPP_SetWindow(cons
     // 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
@@ -827,16 +839,96 @@ PluginInstanceParent::AnswerNPN_GetAuthe
         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:
+        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 
@@ -951,8 +1043,26 @@ PluginInstanceParent::SharedSurfaceAfter
              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
+}
--- a/dom/plugins/PluginInstanceParent.h
+++ b/dom/plugins/PluginInstanceParent.h
@@ -217,16 +217,19 @@ public:
     GetActorForNPObject(NPObject* aObject);
 
     NPP
     GetNPP()
     {
       return mNPP;
     }
 
+    virtual bool
+    AnswerPluginGotFocus();
+
 private:
     bool InternalGetValueForNPObject(NPNVariable aVariable,
                                      PPluginScriptableObjectParent** aValue,
                                      NPError* aResult);
 
 private:
     PluginModuleParent* mParent;
     NPP mNPP;
@@ -237,21 +240,28 @@ private:
 
 #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;
 #endif // defined(XP_WIN)
 };
 
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // ifndef dom_plugins_PluginInstanceParent_h
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -33,16 +33,32 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "prlock.h"
 #include "nsRegion.h"
 #include "nsISupportsImpl.h"
 
+/*
+ * The SENTINEL values below guaranties that a < or >
+ * comparison with it will be false for all values of the
+ * underlying nscoord type.  E.g. this is always false:
+ *   aCoord > NS_COORD_GREATER_SENTINEL
+ * Setting the mRectListHead dummy rectangle to these values
+ * allows us to loop without checking for the list end.
+ */
+#ifdef NS_COORD_IS_FLOAT
+#define NS_COORD_LESS_SENTINEL nscoord_MIN
+#define NS_COORD_GREATER_SENTINEL nscoord_MAX
+#else
+#define NS_COORD_LESS_SENTINEL PR_INT32_MIN
+#define NS_COORD_GREATER_SENTINEL PR_INT32_MAX
+#endif
+
 // Fast inline analogues of nsRect methods for nsRegion::nsRectFast.
 // Check for emptiness is not required - it is guaranteed by caller.
 
 inline PRBool nsRegion::nsRectFast::Contains (const nsRect& aRect) const
 {
   return (PRBool) ((aRect.x >= x) && (aRect.y >= y) &&
                    (aRect.XMost () <= XMost ()) && (aRect.YMost () <= YMost ()));
 }
@@ -344,51 +360,49 @@ inline void nsRegion::RestoreLinkChain (
 void nsRegion::InsertInPlace (RgnRect* aRect, PRBool aOptimizeOnFly)
 {
   if (mRectCount == 0)
     InsertAfter (aRect, &mRectListHead);
   else
   {
     if (aRect->y > mCurRect->y)
     {
-      mRectListHead.y = PR_INT32_MAX;
-
+      mRectListHead.y = NS_COORD_GREATER_SENTINEL;
       while (aRect->y > mCurRect->next->y)
         mCurRect = mCurRect->next;
 
+      mRectListHead.x = NS_COORD_GREATER_SENTINEL;
       while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
         mCurRect = mCurRect->next;
 
       InsertAfter (aRect, mCurRect);
     } else
     if (aRect->y < mCurRect->y)
     {
-      mRectListHead.y = PR_INT32_MIN;
-
+      mRectListHead.y = NS_COORD_LESS_SENTINEL;
       while (aRect->y < mCurRect->prev->y)
         mCurRect = mCurRect->prev;
 
+      mRectListHead.x = NS_COORD_LESS_SENTINEL;
       while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
         mCurRect = mCurRect->prev;
 
       InsertBefore (aRect, mCurRect);
     } else
     {
       if (aRect->x > mCurRect->x)
       {
-        mRectListHead.y = PR_INT32_MAX;
-
+        mRectListHead.x = NS_COORD_GREATER_SENTINEL;
         while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
           mCurRect = mCurRect->next;
 
         InsertAfter (aRect, mCurRect);
       } else
       {
-        mRectListHead.y = PR_INT32_MIN;
-
+        mRectListHead.x = NS_COORD_LESS_SENTINEL;
         while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
           mCurRect = mCurRect->prev;
 
         InsertBefore (aRect, mCurRect);
       }
     }
   }
 
@@ -666,18 +680,18 @@ nsRegion& nsRegion::And (const nsRegion&
             pSrcRgn1 = pSrcRgn2;
             pSrcRgn2 = Tmp;
           }
 
 
           SetToElements (0);
           pSrcRgn2->SaveLinkChain ();
 
-          pSrcRgn1->mRectListHead.y = PR_INT32_MAX;
-          pSrcRgn2->mRectListHead.y = PR_INT32_MAX;
+          pSrcRgn1->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
+          pSrcRgn2->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
 
           for (RgnRect* pSrcRect1 = pSrcRgn1->mRectListHead.next ;
                pSrcRect1->y < pSrcRgn2->mBoundRect.YMost () ; pSrcRect1 = pSrcRect1->next)
           {
             if (pSrcRect1->Intersects (pSrcRgn2->mBoundRect))   // Rectangle intersects region. Process each rectangle
             {
               RgnRect* pPrev2 = &pSrcRgn2->mRectListHead;
 
@@ -746,17 +760,17 @@ nsRegion& nsRegion::And (const nsRegion&
 
           if (&aRegion == this)   // Copy region if it is both source and result
           {
             TmpRegion.Copy (aRegion);
             pSrcRegion = &TmpRegion;
           }
 
           SetToElements (0);
-          pSrcRegion->mRectListHead.y = PR_INT32_MAX;
+          pSrcRegion->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
 
           for (const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next ;
                pSrcRect->y < aRectFast.YMost () ; pSrcRect = pSrcRect->next)
           {
             if (TmpRect.IntersectRect (*pSrcRect, aRectFast))
               InsertInPlace (new RgnRect (TmpRect));
           }
 
@@ -1071,17 +1085,17 @@ void nsRegion::SubRect (const nsRectFast
   if (&aResult == this)           // Copy region if it is both source and result
   {
     TmpRegion.Copy (*this);
     pSrcRegion = &TmpRegion;
   }
 
   aResult.SetToElements (0);
 
-  (const_cast<nsRegion*>(pSrcRegion))->mRectListHead.y = PR_INT32_MAX;
+  const_cast<nsRegion*>(pSrcRegion)->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
   const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next;
 
   for ( ; pSrcRect->y < aRect.YMost () ; pSrcRect = pSrcRect->next)
   {
     nsRectFast TmpRect;
 
     // If bottom of current rectangle is above the top of aRect then this rectangle
     // could be moved to aCompleted region. Successive aRect rectangles from ordered
--- a/gfx/thebes/src/gfxCoreTextFonts.cpp
+++ b/gfx/thebes/src/gfxCoreTextFonts.cpp
@@ -444,19 +444,19 @@ gfxCoreTextFont::InitTextRun(gfxTextRun 
                 bidiWrap = PR_TRUE;
                 break;
             }
         }
     }
 
     // If there's a possibility of any bidi, we wrap the text with direction overrides
     // to ensure neutrals or characters that were bidi-overridden in HTML behave properly.
-    const UniChar beginLTR[]    = { 0x202d };
-    const UniChar beginRTL[]    = { 0x202e };
-    const UniChar endBidiWrap[] = { 0x202c };
+    const UniChar beginLTR[]    = { 0x202d, 0x20 };
+    const UniChar beginRTL[]    = { 0x202e, 0x20 };
+    const UniChar endBidiWrap[] = { 0x20, 0x202c };
 
     PRUint32 startOffset;
     CFStringRef stringObj;
     if (bidiWrap) {
         startOffset = isRTL ?
             sizeof(beginRTL) / sizeof(beginRTL[0]) : sizeof(beginLTR) / sizeof(beginLTR[0]);
         CFMutableStringRef mutableString =
             ::CFStringCreateMutable(kCFAllocatorDefault,
@@ -633,18 +633,16 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTex
     nsAutoTArray<PRInt32,SMALL_GLYPH_RUN> charToGlyphArray;
     if (!charToGlyphArray.SetLength(stringRange.length))
         return NS_ERROR_OUT_OF_MEMORY;
     PRInt32 *charToGlyph = charToGlyphArray.Elements();
     for (PRInt32 offset = 0; offset < stringRange.length; ++offset)
         charToGlyph[offset] = NO_GLYPH;
     for (PRInt32 g = 0; g < numGlyphs; ++g) {
         PRInt32 loc = glyphToChar[g] - stringRange.location;
-        if (loc == 0 && !isLTR)
-            ++loc; // avoid seeing initial surrogate char as "ligated" with direction override
         if (loc >= 0 && loc < stringRange.length) {
             charToGlyph[loc] = g;
         }
     }
 
     // Find character and glyph clumps that correspond, allowing for ligatures,
     // indic reordering, split glyphs, etc.
     //
--- a/ipc/chromium/src/base/debug_util.cc
+++ b/ipc/chromium/src/base/debug_util.cc
@@ -37,40 +37,41 @@ const void *const *StackTrace::Addresses
   if (trace_.size())
     return &trace_[0];
   return NULL;
 }
 
 namespace mozilla {
 
 EnvironmentLog::EnvironmentLog(const char* varname)
-  : fd_(NULL)
 {
   const char *e = getenv(varname);
-  if (e && *e) {
-    if (!strcmp(e, "-")) {
-      fd_ = fdopen(dup(STDOUT_FILENO), "a");
-    }
-    else {
-      fd_ = fopen(e, "a");
-    }
-  }
+  if (e && *e)
+    fname_ = e;
 }
 
 EnvironmentLog::~EnvironmentLog()
 {
-  if (fd_)
-    fclose(fd_);
 }
 
 void
 EnvironmentLog::print(const char* format, ...)
 {
+  if (!fname_.size())
+    return;
+
+  FILE* f;
+  if (fname_.compare("-") == 0)
+    f = fdopen(dup(STDOUT_FILENO), "a");
+  else
+    f = fopen(fname_.c_str(), "a");
+
+  if (!f)
+    return;
+
   va_list a;
   va_start(a, format);
-  if (fd_) {
-    vfprintf(fd_, format, a);
-    fflush(fd_);
-  }
+  vfprintf(f, format, a);
   va_end(a);
+  fclose(f);
 }
 
 } // namespace mozilla
--- a/ipc/chromium/src/base/debug_util.h
+++ b/ipc/chromium/src/base/debug_util.h
@@ -73,16 +73,16 @@ class EnvironmentLog
 {
 public:
   EnvironmentLog(const char* varname);
   ~EnvironmentLog();
 
   void print(const char* format, ...);
 
 private:
-  FILE* fd_;
+  std::string fname_;
 
   DISALLOW_EVIL_CONSTRUCTORS(EnvironmentLog);
 };
 
 } // namespace mozilla
 
 #endif  // BASE_DEBUG_UTIL_H_
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -233,16 +233,30 @@ bool ClientConnectToFifo(const std::stri
     HANDLE_EINTR(close(fd));
     return false;
   }
 
   *client_socket = fd;
   return true;
 }
 
+#if defined(CHROMIUM_MOZILLA_BUILD)
+bool SetCloseOnExec(int fd) {
+  int flags = fcntl(fd, F_GETFD);
+  if (flags == -1)
+    return false;
+
+  flags |= FD_CLOEXEC;
+  if (fcntl(fd, F_SETFD, flags) == -1)
+    return false;
+
+  return true;
+}
+#endif
+
 }  // namespace
 //------------------------------------------------------------------------------
 
 Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
                                   Listener* listener)
     : mode_(mode),
       is_blocked_on_write_(false),
       message_send_bytes_written_(0),
@@ -293,16 +307,26 @@ bool Channel::ChannelImpl::CreatePipe(co
       }
       // Set both ends to be non-blocking.
       if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
           fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
         HANDLE_EINTR(close(pipe_fds[0]));
         HANDLE_EINTR(close(pipe_fds[1]));
         return false;
       }
+
+#if defined(CHROMIUM_MOZILLA_BUILD)
+      if (!SetCloseOnExec(pipe_fds[0]) ||
+          !SetCloseOnExec(pipe_fds[1])) {
+        HANDLE_EINTR(close(pipe_fds[0]));
+        HANDLE_EINTR(close(pipe_fds[1]));
+        return false;
+      }
+#endif
+
       pipe_ = pipe_fds[0];
       client_pipe_ = pipe_fds[1];
 
       Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
     } else {
       pipe_ = ChannelNameToClientFD(pipe_name_);
       DCHECK(pipe_ > 0);
       waiting_connect_ = false;
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -46,16 +46,58 @@
 #include "nsTArray.h"
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4800 )
 #endif
 
 namespace IPC {
 
+template<>
+struct ParamTraits<PRInt8>
+{
+  typedef PRInt8 paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    aMsg->WriteBytes(&aParam, sizeof(aParam));
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    const char* outp;
+    if (!aMsg->ReadBytes(aIter, &outp, sizeof(*aResult)))
+      return false;
+
+    *aResult = *reinterpret_cast<const paramType*>(outp);
+    return true;
+  }
+};
+
+template<>
+struct ParamTraits<PRUint8>
+{
+  typedef PRUint8 paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    aMsg->WriteBytes(&aParam, sizeof(aParam));
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    const char* outp;
+    if (!aMsg->ReadBytes(aIter, &outp, sizeof(*aResult)))
+      return false;
+
+    *aResult = *reinterpret_cast<const paramType*>(outp);
+    return true;
+  }
+};
+
 template <>
 struct ParamTraits<nsACString>
 {
   typedef nsACString paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     bool isVoid = aParam.IsVoid();
--- a/ipc/ipdl/ipdl/builtin.py
+++ b/ipc/ipdl/ipdl/builtin.py
@@ -57,17 +57,17 @@ Types = (
     'uintptr_t',
 
     # stddef types
     'size_t',
     'ssize_t',
 
     # NSPR types
     'PRBool',
-    'PRPackedBool'
+    'PRPackedBool',
     'PRInt8',
     'PRUint8',
     'PRInt16',
     'PRUint16',
     'PRInt32',
     'PRUint32',
     'PRInt64',
     'PRUint64',
--- a/ipc/ipdl/test/cxx/PTestSanity.ipdl
+++ b/ipc/ipdl/test/cxx/PTestSanity.ipdl
@@ -1,21 +1,21 @@
 
 namespace mozilla {
 namespace _ipdltest {
 
 
 protocol PTestSanity {
 
 child:
-    Ping(int zero, float zeroPtFive);
+    Ping(int zero, float zeroPtFive, PRInt8 dummy);
     __delete__();
 
 parent:
-    Pong(int one, float zeroPtTwoFive);
+    Pong(int one, float zeroPtTwoFive, PRUint8 dummy);
 
 
 state PING:
     send Ping goto PONG;
 
 state PONG:
     recv Pong goto DEAD;
 
--- a/ipc/ipdl/test/cxx/TestSanity.cpp
+++ b/ipc/ipdl/test/cxx/TestSanity.cpp
@@ -16,23 +16,24 @@ TestSanityParent::TestSanityParent()
 TestSanityParent::~TestSanityParent()
 {
     MOZ_COUNT_DTOR(TestSanityParent);
 }
 
 void
 TestSanityParent::Main()
 {
-    if (!SendPing(0, 0.5f))
+    if (!SendPing(0, 0.5f, 0))
         fail("sending Ping");
 }
 
 
 bool
-TestSanityParent::RecvPong(const int& one, const float& zeroPtTwoFive)
+TestSanityParent::RecvPong(const int& one, const float& zeroPtTwoFive,
+                           const PRUint8&/*unused*/)
 {
     if (1 != one)
         fail("invalid argument `%d', should have been `1'", one);
 
     if (0.25f != zeroPtTwoFive)
         fail("invalid argument `%g', should have been `0.25'", zeroPtTwoFive);
 
     Close();
@@ -50,24 +51,25 @@ TestSanityChild::TestSanityChild()
 }
 
 TestSanityChild::~TestSanityChild()
 {
     MOZ_COUNT_DTOR(TestSanityChild);
 }
 
 bool
-TestSanityChild::RecvPing(const int& zero, const float& zeroPtFive)
+TestSanityChild::RecvPing(const int& zero, const float& zeroPtFive,
+                          const PRInt8&/*unused*/)
 {
     if (0 != zero)
         fail("invalid argument `%d', should have been `0'", zero);
 
     if (0.5f != zeroPtFive)
         fail("invalid argument `%g', should have been `0.5'", zeroPtFive);
 
-    if (!SendPong(1, 0.25f))
+    if (!SendPong(1, 0.25f, 0))
         fail("sending Pong");
     return true;
 }
 
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/TestSanity.h
+++ b/ipc/ipdl/test/cxx/TestSanity.h
@@ -16,17 +16,18 @@ class TestSanityParent :
 public:
     TestSanityParent();
     virtual ~TestSanityParent();
 
     void Main();
 
 protected:    
     NS_OVERRIDE
-    virtual bool RecvPong(const int& one, const float& zeroPtTwoFive);
+    virtual bool RecvPong(const int& one, const float& zeroPtTwoFive,
+                          const PRUint8& dummy);
 
     NS_OVERRIDE
     virtual void ActorDestroy(ActorDestroyReason why)
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");  
         passed("ok");
         QuitParent();
@@ -38,17 +39,18 @@ class TestSanityChild :
     public PTestSanityChild
 {
 public:
     TestSanityChild();
     virtual ~TestSanityChild();
 
 protected:
     NS_OVERRIDE
-    virtual bool RecvPing(const int& zero, const float& zeroPtFive);
+    virtual bool RecvPing(const int& zero, const float& zeroPtFive,
+                          const PRInt8& dummy);
 
     NS_OVERRIDE
     virtual void ActorDestroy(ActorDestroyReason why)
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");
         QuitChild();
     }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -797,17 +797,17 @@ class TypedArrayTemplate
 
   protected:
     bool
     copyFrom(JSContext *cx, JSObject *ar, jsuint len)
     {
         NativeType *dest = static_cast<NativeType*>(data);
 
         if (ar->isDenseArray()) {
-            JS_ASSERT(ar->fslots[JSSLOT_ARRAY_LENGTH] == len);
+            JS_ASSERT(ar->fslots[JSSLOT_ARRAY_LENGTH] == (jsval)len);
 
             jsval *src = ar->dslots;
 
             for (uintN i = 0; i < len; ++i) {
                 jsval v = *src++;
                 if (JSVAL_IS_INT(v)) {
                     *dest++ = NativeType(JSVAL_TO_INT(v));
                 } else if (JSVAL_IS_DOUBLE(v)) {
@@ -1210,16 +1210,17 @@ TypedArrayConstruct(JSContext *cx, jsint
       case TypedArray::TYPE_UINT32:
         return Uint32Array::class_constructor(cx, cx->globalObject, argc, argv, rv);
 
       case TypedArray::TYPE_FLOAT32:
         return Float32Array::class_constructor(cx, cx->globalObject, argc, argv, rv);
 
       default:
         JS_NOT_REACHED("shouldn't have gotten here");
+        return false;
     }
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements)
 {
     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
 
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -1175,17 +1175,27 @@ UnwrapNW(JSContext *cx, uintN argc, jsva
     return ThrowException(NS_ERROR_INVALID_ARG, cx);
   }
 
   if (!IsNativeWrapper(JSVAL_TO_OBJECT(v))) {
     JS_SET_RVAL(cx, vp, v);
     return JS_TRUE;
   }
 
-  return GetwrappedJSObject(cx, JSVAL_TO_OBJECT(v), vp);
+  XPCWrappedNative *wn;
+  if (!XPCNativeWrapper::GetWrappedNative(cx, JSVAL_TO_OBJECT(v), &wn)) {
+    return JS_FALSE;
+  }
+
+  if (!wn) {
+    JS_SET_RVAL(cx, vp, JSVAL_NULL);
+    return JS_TRUE;
+  }
+
+  return GetwrappedJSObject(cx, wn->GetFlatJSObject(), vp);
 }
 
 static JSFunctionSpec static_functions[] = {
   JS_FN("unwrap", UnwrapNW, 1, 0),
   JS_FS_END
 };
 
 // static
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1069,17 +1069,20 @@ InitWebGLTypes(JSContext *aJSContext, JS
         "WebGLUnsignedByteArray",
         "WebGLShortArray",
         "WebGLUnsignedShortArray",
         "WebGLIntArray",
         "WebGLUnsignedIntArray",
         "WebGLFloatArray"
     };
 
-    for(int i = 0; i < NS_ARRAY_LENGTH(webglTypes); ++i) {
+    for(size_t i = 0;
+        i < NS_ARRAY_LENGTH(webglTypes);
+        ++i)
+    {
         if(!JS_GetProperty(aJSContext, aGlobalJSObj, js::TypedArray::slowClasses[webglTypes[i]].name, &v) ||
            !JS_DefineProperty(aJSContext, aGlobalJSObj, webglNames[i], v,
                               NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
             return PR_FALSE;
     }
 
     return PR_TRUE;
 }
--- a/js/src/xpconnect/tests/chrome/test_bug533596.xul
+++ b/js/src/xpconnect/tests/chrome/test_bug533596.xul
@@ -1,16 +1,16 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
                  type="text/css"?>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=500931
+https://bugzilla.mozilla.org/show_bug.cgi?id=533596
 -->
-<window title="Mozilla Bug 500931"
+<window title="Mozilla Bug 533596"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript"
           src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
@@ -29,16 +29,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     try { XPCNativeWrapper.unwrap(null); } catch (e) {}
 
     var o = {};
     is(o, XPCNativeWrapper.unwrap(o), "unwrap on a random object returns it");
 
     var win = $('ifr').contentWindow;
     var utils = window.getInterface(Components.interfaces.nsIDOMWindowUtils);
     is(utils.getClassName(win), "XPCNativeWrapper", "win is an XPCNW");
+    ok("x" in XPCNativeWrapper.unwrap(win), "actually unwrapped");
     is(utils.getClassName(XPCNativeWrapper.unwrap(win)), "XPCSafeJSObjectWrapper",
        "unwrap on an NW returns the same object");
     is(utils.getClassName(XPCNativeWrapper.unwrap(new XPCNativeWrapper(win))), "XPCSafeJSObjectWrapper",
        "unwrap on an explicit NW works too");
 
     ok(utils.getClassName(window) !== "XPCNativeWrapper", "window is not a native wrapper");
     ok(utils.getClassName(XPCNativeWrapper.unwrap(new XPCNativeWrapper(window))) !== "XPCSafeJSObjectWrapper",
        "unwrapping a chrome object returns the object itself");
--- a/js/src/xpconnect/tests/mochitest/bug500931_helper.html
+++ b/js/src/xpconnect/tests/mochitest/bug500931_helper.html
@@ -1,7 +1,8 @@
 <html>
     <head>
         <title>Inner frame for bug 500931 mochitest</title>
+        <script>x = 42;</script>
     </head>
     <body>
     </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/541869-1.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml"  style="right: 10000px; top: 11121164%; position: fixed;"><div>X</div>
+<script>
+window.addEventListener("load", function() { document.documentElement.style.letterSpacing = '21em'; }, false);
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/541869-2.html
@@ -0,0 +1,5 @@
+<html style="padding: 9007199254740991%;">
+<body onload="document.getElementById('f').style.border = 'none';" style="display: inline">
+<iframe id="f"></iframe>
+</body>
+</html>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -270,8 +270,10 @@ load 501878-1.html
 load 503936-1.html
 load 526378-1.xul
 load 535721-1.xhtml
 load 535911-1.xhtml
 load 536623-1.xhtml
 load 537059-1.xhtml
 load 537141-1.xhtml
 load 537562-1.xhtml
+load 541869-1.xhtml
+load 541869-2.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7497,17 +7497,20 @@ nsCSSFrameConstructor::ProcessRestyledFr
 
   EndUpdate();
 
   if (didInvalidate && !didReflow) {
     // RepaintFrame changes can indicate changes in opacity etc which
     // can require plugin clipping to change. If we requested a reflow,
     // we don't need to do this since the reflow will do it for us.
     nsIFrame* rootFrame = mPresShell->FrameManager()->GetRootFrame();
-    presContext->RootPresContext()->UpdatePluginGeometry(rootFrame);
+    nsRootPresContext* rootPC = presContext->GetRootPresContext();
+    if (rootPC) {
+      rootPC->UpdatePluginGeometry(rootFrame);
+    }
   }
 
   // cleanup references and verify the style tree.  Note that the latter needs
   // to happen once we've processed the whole list, since until then the tree
   // is not in fact in a consistent state.
   index = count;
   while (0 <= --index) {
     const nsStyleChangeData* changeData;
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -986,20 +986,23 @@ void nsCaret::GetViewForRendering(nsIFra
     // window-relative coordinates. Done for us by the view.
     withinViewOffset += theView->GetOffsetTo(nsnull);
     viewOffset = withinViewOffset;
 
     // Get the relative view for top level window coordinates
     if (outRelativeView && coordType == eTopLevelWindowCoordinates) {
       nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
       if (presShell) {
-        nsIViewManager* vm =
-          presShell->GetPresContext()->RootPresContext()->PresShell()->GetViewManager();
-        if (vm) {
-          vm->GetRootView(*outRelativeView);
+        nsRootPresContext* rootPC =
+          presShell->GetPresContext()->GetRootPresContext();
+        if (rootPC) {
+          nsIViewManager* vm = rootPC->PresShell()->GetViewManager();
+          if (vm) {
+            vm->GetRootView(*outRelativeView);
+          }
         }
       }
     }
   }
 
   *outRenderingView = returnView;
 }
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2186,17 +2186,18 @@ nsLayoutUtils::ComputeWidthDependentValu
 {
   NS_PRECONDITION(aContainingBlockWidth != NS_UNCONSTRAINEDSIZE,
                   "unconstrained widths no longer supported");
 
   if (eStyleUnit_Coord == aCoord.GetUnit()) {
     return aCoord.GetCoordValue();
   }
   if (eStyleUnit_Percent == aCoord.GetUnit()) {
-    return NSToCoordFloor(aContainingBlockWidth * aCoord.GetPercentValue());
+    return NSToCoordFloorClamped(aContainingBlockWidth *
+                                 aCoord.GetPercentValue());
   }
   NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
                aCoord.GetUnit() == eStyleUnit_Auto,
                "unexpected width value");
   return 0;
 }
 
 /* static */ nscoord
@@ -2219,17 +2220,18 @@ nsLayoutUtils::ComputeWidthValue(
 
   nscoord result;
   if (eStyleUnit_Coord == aCoord.GetUnit()) {
     result = aCoord.GetCoordValue();
     NS_ASSERTION(result >= 0, "width less than zero");
     result -= aContentEdgeToBoxSizing;
   } else if (eStyleUnit_Percent == aCoord.GetUnit()) {
     NS_ASSERTION(aCoord.GetPercentValue() >= 0.0f, "width less than zero");
-    result = NSToCoordFloor(aContainingBlockWidth * aCoord.GetPercentValue()) -
+    result = NSToCoordFloorClamped(aContainingBlockWidth *
+                                   aCoord.GetPercentValue()) -
              aContentEdgeToBoxSizing;
   } else if (eStyleUnit_Enumerated == aCoord.GetUnit()) {
     PRInt32 val = aCoord.GetIntValue();
     switch (val) {
       case NS_STYLE_WIDTH_MAX_CONTENT:
         result = aFrame->GetPrefWidth(aRenderingContext);
         NS_ASSERTION(result >= 0, "width less than zero");
         break;
@@ -2276,17 +2278,18 @@ nsLayoutUtils::ComputeHeightDependentVal
     // be inside the percentage case.  However, it would be much more
     // likely to catch problems if it were at the start of the function.
     // XXXldb Many callers pass a non-'auto' containing block height when
     // according to CSS2.1 they should be passing 'auto'.
     NS_PRECONDITION(NS_AUTOHEIGHT != aContainingBlockHeight,
                     "unexpected 'containing block height'");
 
     if (NS_AUTOHEIGHT != aContainingBlockHeight) {
-      return NSToCoordFloor(aContainingBlockHeight * aCoord.GetPercentValue());
+      return NSToCoordFloorClamped(aContainingBlockHeight *
+                                   aCoord.GetPercentValue());
     }
   }
   NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
                aCoord.GetUnit() == eStyleUnit_Auto,
                "unexpected height value");
   return 0;
 }
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1045,31 +1045,31 @@ nsPresContext::Observe(nsISupports* aSub
   }
 
   NS_WARNING("unrecognized topic in nsPresContext::Observe");
   return NS_ERROR_FAILURE;
 }
 
 // We may want to replace this with something faster, maybe caching the root prescontext
 nsRootPresContext*
-nsPresContext::RootPresContext()
+nsPresContext::GetRootPresContext()
 {
   nsPresContext* pc = this;
   for (;;) {
     if (pc->mShell) {
       nsIFrame* rootFrame = pc->mShell->FrameManager()->GetRootFrame();
       if (rootFrame) {
         nsIFrame* f = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
         if (f) {
           pc = f->PresContext();
           continue;
         }
       }
     }
-    return static_cast<nsRootPresContext*>(pc);
+    return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nsnull;
   }
 }
 
 void
 nsPresContext::CompatibilityModeChanged()
 {
   if (!mShell)
     return;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -208,19 +208,23 @@ public:
   nsIPresShell* PresShell() const
   {
     NS_ASSERTION(mShell, "Null pres shell");
     return mShell;
   }
 
   nsIPresShell* GetPresShell() const { return mShell; }
 
-  // Find the prescontext for the root of the view manager hierarchy that contains
-  // this prescontext.
-  nsRootPresContext* RootPresContext();
+  /**
+   * Return the presentation context for the root of the view manager
+   * hierarchy that contains this presentation context, or nsnull if it can't
+   * be found (e.g. it's detached).
+   */
+  nsRootPresContext* GetRootPresContext();
+  virtual PRBool IsRoot() { return PR_FALSE; }
 
   nsIDocument* Document() const
   {
       NS_ASSERTION(!mShell || !mShell->GetDocument() ||
                    mShell->GetDocument() == mDocument,
                    "nsPresContext doesn't have the same document as nsPresShell!");
       return mDocument;
   }
@@ -1170,16 +1174,18 @@ public:
 
   /**
    * When all geometry updates have been applied, call this function
    * in case the nsObjectFrames have work to do after the widgets
    * have been updated.
    */
   void DidApplyPluginGeometryUpdates();
 
+  virtual PRBool IsRoot() { return PR_TRUE; }
+
 private:
   nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
 };
 
 #ifdef DEBUG
 
 struct nsAutoLayoutPhase {
   nsAutoLayoutPhase(nsPresContext* aPresContext, nsLayoutPhase aPhase)
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4557,17 +4557,20 @@ PresShell::UnsuppressAndInvalidate()
     // let's assume that outline on a root frame is not supported
     nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
     rootFrame->Invalidate(rect);
 
     if (mCaretEnabled && mCaret) {
       mCaret->CheckCaretDrawingState();
     }
 
-    mPresContext->RootPresContext()->UpdatePluginGeometry(rootFrame);
+    nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
+    if (rootPC) {
+      rootPC->UpdatePluginGeometry(rootFrame);
+    }
   }
 
   // now that painting is unsuppressed, focus may be set on the document
   nsPIDOMWindow *win = mDocument->GetWindow();
   if (win)
     win->SetReadyForFocus();
 
   if (!mHaveShutDown && mViewManager)
@@ -6113,18 +6116,18 @@ PresShell::HandleEvent(nsIView         *
   }
 
   if (dispatchUsingCoordinates) {
     NS_WARN_IF_FALSE(frame, "Nothing to handle this event!");
     if (!frame)
       return NS_OK;
 
     nsPresContext* framePresContext = frame->PresContext();
-    nsPresContext* rootPresContext = framePresContext->RootPresContext();
-    NS_ASSERTION(rootPresContext == mPresContext->RootPresContext(),
+    nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
+    NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
                  "How did we end up outside the connected prescontext/viewmanager hierarchy?"); 
     // If we aren't starting our event dispatch from the root frame of the root prescontext,
     // then someone must be capturing the mouse. In that case we don't want to search the popup
     // list.
     if (framePresContext == rootPresContext &&
         frame == FrameManager()->GetRootFrame()) {
 
 #ifdef MOZ_XUL
@@ -6633,18 +6636,23 @@ PresShell::AdjustContextMenuKeyEvent(nsM
   // If we're here because of the key-equiv for showing context menus, we
   // have to twiddle with the NS event to make sure the context menu comes
   // up in the upper left of the relevant content area before we create
   // the DOM event. Since we never call InitMouseEvent() on the event, 
   // the client X/Y will be 0,0. We can make use of that if the widget is null.
   // Use the root view manager's widget since it's most likely to have one,
   // and the coordinates returned by GetCurrentItemAndPositionForElement
   // are relative to the root of the root view manager.
-  mPresContext->RootPresContext()->PresShell()->GetViewManager()->
-    GetRootWidget(getter_AddRefs(aEvent->widget));
+  nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
+  if (rootPC) {
+    rootPC->PresShell()->GetViewManager()->
+      GetRootWidget(getter_AddRefs(aEvent->widget));
+  } else {
+    aEvent->widget = nsnull;
+  }
   aEvent->refPoint.x = 0;
   aEvent->refPoint.y = 0;
 
   // see if we should use the caret position for the popup
   nsIntPoint caretPoint;
   // Beware! This may flush notifications via synchronous
   // ScrollSelectionIntoView.
   if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) {
@@ -7355,17 +7363,20 @@ PresShell::DoReflow(nsIFrame* target, PR
 
     // Any FlushPendingNotifications with interruptible reflows
     // should be suppressed now. We don't want to do extra reflow work
     // before our reflow event happens.
     mSuppressInterruptibleReflows = PR_TRUE;
     PostReflowEvent();
   }
 
-  mPresContext->RootPresContext()->UpdatePluginGeometry(target);
+  nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
+  if (rootPC) {
+    rootPC->UpdatePluginGeometry(target);
+  }
 
   return !interrupted;
 }
 
 #ifdef DEBUG
 void
 PresShell::DoVerifyReflow()
 {
--- a/layout/base/tests/scrolling_helper.html
+++ b/layout/base/tests/scrolling_helper.html
@@ -123,16 +123,42 @@ iframe {
 
 <div id="testTableNoBackground" class="testcase">
   <table style="position:fixed; width:200px; height:200px;">
     <tr><td></td></tr>
   </table>
   <div style="height:300px; background:-moz-linear-gradient(top, red, black);"></div>
 </div>
 
+<iframe class="testcase" id="testNoBlitInSVG" height="200" width="200"
+        src="data:text/html,<body class='testcase' style='margin:0; height:300px; background:-moz-linear-gradient(top, red, black);'>">
+</iframe>
+<script>
+// We're not in XHTML, so we have to make our SVG elements with script.
+var SVG_NS = "http://www.w3.org/2000/svg";
+var svg = document.createElementNS(SVG_NS, "svg");
+svg.setAttribute("style", "width: 300px; height: 300px");
+var g = document.createElementNS(SVG_NS, "g");
+g.setAttribute("transform", "translate(100,0) rotate(30)");
+var fo = document.createElementNS(SVG_NS, "foreignObject");
+fo.setAttribute("x", "0");
+fo.setAttribute("y", "0");
+fo.setAttribute("width", "200");
+fo.setAttribute("height", "200");
+var iframe = document.getElementById("testNoBlitInSVG");
+iframe.parentNode.replaceChild(svg, iframe);
+fo.appendChild(iframe);
+g.appendChild(fo);
+svg.appendChild(g);
+</script>
+
+<iframe class="testcase" id="testNoBlitInTransform" height="200" width="200" style="-moz-transform-origin: 0 0; -moz-transform: translateX(100px) rotate(30deg)"
+        src="data:text/html,<body class='testcase' style='margin:0; height:300px; background:-moz-linear-gradient(top, red, black);'>">
+</iframe>
+
 <script>
 var testcases = document.querySelectorAll("div.testcase");
 var tests = [];
 var iframes = document.querySelectorAll("iframe.testcase");
 
 var currentTest = -1;
 
 function ok(a, msg) {
@@ -304,21 +330,51 @@ function testHiddenTable(blitRegion, pai
 
 function testTableNoBackground(blitRegion, paintRegion) {
   ok(blitRegion.equalsRegion(new Region([[0,0,200,180]])),
      "Should blit everything that was already visible: " + blitRegion.toString());
   ok(paintRegion.equalsRegion(new Region([[0,180,200,200]])),
      "Should repaint area that was scrolled into view: " + paintRegion.toString());
 }
 
+function testNoBlitInSVG(blitRegion, paintRegion) {
+  ok(blitRegion.isEmpty(), "should not blit when in transformed SVG");
+  // We're looking at regions in the coordinates of the inner iframe.
+  // (Not the most useful test, but it does test the particular bug that we
+  // should be repainting rather than blitting.)
+  ok(paintRegion.equalsRegion(new Region([[0,0,200,200]])),
+     "repaint rect must contain area completely inside scrolled region");
+}
+
+function testNoBlitInTransform(blitRegion, paintRegion) {
+  ok(blitRegion.isEmpty(), "should not blit when in CSS Transform");
+  // We're looking at regions in the coordinates of the inner iframe.
+  // (Not the most useful test, but it does test the particular bug that we
+  // should be repainting rather than blitting.)
+  ok(paintRegion.equalsRegion(new Region([[0,0,200,200]])),
+     "repaint rect must contain area completely inside scrolled region");
+}
+
 function clientRectToRect(cr)
 {
   return [cr.left, cr.top, cr.right, cr.bottom];
 }
 
+// Return the ancestor-or-self of |container| that is a child of body.
+function bodyChild(container)
+{
+  var prev;
+  var next = container;
+  do {
+    prev = next;
+    next = prev.parentNode;
+  } while (next != document.body);
+  return prev;
+}
+
 function regionForReason(requests, reason)
 {
   var rects = [];
   for (var i = 0; i < requests.length; ++i) {
     var r = requests[i];
     if (r.reason == reason) {
       rects.push(clientRectToRect(r.clientRect));
     }
@@ -342,30 +398,30 @@ function afterPaint(event) {
     return;
 
   var testFunc = window[tests[currentTest].container.id];
   if (!testFunc) {
     ok(false, "Cannot find test function for " + tests[currentTest].container.id);
   } else {
     testFunc(blitRegion, paintRegion);
   }
-  tests[currentTest].container.style.display = 'none';
+  bodyChild(tests[currentTest].container).style.display = 'none';
 
   nextTest();
 }
 
 function nextTest() {
   ++currentTest;
   if (currentTest >= tests.length) {
     finish();
     return;
   }
 
   var t = tests[currentTest];
-  t.container.style.display = "";
+  bodyChild(t.container).style.display = "";
   setTimeout(function() {
     if (t.scrollable.getAttribute("class").match(/horizontal/)) {
       t.scrollable.scrollLeft = 20;
     } else {
       t.scrollable.scrollTop = 20;
     }
   }, 0);
 }
@@ -375,17 +431,17 @@ function runTests() {
     tests.push({ scrollable:testcases[i], container:testcases[i] });
   }
   for (var i = 0; i < iframes.length; ++i) {
     tests.push({ scrollable:iframes[i].contentDocument.body, container:iframes[i] });
   }
 
   for (var i = 0; i < tests.length; ++i) {
     var t = tests[i];
-    t.container.style.display = "none";
+    bodyChild(t.container).style.display = "none";
     // Make sure we don't remember a scroll position from history
     t.scrollable.scrollTop = 0;
     t.scrollable.scrollLeft = 0;
   }
 
   window.addEventListener("MozAfterPaint", afterPaint, false);
   for (var i = 0; i < iframes.length; ++i) {
     iframes[i].contentWindow.addEventListener("MozAfterPaint", afterPaint, false);
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/541277-1.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<span>&#xFBE4;</span><span>&#xFB4B;</span><span>&#xFBE6;</span>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/541277-2.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+&#x202E;X&#x200D; &#x5D60;
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -280,8 +280,10 @@ load 505912-1.html
 load 509749-1.html
 load 511482.html
 load 513394-1.html
 load 514800-1.html
 load 517968.html
 load 520340.html
 load 533379-1.html
 load 533379-2.html
+load 541277-1.html
+load 541277-2.html
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1593,33 +1593,37 @@ SortBlitRectsForCopy(nsIntPoint aPixDelt
     aRects->AppendElement(FlipRect(rects[i], aPixDelta));
     rects.RemoveElementAt(i);
   }
 }
 
 static PRBool
 CanScrollWithBlitting(nsIFrame* aFrame)
 {
-  for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
+  for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
     if (f->GetStyleDisplay()->HasTransform()) {
       return PR_FALSE;
     }
 #ifdef MOZ_SVG
     if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) ||
         f->IsFrameOfType(nsIFrame::eSVG)) {
       return PR_FALSE;
     }
 #endif
   }
   return PR_TRUE;
 }
 
 void nsGfxScrollFrameInner::ScrollVisual(nsIntPoint aPixDelta)
 {
-  nsRootPresContext* rootPresContext = mOuter->PresContext()->RootPresContext();
+  nsRootPresContext* rootPresContext =
+    mOuter->PresContext()->GetRootPresContext();
+  if (!rootPresContext) {
+    return;
+  }
 
   nsPoint offsetToView;
   nsPoint offsetToWidget;
   nsIWidget* nearestWidget =
     mOuter->GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
   nsPoint nearestWidgetOffset = offsetToView + offsetToWidget;
 
   nsTArray<nsIWidget::Configuration> configurations;
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -610,18 +610,16 @@ nsObjectFrame::Init(nsIContent*      aCo
 
 void
 nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   NS_ASSERTION(!mPreventInstantiation ||
                (mContent && mContent->GetCurrentDoc()->GetDisplayDocument()),
                "about to crash due to bug 136927");
 
-  PresContext()->RootPresContext()->UnregisterPluginForGeometryUpdates(this);
-
   // we need to finish with the plugin before native window is destroyed
   // doing this in the destructor is too late.
   StopPluginInternal(PR_TRUE);
 
   // StopPluginInternal might have disowned the widget; if it has,
   // mWidget will be null.
   if (mWidget) {
     mInnerView->DetachWidgetEventHandler(mWidget);
@@ -690,29 +688,31 @@ nsObjectFrame::CreateWidget(nscoord aWid
   nsPoint origin;
   nsRect r(0, 0, mRect.width, mRect.height);
 
   GetOffsetFromView(origin, &parentWithView);
   viewMan->ResizeView(view, r);
   viewMan->MoveViewTo(view, origin.x, origin.y);
 
   if (!aViewOnly && !mWidget && usewidgets) {
+    nsRootPresContext* rpc = PresContext()->GetRootPresContext();
+    if (!rpc)
+      return NS_ERROR_FAILURE;
     mInnerView = viewMan->CreateView(GetContentRect() - GetPosition(), view);
     if (!mInnerView) {
       NS_ERROR("Could not create inner view");
       return NS_ERROR_OUT_OF_MEMORY;
     }
     viewMan->InsertChild(view, mInnerView, nsnull, PR_TRUE);
 
     nsresult rv;
     mWidget = do_CreateInstance(kWidgetCID, &rv);
     if (NS_FAILED(rv))
       return rv;
 
-    nsRootPresContext* rpc = PresContext()->RootPresContext();
     // XXX this breaks plugins in popups ... do we care?
     nsIWidget* parentWidget =
       rpc->PresShell()->FrameManager()->GetRootFrame()->GetWindow();
 
     nsWidgetInitData initData;
     initData.mWindowType = eWindowType_plugin;
     initData.mUnicode = PR_FALSE;
     initData.clipChildren = PR_TRUE;
@@ -1186,26 +1186,28 @@ nsDisplayPlugin::GetWidgetConfiguration(
 void
 nsObjectFrame::ComputeWidgetGeometry(const nsRegion& aRegion,
                                      const nsPoint& aPluginOrigin,
                                      nsTArray<nsIWidget::Configuration>* aConfigurations)
 {
   if (!mWidget)
     return;
 
-  nsIWidget::Configuration* configuration =
-    aConfigurations->AppendElement();
+  nsPresContext* presContext = PresContext();
+  nsRootPresContext* rootPC = presContext->GetRootPresContext();
+  if (!rootPC)
+    return;
+
+  nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
   if (!configuration)
     return;
   configuration->mChild = mWidget;
 
-  nsPresContext* presContext = PresContext();
   PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
-  nsIFrame* rootFrame =
-    presContext->RootPresContext()->PresShell()->FrameManager()->GetRootFrame();
+  nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
   nsRect bounds = GetContentRect() + GetParent()->GetOffsetTo(rootFrame);
   configuration->mBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
 
   nsRegionRectIterator iter(aRegion);
   nsIntPoint pluginOrigin = aPluginOrigin.ToNearestPixels(appUnitsPerDevPixel);
   for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
     // Snap *r to pixels while it's relative to the painted widget, to
     // improve consistency with rectangle and image drawing
@@ -2249,16 +2251,22 @@ nsObjectFrame::StopPlugin()
 
 void
 nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
 {
   if (!mInstanceOwner) {
     return;
   }
 
+  if (mWidget) {
+    nsRootPresContext* rootPC = PresContext()->GetRootPresContext();
+    NS_ASSERTION(rootPC, "unable to unregister the plugin frame");
+    rootPC->UnregisterPluginForGeometryUpdates(this);
+  }
+
   // Transfer the reference to the instance owner onto the stack so
   // that if we do end up re-entering this code, or if we unwind back
   // here witha deleted frame (this), we can still continue to stop
   // the plugin. Note that due to that, the ordering of the code in
   // this function is extremely important.
 
   nsRefPtr<nsPluginInstanceOwner> owner;
   owner.swap(mInstanceOwner);
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -4640,18 +4640,20 @@ nsTypedSelection::DoAutoScroll(nsIFrame 
   NS_PRECONDITION(aFrame, "Need a frame");
 
   nsresult result = NS_OK;
 
   if (mAutoScrollTimer)
     result = mAutoScrollTimer->Stop();
 
   nsPresContext* presContext = aFrame->PresContext();
-  nsIFrame* rootmostFrame =
-    presContext->RootPresContext()->PresShell()->FrameManager()->GetRootFrame();
+  nsRootPresContext* rootPC = presContext->GetRootPresContext();
+  if (!rootPC)
+    return NS_OK;
+  nsIFrame* rootmostFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
   nsPoint globalPoint = aPoint + aFrame->GetOffsetTo(rootmostFrame);
 
   PRBool didScroll = presContext->PresShell()->
     ScrollFrameRectIntoView(aFrame, nsRect(aPoint, nsSize(1,1)),
                             NS_PRESSHELL_SCROLL_ANYWHERE,
                             NS_PRESSHELL_SCROLL_ANYWHERE, 0);
 
   //
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -2097,17 +2097,17 @@ nsTextFrame::GetTrimmedOffsets(const nsT
  * are surrogates.
  */
 static PRBool IsJustifiableCharacter(const nsTextFragment* aFrag, PRInt32 aPos,
                                      PRBool aLangIsCJ)
 {
   PRUnichar ch = aFrag->CharAt(aPos);
   if (ch == '\n' || ch == '\t')
     return PR_TRUE;
-  if (ch == ' ') {
+  if (ch == ' ' || ch == CH_NBSP) {
     // Don't justify spaces that are combined with diacriticals
     if (!aFrag->Is2b())
       return PR_TRUE;
     return !nsTextFrameUtils::IsSpaceCombiningSequenceTail(
         aFrag->Get2b() + aPos + 1, aFrag->GetLength() - (aPos + 1));
   }
   if (ch < 0x2150u)
     return PR_FALSE;
--- a/layout/generic/test/plugin_clipping_helper.xhtml
+++ b/layout/generic/test/plugin_clipping_helper.xhtml
@@ -1,14 +1,12 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
 <html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping">
 <head>
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <style>
   embed { width:200px; height:200px; display:block; }
   iframe { border:none; }
   </style>
 </head>
 <body>
 
 <!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
@@ -45,14 +43,17 @@
 <![CDATA[
 
 function runTests() {
   checkClipRegion("p1", [[0, 0, 200, 200]]);
   checkClipRegion("p2", [[100, 100, 200, 200]]);
   checkClipRegion("p3", [[100, 100, 200, 200]]);
   checkClipRegion("p4", [[100, 100, 200, 200]]);
   checkClipRegionForFrame("f1", "p5", [[100, 100, 200, 200]]);
+
+  window.opener.SimpleTest.finish();
+  window.close();
 }
 ]]>
 </script>
 
 </body>
 </html>
--- a/layout/generic/test/plugin_clipping_helper2.xhtml
+++ b/layout/generic/test/plugin_clipping_helper2.xhtml
@@ -28,49 +28,75 @@
   <div id="sbox"
        style="margin-top:350px; margin-left:50px; margin-bottom:1000px; width:100px; height:100px; background:blue;"></div>
 </div>
 
 <script src="plugin_clipping_lib.js"></script>
 <script class="testbody" type="application/javascript">
 <![CDATA[
 var scroll = document.getElementById("scroll");
+var zbox = document.getElementById("zbox");
+var sbox = document.getElementById("sbox");
+var p1 = document.getElementById("p1");
+var d2 = document.getElementById("d2");
 
 function runTests() {
-  var zbox = document.getElementById("zbox");
-  var sbox = document.getElementById("sbox");
-  var p1 = document.getElementById("p1");
-  var d2 = document.getElementById("d2");
 
   checkClipRegion("p1", [[0, 0, 200, 100]]);
   checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 150], [150, 50, 200, 150], [0, 150, 200, 200]]);
 
   scroll.scrollTop = 150;
   checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 200], [150, 50, 200, 200]]);
 
   zbox.style.zIndex = -1;
+
   flush();
+  // A non-zero timeout is needed on X11 (unless an XSync could be performed)
+  // to delay an OOP plugin's X requests enough so that the X server processes
+  // them after the parent processes requests (for the changes above).
+  setTimeout(part2, 1000);
+}
+
+function part2() {
   checkClipRegion("p2", [[0, 0, 200, 100], [0, 100, 50, 200], [150, 100, 200, 200]]);
 
   sbox.style.background = "";
+
   flush();
+  setTimeout(part3, 1000);
+}
+
+function part3() {
   checkClipRegion("p2", [[0, 0, 200, 200]]);
   
   p1.style.zIndex = 1;
+
   flush();
+  setTimeout(part4, 1000);
+}
+
+function part4() {
   checkClipRegion("p1", [[0, 0, 200, 200]]);
   checkClipRegion("p2", [[0, 100, 200, 200]]);
 
   // Test subpixel stuff
   p1.style.zIndex = -1;
   zbox.style.zIndex = 1;
   zbox.style.top = "50.3px;"
   d2.style.top = "100.3px";
+
   flush();
+  setTimeout(done, 1000);
+}
+
+function done() {
   checkClipRegionNoBounds("p2", [[0, 0, 200, 50], [0, 50, 50, 150], [150, 50, 200, 150], [0, 150, 200, 200]]);
+
+  window.opener.SimpleTest.finish();
+  window.close();
 }
 
 function flush() {
   // This function is for X11 to flush the Xlib request queue.  It takes
   // advantage of the current scrolling implementation, which will do this for
   // us.  Beware though, it does not wait for the X server to process the
   // events.
   ++scroll.scrollTop;
--- a/layout/generic/test/plugin_clipping_helper_table.xhtml
+++ b/layout/generic/test/plugin_clipping_helper_table.xhtml
@@ -1,14 +1,12 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
 <html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins and Tables">
 <head>
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <style>
   embed { width:300px; height:200px; display:block; }
   </style>
 </head>
 <body>
 
 <!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
 <hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
@@ -29,15 +27,18 @@
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 function runTests() {
   // p1 is partially covered by a table with an opaque background
   checkClipRegion("p1", [[0, 0, 300, 100]]);
   // p2 is partially covered by a table with an opaque background
   checkClipRegion("p2", [[0, 0, 300, 100]]);
+
+  window.opener.SimpleTest.finish();
+  window.close();
 }
 
 ]]>
 </script>
 
 </body>
 </html>
--- a/layout/generic/test/plugin_clipping_helper_transformed.xhtml
+++ b/layout/generic/test/plugin_clipping_helper_transformed.xhtml
@@ -1,14 +1,12 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
 <html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins in Transforms">
 <head>
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <style>
   embed { width:300px; height:200px; display:block; }
   </style>
 </head>
 <body>
 
 <!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
 <hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
@@ -28,15 +26,18 @@
 <script src="plugin_clipping_lib.js"></script>
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
 function runTests() {
   // p1 and p2 are both in a transformed context so they should be hidden.
   checkClipRegionNoBounds("p1", []);
   checkClipRegionNoBounds("p2", []);
+
+  window.opener.SimpleTest.finish();
+  window.close();
 }
 
 ]]>
 </script>
 
 </body>
 </html>
--- a/layout/generic/test/plugin_clipping_lib.js
+++ b/layout/generic/test/plugin_clipping_lib.js
@@ -148,19 +148,16 @@ function loaded() {
   }
 
   var bounds = h1.getBoundingClientRect();
   windowFrameX = h1.boxObject.screenX - bounds.left - window.screenX;
   windowFrameY = h1.boxObject.screenY - bounds.top - window.screenY;
 
   // Run actual test code
   runTests();
-
-  finish();
-  window.close();
 }
 
 // Need to run 'loaded' after painting is unsuppressed, or we'll set clip
 // regions to empty.  The timeout must be non-zero on X11 so that
 // gtk_container_idle_sizer runs after the GtkSocket gets the plug_window.
 window.addEventListener("load",
                         function () { setTimeout(loaded, 1000); }, false);
 })();
--- a/layout/generic/test/plugin_focus_helper.html
+++ b/layout/generic/test/plugin_focus_helper.html
@@ -61,17 +61,17 @@ function handleEvent(event) {
     return;
 
   var s = steps[step++];
   is(event.type, s.event, "Check event type");
   is(event.target.id, s.id, "Check event target");
 
   if (s.action) {
     // Do the action after this event cycle is done
-    setTimeout(s.action, 0);
+    setTimeout(s.action, 1000);
   }
 }
 
 var elems = ["input", "p1", "p2"];
 for (var i = 0; i < elems.length; ++i) {
   var e = document.getElementById(elems[i]);
   e.addEventListener("focus", handleEvent, false);
   e.addEventListener("blur", handleEvent, false);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/justification-2c.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+span { display:inline-block; width:100px; height:10px; background:yellow; }
+</style>
+</head>
+<!-- Test that &nbsp; has justification space added. -->
+<body style="text-align:justify; width:300px;">
+<span></span>&nbsp;<span></span>
+<span></span>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/justification-2d.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+span { display:inline-block; width:100px; height:10px; background:yellow; }
+</style>
+</head>
+<!-- Test that U+2007 FIGURE SPACE does not have justification space added. -->
+<body style="text-align:justify; width:300px;">
+<span></span>&#x2007;<span></span>
+<span></span>
+</body>
+</html>
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -7,16 +7,18 @@
 random-if(MOZ_WIDGET_TOOLKIT!="cocoa") == font-size-adjust-02.html font-size-adjust-02-ref.html
 # This currently fails because line spacing does not respect font-size-adjust
 # in the "obvious" way, but it is unclear what the behavior should really be;
 # see bug #366138 for some (inconclusive) discussion
 # == font-size-adjust-03.html font-size-adjust-03-ref.html
 == justification-1.html justification-1-ref.html
 == justification-2a.html justification-2-ref.html
 == justification-2b.html justification-2-ref.html
+== justification-2c.html justification-2-ref.html
+!= justification-2d.html justification-2-ref.html
 == line-editing-1a.html line-editing-1-ref.html
 == line-editing-1b.html line-editing-1-ref.html
 == line-editing-1c.html line-editing-1-ref.html
 == line-editing-1d.html line-editing-1-ref.html
 == line-editing-1e.html line-editing-1-ref.html
 == long-1.html long-ref.html
 == pre-line-1.html pre-line-1-ref.html
 == pre-line-2.html pre-line-2-ref.html
--- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
@@ -610,20 +610,16 @@ nsSVGForeignObjectFrame::InvalidateDirty
 
   nsRect rect = ToCanvasBounds(r, GetCanvasTM(), PresContext());
 
   // Don't invalidate areas outside our bounds:
   rect.IntersectRect(rect, mRect);
   if (rect.IsEmpty())
     return;
 
-  // XXX invalidate the entire covered region
-  // See bug 418063
-  rect.UnionRect(rect, mRect);
-
   rect = nsSVGUtils::FindFilterInvalidation(this, rect);
   aOuter->InvalidateWithFlags(rect, aFlags);
 }
 
 void
 nsSVGForeignObjectFrame::FlushDirtyRegion()
 {
   if ((mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) ||
--- a/layout/xul/base/src/nsXULPopupManager.cpp
+++ b/layout/xul/base/src/nsXULPopupManager.cpp
@@ -345,17 +345,19 @@ nsXULPopupManager::SetTriggerEvent(nsIDO
       nsEvent* event;
       event = privateEvent->GetInternalNSEvent();
       if (event) {
         nsIDocument* doc = aPopup->GetCurrentDoc();
         if (doc) {
           nsIPresShell* presShell = doc->GetPrimaryShell();
           if (presShell && presShell->GetPresContext()) {
             nsPresContext* rootDocPresContext =
-                presShell->GetPresContext()->RootPresContext();
+              presShell->GetPresContext()->GetRootPresContext();
+            if (!rootDocPresContext)
+              return;
             nsIFrame* rootDocumentRootFrame = rootDocPresContext->
                 PresShell()->FrameManager()->GetRootFrame();
             if ((event->eventStructType == NS_MOUSE_EVENT || 
                  event->eventStructType == NS_MOUSE_SCROLL_EVENT) &&
                  !(static_cast<nsGUIEvent *>(event))->widget) {
               // no widget, so just use the client point if available
               nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
               nsIntPoint clientPt;
@@ -1015,18 +1017,24 @@ nsXULPopupManager::FirePopupShowingEvent
   //   additional fields for the anchor node and position and so forth. This
   //   is where those details would be retrieved. This removes the need for
   //   all the globals people keep adding to nsIDOMXULDocument.
   nsEventStatus status = nsEventStatus_eIgnore;
   nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING, nsnull, nsMouseEvent::eReal);
 
   // coordinates are relative to the root widget
   nsPresContext* rootPresContext =
-    presShell->GetPresContext()->RootPresContext();
-  rootPresContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(event.widget));
+    presShell->GetPresContext()->GetRootPresContext();
+  if (rootPresContext) {
+    rootPresContext->PresShell()->GetViewManager()->
+      GetRootWidget(getter_AddRefs(event.widget));
+  }
+  else {
+    event.widget = nsnull;
+  }
 
   event.refPoint = mCachedMousePoint;
   nsEventDispatcher::Dispatch(aPopup, aPresContext, &event, nsnull, &status);
   mCachedMousePoint = nsIntPoint(0, 0);
 
   // if a panel, blur whatever has focus so that the panel can take the focus.
   // This is done after the popupshowing event in case that event is cancelled.
   // Using noautofocus="true" will disable this behaviour, which is needed for
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -1036,17 +1036,20 @@ NPError NP_CALLBACK
   // Block Adobe Acrobat from loading URLs that are not http:, https:,
   // or ftp: URLs if the given target is null.
   if (!target && relativeURL &&
       (strncmp(relativeURL, "http:", 5) != 0) &&
       (strncmp(relativeURL, "https:", 6) != 0) &&
       (strncmp(relativeURL, "ftp:", 4) != 0)) {
     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
 
-    const char *name = nsPluginHost::GetPluginName(inst);
+    
+    const char *name;
+    nsRefPtr<nsPluginHost> host = dont_AddRef(nsPluginHost::GetInst());
+    host->GetPluginName(inst, &name);
 
     if (name && strstr(name, "Adobe") && strstr(name, "Acrobat")) {
       return NPERR_NO_ERROR;
     }
   }
 
   return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
                                     eNPPStreamTypeInternal_Get);
--- a/modules/plugin/base/src/nsPluginHost.cpp
+++ b/modules/plugin/base/src/nsPluginHost.cpp
@@ -146,26 +146,29 @@
 #include "nsIWebNavigation.h"
 #include "nsISupportsArray.h"
 #include "nsIDocShell.h"
 #include "nsPluginNativeWindow.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentErrors.h"
+#include "mozilla/TimeStamp.h"
 
 #if defined(XP_WIN)
 #include "windows.h"
 #include "winbase.h"
 #endif
 
 #if defined(XP_UNIX) && defined(MOZ_WIDGET_GTK2) & defined(MOZ_X11)
 #include <gdk/gdkx.h> // for GDK_DISPLAY()
 #endif
 
+using mozilla::TimeStamp;
+
 // Null out a strong ref to a linked list iteratively to avoid
 // exhausting the stack (bug 486349).
 #define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_)                \
   {                                                                  \
     while (list_) {                                                  \
       type_ temp = list_->mNext_;                                    \
       list_->mNext_ = nsnull;                                        \
       list_ = temp;                                                  \
@@ -221,18 +224,16 @@ PRLogModuleInfo* nsPluginLogging::gPlugi
 #define PLUGIN_PROPERTIES_URL "chrome://global/locale/downloadProgress.properties"
 
 // #defines for plugin cache and prefs
 #define NS_PREF_MAX_NUM_CACHED_PLUGINS "browser.plugins.max_num_cached_plugins"
 #define DEFAULT_NUMBER_OF_STOPPED_PLUGINS 10
 
 #define MAGIC_REQUEST_CONTEXT 0x01020304
 
-static nsPluginInstanceTagList *gActivePluginList;
-
 #ifdef CALL_SAFETY_ON
 PRBool gSkipPluginSafeCalls = PR_FALSE;
 #endif
 
 nsIFile *nsPluginHost::sPluginTempDir;
 nsPluginHost *nsPluginHost::sInst;
 
 // flat file reg funcs
@@ -448,18 +449,17 @@ public:
   // Called by GetURL and PostURL (via NewStream)
   nsresult Initialize(nsIURI *aURL,
                       nsIPluginInstance *aInstance,
                       nsIPluginStreamListener *aListener,
                       PRInt32 requestCount = 1);
 
   nsresult InitializeEmbedded(nsIURI *aURL,
                              nsIPluginInstance* aInstance,
-                             nsIPluginInstanceOwner *aOwner = nsnull,
-                             nsIPluginHost *aHost = nsnull);
+                             nsIPluginInstanceOwner *aOwner = nsnull);
 
   nsresult InitializeFullPage(nsIPluginInstance *aInstance);
 
   nsresult OnFileAvailable(nsIFile* aFile);
 
   nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
   
   nsIPluginInstance *GetPluginInstance() { return mInstance; }
@@ -484,17 +484,16 @@ private:
    * been called.
    */
   PRPackedBool      mStartBinding;
   PRPackedBool      mHaveFiredOnStartRequest;
   // these get passed to the plugin stream listener
   char                    *mMIMEType;
   PRUint32                mLength;
   PRInt32                 mStreamType;
-  nsIPluginHost           *mHost;
 
   // local cached file, we save the content into local cache if browser cache is not available,
   // or plugin asks stream as file and it expects file extension until bug 90558 got fixed
   nsIFile                 *mLocalCachedFile;
   nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
   nsHashtable             *mDataForwardToRequest;
 
 public:
@@ -817,17 +816,16 @@ nsPluginCacheListener::OnStopRequest(nsI
 }
 
 nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
 {
   mURL = nsnull;
   mOwner = nsnull;
   mInstance = nsnull;
   mPStreamListener = nsnull;
-  mHost = nsnull;
   mStreamType = NP_NORMAL;
   mStartBinding = PR_FALSE;
   mAbort = PR_FALSE;
   mRequestFailed = PR_FALSE;
 
   mPendingRequests = 0;
   mHaveFiredOnStartRequest = PR_FALSE;
   mDataForwardToRequest = nsnull;
@@ -843,17 +841,16 @@ nsPluginStreamListenerPeer::~nsPluginStr
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     ("nsPluginStreamListenerPeer::dtor this=%p, url=%s%c",this, urlSpec.get(), mLocalCachedFile?',':'\n'));
 #endif
 
   NS_IF_RELEASE(mURL);
   NS_IF_RELEASE(mOwner);
   NS_IF_RELEASE(mInstance);
   NS_IF_RELEASE(mPStreamListener);
-  NS_IF_RELEASE(mHost);
 
   // close FD of mFileCacheOutputStream if it's still open
   // or we won't be able to remove the cache file
   if (mFileCacheOutputStream)
     mFileCacheOutputStream = nsnull;
 
   // if we have mLocalCachedFile lets release it
   // and it'll be fiscally remove if refcnt == 1
@@ -924,22 +921,21 @@ nsresult nsPluginStreamListenerPeer::Ini
 
   return NS_OK;
 }
 
 
 /* Called by NewEmbeddedPluginStream() - if this is called, we weren't
  * able to load the plugin, so we need to load it later once we figure
  * out the mimetype.  In order to load it later, we need the plugin
- * host and instance owner.
+ * instance owner.
  */
 nsresult nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI *aURL,
                                                         nsIPluginInstance* aInstance,
-                                                        nsIPluginInstanceOwner *aOwner,
-                                                        nsIPluginHost *aHost)
+                                                        nsIPluginInstanceOwner *aOwner)
 {
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec;
   aURL->GetSpec(urlSpec);
 
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
         ("nsPluginStreamListenerPeer::InitializeEmbedded url=%s\n", urlSpec.get()));
 
@@ -951,19 +947,16 @@ nsresult nsPluginStreamListenerPeer::Ini
 
   if (aInstance) {
     NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeEmbedded mInstance != nsnull");
     mInstance = aInstance;
     NS_ADDREF(mInstance);
   } else {
     mOwner = aOwner;
     NS_IF_ADDREF(mOwner);
-
-    mHost = aHost;
-    NS_IF_ADDREF(mHost);
   }
 
   mPluginStreamInfo = new nsPluginStreamInfo();
   if (!mPluginStreamInfo)
     return NS_ERROR_OUT_OF_MEMORY;
 
   mPluginStreamInfo->SetPluginInstance(aInstance);
   mPluginStreamInfo->SetPluginStreamListenerPeer(this);
@@ -1006,43 +999,43 @@ nsresult nsPluginStreamListenerPeer::Ini
 //
 // These files will be deleted when the host is destroyed.
 //
 // TODO? What if we fill up the the dest dir?
 nsresult
 nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
 {
   nsresult rv = NS_OK;
-  // lets try to reused a file if we already have in the local plugin cache
-  // we loop through all of active plugins
-  // and call |nsPluginStreamInfo::UseExistingPluginCacheFile()| on opened stream
-  // will return RP_TRUE if file exisrs
-  // and some conditions are matched, in this case that file will be use
-  // in |::OnFileAvailable()| calls w/o rewriting the file again.
-  // The file will be deleted in |nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer|
+
   PRBool useExistingCacheFile = PR_FALSE;
-  nsPluginInstanceTag *pActivePlugins = gActivePluginList->mFirst;
-  while (pActivePlugins && pActivePlugins->mStreams && !useExistingCacheFile) {
-    // most recent streams are at the end of list
-    PRInt32 cnt;
-    pActivePlugins->mStreams->Count((PRUint32*)&cnt);
-    while (--cnt >= 0 && !useExistingCacheFile) {
-      nsPluginStreamListenerPeer *lp =
-        reinterpret_cast<nsPluginStreamListenerPeer *>(pActivePlugins->mStreams->ElementAt(cnt));
-      if (lp) {
-        if (lp->mLocalCachedFile &&
-            lp->mPluginStreamInfo &&
-            (useExistingCacheFile =
-             lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo))) {
-            NS_ADDREF(mLocalCachedFile = lp->mLocalCachedFile);
+
+  nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
+  nsTArray< nsAutoPtr<nsPluginInstanceTag> > *instanceTags = pluginHost->InstanceTagArray();
+  for (PRUint32 i = 0; i < instanceTags->Length(); i++) {
+    nsPluginInstanceTag *instanceTag = (*instanceTags)[i];
+    if (instanceTag->mStreams) {
+      // most recent streams are at the end of list
+      PRInt32 cnt;
+      instanceTag->mStreams->Count((PRUint32*)&cnt);
+      while (--cnt >= 0) {
+        nsPluginStreamListenerPeer *lp =
+          reinterpret_cast<nsPluginStreamListenerPeer*>(instanceTag->mStreams->ElementAt(cnt));
+        if (lp && lp->mLocalCachedFile && lp->mPluginStreamInfo) {
+          useExistingCacheFile = lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo);
+          if (useExistingCacheFile) {
+            mLocalCachedFile = lp->mLocalCachedFile;
+            NS_ADDREF(mLocalCachedFile);
+            break;
+          }
+          NS_RELEASE(lp);
         }
-        NS_RELEASE(lp);
       }
+      if (useExistingCacheFile)
+        break;
     }
-    pActivePlugins = pActivePlugins->mNext;
   }
 
   if (!useExistingCacheFile) {
     nsCOMPtr<nsIFile> pluginTmp;
     rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
     if (NS_FAILED(rv)) {
       return rv;
     }
@@ -1083,25 +1076,25 @@ nsPluginStreamListenerPeer::SetupPluginC
     // add one extra refcnt, we can use NS_RELEASE2(mLocalCachedFile...) in dtor
     // to remove this file when refcnt == 1
     NS_ADDREF(mLocalCachedFile);
   }
 
   // add this listenerPeer to list of stream peers for this instance
   // it'll delay release of listenerPeer until nsPluginInstanceTag::~nsPluginInstanceTag
   // and the temp file is going to stay alive until then
-  pActivePlugins = gActivePluginList->find(mInstance);
-  if (pActivePlugins) {
-    if (!pActivePlugins->mStreams &&
-       (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(pActivePlugins->mStreams))))) {
+  nsPluginInstanceTag *instanceTag = pluginHost->FindInstanceTag(mInstance);
+  if (instanceTag) {
+    if (!instanceTag->mStreams &&
+        (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(instanceTag->mStreams))))) {
       return rv;
     }
 
     nsISupports* supports = static_cast<nsISupports*>((static_cast<nsIStreamListener*>(this)));
-    pActivePlugins->mStreams->AppendElement(supports);
+    instanceTag->mStreams->AppendElement(supports);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
                                            nsISupports* aContext)
@@ -1220,24 +1213,26 @@ nsPluginStreamListenerPeer::OnStartReque
   // didn't have the mimetype.  Now that we do (aContentType),
   // we'll try again with SetUpPluginInstance()
   // which is called by InstantiateEmbeddedPlugin()
   // NOTE: we don't want to try again if we didn't get the MIME type this time
 
   if (!mInstance && mOwner && !aContentType.IsEmpty()) {
     mOwner->GetInstance(mInstance);
     mOwner->GetWindow(window);
-    if (!mInstance && mHost && window) {
+    if (!mInstance && window) {
+      nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
+
       // determine if we need to try embedded again. FullPage takes a different code path
       PRInt32 mode;
       mOwner->GetMode(&mode);
       if (mode == NP_EMBED)
-        rv = mHost->InstantiateEmbeddedPlugin(aContentType.get(), aURL, mOwner);
+        rv = pluginHost->InstantiateEmbeddedPlugin(aContentType.get(), aURL, mOwner);
       else
-        rv = mHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
+        rv = pluginHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
 
       if (NS_OK == rv) {
         // GetInstance() adds a ref
         mOwner->GetInstance(mInstance);
         if (mInstance) {
           mInstance->Start();
           mOwner->CreateWidget();
           // If we've got a native window, the let the plugin know about it.
@@ -1680,18 +1675,16 @@ nsPluginStreamListenerPeer::VisitHeader(
   return listener->NewResponseHeader(PromiseFlatCString(header).get(),
                                      PromiseFlatCString(value).get());
 }
 
 nsPluginHost::nsPluginHost()
   // No need to initialize members to nsnull, PR_FALSE etc because this class
   // has a zeroing operator new.
 {
-  gActivePluginList = &mPluginInstanceTagList;
-
   // check to see if pref is set at startup to let plugins take over in
   // full page mode for certain image mime types that we handle internally
   mPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (mPrefService) {
     PRBool tmp;
     nsresult rv = mPrefService->GetBoolPref("plugin.override_internal_types",
                                             &tmp);
     if (NS_SUCCEEDED(rv)) {
@@ -1703,16 +1696,21 @@ nsPluginHost::nsPluginHost()
       mAllowAlienStarHandler = tmp;
     }
 
     rv = mPrefService->GetBoolPref("plugin.default_plugin_disabled", &tmp);
     if (NS_SUCCEEDED(rv)) {
       mDefaultPluginDisabled = tmp;
     }
 
+    rv = mPrefService->GetBoolPref("plugin.disable", &tmp);
+    if (NS_SUCCEEDED(rv)) {
+      mPluginsDisabled = tmp;
+    }
+
 #ifdef WINCE
     mDefaultPluginDisabled = PR_TRUE;
 #endif
   }
 
   nsCOMPtr<nsIObserverService> obsService = do_GetService("@mozilla.org/observer-service;1");
   if (obsService) {
     obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
@@ -1761,53 +1759,38 @@ nsPluginHost::GetInst()
       return nsnull;
     NS_ADDREF(sInst);
   }
 
   NS_ADDREF(sInst);
   return sInst;
 }
 
-// static
-const char *
-nsPluginHost::GetPluginName(nsIPluginInstance *aPluginInstance)
-{
-  nsPluginInstanceTag *plugin =
-    gActivePluginList ? gActivePluginList->find(aPluginInstance) : nsnull;
-
-  if (plugin && plugin->mPluginTag)
-    return plugin->mPluginTag->mName.get();
-
-  return nsnull;
-}
-
 PRBool nsPluginHost::IsRunningPlugin(nsPluginTag * plugin)
 {
   if (!plugin)
     return PR_FALSE;
 
-  // we can check for mLibrary to be non-zero and then ask nsIPluginInstance
-  // in nsPluginInstanceTagList to see if plugin with matching mime type is not stopped
   if (!plugin->mLibrary)
     return PR_FALSE;
 
   for (int i = 0; i < plugin->mVariants; i++) {
-    nsPluginInstanceTag * p = mPluginInstanceTagList.find(plugin->mMimeTypeArray[i]);
-    if (p && p->mInstance->IsRunning())
+    nsPluginInstanceTag *instanceTag = FindInstanceTag(plugin->mMimeTypeArray[i]);
+    if (instanceTag && instanceTag->mInstance->IsRunning())
       return PR_TRUE;
   }
 
   return PR_FALSE;
 }
 
 nsresult nsPluginHost::ReloadPlugins(PRBool reloadPages)
 {
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
-  reloadPages, mPluginInstanceTagList.mCount));
+  reloadPages, mInstanceTags.Length()));
 
   nsresult rv = NS_OK;
 
   // this will create the initial plugin list out of cache
   // if it was not created yet
   if (!mPluginsLoaded)
     return LoadPlugins();
 
@@ -1822,28 +1805,24 @@ nsresult nsPluginHost::ReloadPlugins(PRB
   PRBool pluginschanged = PR_TRUE;
   FindPlugins(PR_FALSE, &pluginschanged);
 
   // if no changed detected, return an appropriate error code
   if (!pluginschanged)
     return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
 
   nsCOMPtr<nsISupportsArray> instsToReload;
-
   if (reloadPages) {
     NS_NewISupportsArray(getter_AddRefs(instsToReload));
 
     // Then stop any running plugin instances but hold on to the documents in the array
     // We are going to need to restart the instances in these documents later
-    mPluginInstanceTagList.stopRunning(instsToReload, nsnull);
+    StopRunningInstances(instsToReload, nsnull);
   }
 
-  // clean active plugin list
-  mPluginInstanceTagList.removeAllStopped();
-
   // shutdown plugins and kill the list if there are no running plugins
   nsRefPtr<nsPluginTag> prev;
   nsRefPtr<nsPluginTag> next;
 
   for (nsRefPtr<nsPluginTag> p = mPlugins; p != nsnull;) {
     next = p->mNext;
 
     // only remove our plugin from the list if it's not running.
@@ -1882,17 +1861,17 @@ nsresult nsPluginHost::ReloadPlugins(PRB
       c > 0) {
     nsCOMPtr<nsIRunnable> ev = new nsPluginDocReframeEvent(instsToReload);
     if (ev)
       NS_DispatchToCurrentThread(ev);
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::ReloadPlugins End active_instance_count=%d\n",
-  mPluginInstanceTagList.mCount));
+  mInstanceTags.Length()));
 
   return rv;
 }
 
 #define NS_RETURN_UASTRING_SIZE 128
 
 nsresult nsPluginHost::UserAgent(const char **retstring)
 {
@@ -2204,20 +2183,17 @@ NS_IMETHODIMP nsPluginHost::Destroy()
 
   if (mIsDestroyed)
     return NS_OK;
 
   mIsDestroyed = PR_TRUE;
 
   // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
   // for those plugins who want it
-  mPluginInstanceTagList.stopRunning(nsnull, nsnull);
-
-  // at this point nsIPlugin::Shutdown calls will be performed if needed
-  mPluginInstanceTagList.shutdown();
+  StopRunningInstances(nsnull, nsnull);
 
   nsPluginTag *pluginTag;
   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
     pluginTag->TryUnloadPlugin();
   }
 
   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mPlugins, mNext);
   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
@@ -2249,16 +2225,39 @@ void nsPluginHost::UnloadUnusedLibraries
   for (PRUint32 i = 0; i < mUnusedLibraries.Length(); i++) {
     PRLibrary * library = mUnusedLibraries[i];
     if (library)
       PostPluginUnloadEvent(library);
   }
   mUnusedLibraries.Clear();
 }
 
+void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
+{
+  PRBool hasInstance = PR_FALSE;
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    if (mInstanceTags[i]->mPluginTag == aPluginTag) {
+      hasInstance = PR_TRUE;
+      break;
+    }
+  }
+
+  if (!hasInstance) {
+    nsresult rv;
+    nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+    if (NS_FAILED(rv))
+      return;
+
+    PRBool unloadPluginsASAP = PR_FALSE;
+    rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
+    if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
+      aPluginTag->TryUnloadPlugin();
+  }
+}
+
 nsresult
 nsPluginHost::GetPluginTempDir(nsIFile **aDir)
 {
   if (!sPluginTempDir) {
     nsCOMPtr<nsIFile> tmpDir;
     nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
                                          getter_AddRefs(tmpDir));
     NS_ENSURE_SUCCESS(rv, rv);
@@ -2597,17 +2596,17 @@ nsresult nsPluginHost::FindStoppedPlugin
                                                nsIPluginInstanceOwner *aOwner)
 {
   nsCAutoString url;
   if (!aURL)
     return NS_ERROR_FAILURE;
 
   aURL->GetAsciiSpec(url);
 
-  nsPluginInstanceTag *instanceTag = mPluginInstanceTagList.findStopped(url.get());
+  nsPluginInstanceTag *instanceTag = FindStoppedInstanceTag(url.get());
 
   if (instanceTag && !instanceTag->mInstance->IsRunning()) {
     NPWindow* window = nsnull;
     aOwner->GetWindow(window);
 
     nsIPluginInstance* instance = static_cast<nsIPluginInstance*>(instanceTag->mInstance);
     aOwner->SetInstance(instance);
     instance->SetOwner(aOwner);
@@ -2641,22 +2640,21 @@ nsresult nsPluginHost::AddInstanceToActi
   // It is going to be used later when we decide whether or not we should delay
   // unloading NPAPI dll from memory.
   nsPluginTag * pluginTag = nsnull;
   if (aPlugin) {
     pluginTag = FindTagForPlugin(aPlugin);
     NS_ASSERTION(pluginTag, "Plugin tag not found");
   }
 
-  nsPluginInstanceTag * plugin = new nsPluginInstanceTag(pluginTag, aInstance, url.get(), aDefaultPlugin);
-
-  if (!plugin)
+  nsPluginInstanceTag *instanceTag = new nsPluginInstanceTag(pluginTag, aInstance, url.get(), aDefaultPlugin);
+  if (!instanceTag)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  mPluginInstanceTagList.add(plugin);
+  mInstanceTags.AppendElement(instanceTag);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginHost::SetUpPluginInstance(const char *aMimeType,
                                                 nsIURI *aURL,
                                                 nsIPluginInstanceOwner *aOwner)
 {
   nsresult rv = NS_OK;
@@ -3689,16 +3687,19 @@ nsresult nsPluginHost::ScanPluginsDirect
 
 NS_IMETHODIMP nsPluginHost::LoadPlugins()
 {
   // do not do anything if it is already done
   // use ReloadPlugins() to enforce loading
   if (mPluginsLoaded)
     return NS_OK;
 
+  if (mPluginsDisabled)
+    return NS_OK;
+
   PRBool pluginschanged;
   nsresult rv = FindPlugins(PR_TRUE, &pluginschanged);
   if (NS_FAILED(rv))
     return rv;
 
   // only if plugins have changed will we notify plugin-change observers
   if (pluginschanged) {
     nsCOMPtr<nsIObserverService>
@@ -3905,18 +3906,17 @@ nsPluginHost::UpdatePluginInfo(nsPluginT
   WritePluginInfo();
   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
 
   if (!aPluginTag || aPluginTag->IsEnabled())
     return NS_OK;
 
   nsCOMPtr<nsISupportsArray> instsToReload;
   NS_NewISupportsArray(getter_AddRefs(instsToReload));
-  mPluginInstanceTagList.stopRunning(instsToReload, aPluginTag);
-  mPluginInstanceTagList.removeAllStopped();
+  StopRunningInstances(instsToReload, aPluginTag);
   
   PRUint32 c;
   if (instsToReload && NS_SUCCEEDED(instsToReload->Count(&c)) && c > 0) {
     nsCOMPtr<nsIRunnable> ev = new nsPluginDocReframeEvent(instsToReload);
     if (ev)
       NS_DispatchToCurrentThread(ev);
   }
 
@@ -4534,50 +4534,82 @@ nsPluginHost::StopPluginInstance(nsIPlug
 {
   if (PluginDestructionGuard::DelayDestroy(aInstance)) {
     return NS_OK;
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
 
-  nsPluginInstanceTag * plugin = mPluginInstanceTagList.find(aInstance);
-
-  if (plugin) {
+  aInstance->Stop();
+
+  nsPluginInstanceTag * instanceTag = FindInstanceTag(aInstance);
+  if (instanceTag) {
     // if the plugin does not want to be 'cached' just remove it
     PRBool doCache = PR_TRUE;
     aInstance->ShouldCache(&doCache);
-    if (!doCache) {
-      PRLibrary * library = nsnull;
-      if (plugin->mPluginTag)
-        library = plugin->mPluginTag->mLibrary;
-
-      mPluginInstanceTagList.remove(plugin);
-    } else {
-      // if it is allowed to be cached simply stop it, but first we should check
-      // if we haven't exceeded the maximum allowed number of cached instances
-
+    if (doCache) {
       // try to get the max cached plugins from a pref or use default
-      PRUint32 max_num;
+      PRUint32 cachedPluginLimit;
       nsresult rv = NS_ERROR_FAILURE;
       if (mPrefService)
-        rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&max_num);
+        rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&cachedPluginLimit);
       if (NS_FAILED(rv))
-        max_num = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
-
-      if (mPluginInstanceTagList.getStoppedCount() >= max_num) {
-        nsPluginInstanceTag * oldest = mPluginInstanceTagList.findOldestStopped();
-        if (oldest != nsnull)
-          mPluginInstanceTagList.remove(oldest);
+        cachedPluginLimit = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
+      
+      if (StoppedInstanceTagCount() >= cachedPluginLimit) {
+        nsPluginInstanceTag * oldestInstanceTag = FindOldestStoppedInstanceTag();
+        if (oldestInstanceTag) {
+          nsPluginTag* pluginTag = oldestInstanceTag->mPluginTag;
+          mInstanceTags.RemoveElement(oldestInstanceTag);
+          OnPluginInstanceDestroyed(pluginTag);
+        }
       }
+    } else {
+      nsPluginTag* pluginTag = instanceTag->mPluginTag;
+      mInstanceTags.RemoveElement(instanceTag);
+      OnPluginInstanceDestroyed(pluginTag);
     }
   }
+
   return NS_OK;
 }
 
+nsPluginInstanceTag*
+nsPluginHost::FindOldestStoppedInstanceTag()
+{
+  nsPluginInstanceTag *oldestInstanceTag = nsnull;
+  TimeStamp oldestTime = TimeStamp::Now();
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (instanceTag->mInstance->IsRunning())
+      continue;
+
+    TimeStamp time = instanceTag->mInstance->LastStopTime();
+    if (time < oldestTime) {
+      oldestTime = time;
+      oldestInstanceTag = instanceTag;
+    }
+  }
+
+  return oldestInstanceTag;
+}
+
+PRUint32
+nsPluginHost::StoppedInstanceTagCount()
+{
+  PRUint32 stoppedCount = 0;
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (!instanceTag->mInstance->IsRunning())
+      stoppedCount++;
+  }
+  return stoppedCount;
+}
+
 nsresult nsPluginHost::NewEmbeddedPluginStreamListener(nsIURI* aURL,
                                                        nsIPluginInstanceOwner *aOwner,
                                                        nsIPluginInstance* aInstance,
                                                        nsIStreamListener** aListener)
 {
   if (!aURL)
     return NS_OK;
 
@@ -4590,17 +4622,17 @@ nsresult nsPluginHost::NewEmbeddedPlugin
 
   // if we have an instance, everything has been set up
   // if we only have an owner, then we need to pass it in
   // so the listener can set up the instance later after
   // we've determined the mimetype of the stream
   if (aInstance != nsnull)
     rv = listener->InitializeEmbedded(aURL, aInstance);
   else if (aOwner != nsnull)
-    rv = listener->InitializeEmbedded(aURL, nsnull, aOwner, this);
+    rv = listener->InitializeEmbedded(aURL, nsnull, aOwner);
   else
     rv = NS_ERROR_ILLEGAL_VALUE;
   if (NS_SUCCEEDED(rv))
     NS_ADDREF(*aListener = listener);
 
   return rv;
 }
 
@@ -4650,17 +4682,17 @@ nsresult nsPluginHost::NewFullPagePlugin
   nsresult rv;
 
   rv = listener->InitializeFullPage(aInstance);
 
   aStreamListener = listener;
   NS_ADDREF(listener);
 
   // add peer to list of stream peers for this instance
-  nsPluginInstanceTag * p = mPluginInstanceTagList.find(aInstance);
+  nsPluginInstanceTag * p = FindInstanceTag(aInstance);
   if (p) {
     if (!p->mStreams && (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(p->mStreams)))))
       return rv;
     p->mStreams->AppendElement(aStreamListener);
   }
 
   return rv;
 }
@@ -4672,18 +4704,18 @@ NS_IMETHODIMP nsPluginHost::Observe(nsIS
   if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
     OnShutdown();
     Destroy();
     UnloadUnusedLibraries();
     sInst->Release();
   }
   if (!nsCRT::strcmp(NS_PRIVATE_BROWSING_SWITCH_TOPIC, aTopic)) {
     // inform all active plugins of changed private mode state
-    for (nsPluginInstanceTag* ap = mPluginInstanceTagList.mFirst; ap; ap = ap->mNext) {
-      nsNPAPIPluginInstance* pi = static_cast<nsNPAPIPluginInstance*>(ap->mInstance);
+    for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+      nsNPAPIPluginInstance* pi = static_cast<nsNPAPIPluginInstance*>(mInstanceTags[i]->mInstance);
       pi->PrivateModeStateChanged();
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPluginHost::HandleBadPlugin(PRLibrary* aLibrary, nsIPluginInstance *aInstance)
@@ -4735,17 +4767,17 @@ nsPluginHost::HandleBadPlugin(PRLibrary*
       return rv;
 
     if (NS_FAILED(rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginCheckboxMessage").get(),
                                  getter_Copies(checkboxMessage))))
       return rv;
 
     // add plugin name to the message
     nsCString pluginname;
-    nsPluginInstanceTag * p = mPluginInstanceTagList.find(aInstance);
+    nsPluginInstanceTag * p = FindInstanceTag(aInstance);
     if (p) {
       nsPluginTag * tag = p->mPluginTag;
       if (tag) {
         if (!tag->mName.IsEmpty())
           pluginname = tag->mName;
         else
           pluginname = tag->mFileName;
       }
@@ -5061,33 +5093,37 @@ nsPluginHost::InstantiateDummyJavaPlugin
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPluginHost::GetPluginName(nsIPluginInstance *aPluginInstance,
                             const char** aPluginName)
 {
-  *aPluginName = GetPluginName(aPluginInstance);
+  nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance);
+  if (!instanceTag || !instanceTag->mPluginTag)
+    return NS_ERROR_FAILURE;
+
+  *aPluginName = instanceTag->mPluginTag->mName.get();
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPluginHost::GetPluginTagForInstance(nsIPluginInstance *aPluginInstance,
                                       nsIPluginTag **aPluginTag)
 {
   NS_ENSURE_ARG_POINTER(aPluginInstance);
   NS_ENSURE_ARG_POINTER(aPluginTag);
+
+  nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance);
+
+  NS_ENSURE_TRUE(instanceTag && instanceTag->mPluginTag, NS_ERROR_FAILURE);
   
-  nsPluginInstanceTag *plugin =
-    gActivePluginList ? gActivePluginList->find(aPluginInstance) : nsnull;
-
-  NS_ENSURE_TRUE(plugin && plugin->mPluginTag, NS_ERROR_FAILURE);
-  
-  *aPluginTag = plugin->mPluginTag;
+  *aPluginTag = instanceTag->mPluginTag;
   NS_ADDREF(*aPluginTag);
   return NS_OK;
 }
 
 nsresult nsPluginHost::AddUnusedLibrary(PRLibrary * aLibrary)
 {
   if (!mUnusedLibraries.Contains(aLibrary)) // don't add duplicates
     mUnusedLibraries.AppendElement(aLibrary);
@@ -5164,53 +5200,136 @@ NS_IMETHODIMP nsPluginHost::Notify(nsITi
 #endif
   return NS_ERROR_FAILURE;
 }
 
 #ifdef MOZ_IPC
 void
 nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin)
 {
-  nsPluginTag* plugin = FindTagForPlugin(aPlugin);
-  if (!plugin) {
+  nsPluginTag* pluginTag = FindTagForPlugin(aPlugin);
+  if (!pluginTag) {
     NS_WARNING("nsPluginTag not found in nsPluginHost::PluginCrashed");
     return;
   }
 
   // Invalidate each nsPluginInstanceTag for the crashed plugin
 
-  nsPluginInstanceTag** pinstancetag = &mPluginInstanceTagList.mFirst;
-  while (*pinstancetag) {
-    nsPluginInstanceTag* instancetag = *pinstancetag;
-    if (instancetag->mPluginTag == plugin) {
+  for (PRUint32 i = mInstanceTags.Length(); i > 0; i--) {
+    nsPluginInstanceTag* instanceTag = mInstanceTags[i - 1];
+    if (instanceTag->mPluginTag == pluginTag) {
       // notify the content node (nsIObjectLoadingContent) that the plugin has crashed
       nsCOMPtr<nsIDOMElement> domElement;
-      instancetag->mInstance->GetDOMElement(getter_AddRefs(domElement));
+      instanceTag->mInstance->GetDOMElement(getter_AddRefs(domElement));
       nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
       if (objectContent) {
         objectContent->PluginCrashed();
       }
-
-      instancetag->mInstance->Stop();
-      *pinstancetag = (*pinstancetag)->mNext;
-      delete instancetag;
-    }
-    else {
-      pinstancetag = &(*pinstancetag)->mNext;
+      
+      instanceTag->mInstance->Stop();
+
+      nsPluginTag* pluginTag = instanceTag->mPluginTag;
+      mInstanceTags.RemoveElement(instanceTag);
+      OnPluginInstanceDestroyed(pluginTag);
     }
   }
 
   // Only after all instances have been invalidated is it safe to null
   // out nsPluginTag.mEntryPoint. The next time we try to create an
   // instance of this plugin we reload it (launch a new plugin process).
 
-  plugin->mEntryPoint = nsnull;
+  pluginTag->mEntryPoint = nsnull;
 }
 #endif
 
+nsPluginInstanceTag*
+nsPluginHost::FindInstanceTag(nsIPluginInstance *instance)
+{
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (instanceTag->mInstance == instance)
+      return instanceTag;
+  }
+  return nsnull;
+}
+
+nsPluginInstanceTag*
+nsPluginHost::FindInstanceTag(const char *mimetype)
+{
+  PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
+  
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag* instanceTag = mInstanceTags[i];
+    // give it some special treatment for the default plugin first
+    // because we cannot tell the default plugin by asking instance for a mime type
+    if (defaultplugin && instanceTag->mDefaultPlugin)
+      return instanceTag;
+    
+    if (!instanceTag->mInstance)
+      continue;
+    
+    const char* mt;
+    nsresult rv = instanceTag->mInstance->GetMIMEType(&mt);
+    if (NS_FAILED(rv))
+      continue;
+    
+    if (PL_strcasecmp(mt, mimetype) == 0)
+      return instanceTag;
+  }
+  return nsnull;
+}
+
+nsPluginInstanceTag*
+nsPluginHost::FindStoppedInstanceTag(const char * url)
+{
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (!PL_strcmp(url, instanceTag->mURL) && !instanceTag->mInstance->IsRunning())
+      return instanceTag;
+  }
+  return nsnull;
+}
+
+void 
+nsPluginHost::StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag)
+{
+  for (PRInt32 i = mInstanceTags.Length(); i > 0; i--) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i - 1];
+    nsNPAPIPluginInstance* instance = instanceTag->mInstance;
+    if (instance->IsRunning() && (!aPluginTag || aPluginTag == instanceTag->mPluginTag)) {
+      instance->SetWindow(nsnull);
+      instance->Stop();
+
+      // If we've been passed an array to return, lets collect all our documents,
+      // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
+      // to kickstart our instances.
+      if (aReloadDocs) {
+        nsCOMPtr<nsIPluginInstanceOwner> owner;
+        instance->GetOwner(getter_AddRefs(owner));
+        if (owner) {
+          nsCOMPtr<nsIDocument> doc;
+          owner->GetDocument(getter_AddRefs(doc));
+          if (doc && aReloadDocs->IndexOf(doc) == -1)  // don't allow for duplicates
+            aReloadDocs->AppendElement(doc);
+        }
+      }
+
+      nsPluginTag* pluginTag = instanceTag->mPluginTag;
+      mInstanceTags.RemoveElement(instanceTag);
+      OnPluginInstanceDestroyed(pluginTag);
+    }
+  }
+}
+
+nsTArray< nsAutoPtr<nsPluginInstanceTag> >*
+nsPluginHost::InstanceTagArray()
+{
+  return &mInstanceTags;
+}
+
 nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
                                                        nsISupports* aContext)
 {
   if (!mInstance)
     return NS_ERROR_FAILURE;
 
   // mInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
   mInstance->Stop();
@@ -5442,20 +5561,17 @@ public:
         return NS_OK;
       }
       r = static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(r));
     }
 
     PLUGIN_LOG(PLUGIN_LOG_NORMAL,
                ("Doing delayed destroy of instance %p\n", instance.get()));
 
-    instance->Stop();
-
     nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
-
     if (host)
       host->StopPluginInstance(instance);
 
     PLUGIN_LOG(PLUGIN_LOG_NORMAL,
                ("Done with delayed destroy of instance %p\n", instance.get()));
 
     return NS_OK;
   }
--- a/modules/plugin/base/src/nsPluginHost.h
+++ b/modules/plugin/base/src/nsPluginHost.h
@@ -76,17 +76,16 @@ class nsPluginHost : public nsIPluginHos
                      public nsITimerCallback,
                      public nsSupportsWeakReference
 {
 public:
   nsPluginHost();
   virtual ~nsPluginHost();
 
   static nsPluginHost* GetInst();
-  static const char *GetPluginName(nsIPluginInstance *aPluginInstance);
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPLUGINHOST
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
 
@@ -159,16 +158,26 @@ public:
 
   void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible);
   void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame);
 
 #ifdef MOZ_IPC
   void PluginCrashed(nsNPAPIPlugin* plugin);
 #endif
 
+  nsPluginInstanceTag *FindInstanceTag(nsIPluginInstance *instance);
+  nsPluginInstanceTag *FindInstanceTag(const char *mimetype);
+  nsPluginInstanceTag *FindStoppedInstanceTag(const char * url);
+  nsPluginInstanceTag *FindOldestStoppedInstanceTag();
+  PRUint32 StoppedInstanceTagCount();
+
+  void StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag);
+
+  nsTArray< nsAutoPtr<nsPluginInstanceTag> > *InstanceTagArray();
+
 private:
   nsresult
   TrySetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner);
 
   nsresult
   NewEmbeddedPluginStreamListener(nsIURI* aURL, nsIPluginInstanceOwner *aOwner,
                                   nsIPluginInstance* aInstance,
                                   nsIStreamListener** aListener);
@@ -238,33 +247,39 @@ private:
   // checks if given plugin is a duplicate of what we already have
   // in the plugin list but found in some different place
   PRBool IsDuplicatePlugin(nsPluginTag * aPluginTag);
 
   nsresult EnsurePrivateDirServiceProvider();
 
   // calls PostPluginUnloadEvent for each library in mUnusedLibraries
   void UnloadUnusedLibraries();
-  
+
+  void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag);
+
   nsRefPtr<nsPluginTag> mPlugins;
   nsRefPtr<nsPluginTag> mCachedPlugins;
   PRPackedBool mPluginsLoaded;
   PRPackedBool mDontShowBadPluginMessage;
   PRPackedBool mIsDestroyed;
 
   // set by pref plugin.override_internal_types
   PRPackedBool mOverrideInternalTypes;
 
   // set by pref plugin.allow_alien_star_handler
   PRPackedBool mAllowAlienStarHandler;
 
   // set by pref plugin.default_plugin_disabled
   PRPackedBool mDefaultPluginDisabled;
 
-  nsPluginInstanceTagList mPluginInstanceTagList;
+  // set by pref plugin.disable
+  PRPackedBool mPluginsDisabled;
+
+  nsTArray< nsAutoPtr<nsPluginInstanceTag> > mInstanceTags;
+
   nsTArray<PRLibrary*> mUnusedLibraries;
 
   nsCOMPtr<nsIFile> mPluginRegFile;
   nsCOMPtr<nsIPrefBranch> mPrefService;
 #ifdef XP_WIN
   nsRefPtr<nsPluginDirServiceProvider> mPrivateDirServiceProvider;
 #endif
 
--- a/modules/plugin/base/src/nsPluginNativeWindowWin.cpp
+++ b/modules/plugin/base/src/nsPluginNativeWindowWin.cpp
@@ -301,27 +301,29 @@ static LRESULT CALLBACK PluginWndProc(HW
     case WM_KEYUP:
       enablePopups = PR_TRUE;
 
       break;
 
 #ifndef WINCE
     case WM_MOUSEACTIVATE: {
       // If a child window of this plug-in is already focused,
-      // don't focus the parent to avoid focus dance.
-      // The following WM_SETFOCUS message will give the focus
-      // to the appropriate window anyway.
+      // don't focus the parent to avoid focus dance. We'll 
+      // receive a follow up WM_SETFOCUS which will notify
+      // the appropriate window anyway.
       HWND focusedWnd = ::GetFocus();
       if (!::IsChild((HWND)win->window, focusedWnd)) {
-        // This seems to be the only way we're
-        // notified when a child window that doesn't have this handler proc
-        // (read as: windows created by plugins like Adobe Acrobat)
-        // has been activated via clicking.
-        // should be handled here because some plugins won't forward
-        // messages to original WinProc.
+        // Notify the dom / focus manager the plugin has focus when one of
+        // it's child windows receives it. OOPP specific - this code is
+        // critical in notifying the dom of focus changes when the plugin
+        // window in the child process receives focus via a mouse click.
+        // WM_MOUSEACTIVATE is sent by nsWindow via a custom window event
+        // sent from PluginInstanceParent in response to focus events sent
+        // from the child. (bug 540052) Note, this gui event could also be
+        // sent directly from widget.
         nsCOMPtr<nsIWidget> widget;
         win->GetPluginWidget(getter_AddRefs(widget));
         if (widget) {
           nsGUIEvent event(PR_TRUE, NS_PLUGIN_ACTIVATE, widget);
           nsEventStatus status;
           widget->DispatchEvent(&event, status);
         }
       }
--- a/modules/plugin/base/src/nsPluginTags.cpp
+++ b/modules/plugin/base/src/nsPluginTags.cpp
@@ -566,17 +566,16 @@ nsPluginInstanceTag::nsPluginInstanceTag
                                          nsIPluginInstance* aInstance,
                                          const char * url,
                                          PRBool aDefaultPlugin)
 {
   NS_ASSERTION(aInstance, "Must have a valid plugin instance when creating an nsPluginInstanceTag");
   NS_ADDREF(aInstance);
   mInstance = static_cast<nsNPAPIPluginInstance*>(aInstance);
 
-  mNext = nsnull;
   mPluginTag = aPluginTag;
   
   mURL = PL_strdup(url);
 
   mDefaultPlugin = aDefaultPlugin;
 }
 
 nsPluginInstanceTag::~nsPluginInstanceTag()
@@ -588,236 +587,8 @@ nsPluginInstanceTag::~nsPluginInstanceTa
   if (owner)
     owner->SetInstance(nsnull);
   mInstance->InvalidateOwner();
 
   NS_RELEASE(mInstance);
 
   PL_strfree(mURL);
 }
-
-/* nsPluginInstanceTagList */
-
-nsPluginInstanceTagList::nsPluginInstanceTagList()
-{
-  mFirst = nsnull;
-  mLast = nsnull;
-  mCount = 0;
-}
-
-nsPluginInstanceTagList::~nsPluginInstanceTagList()
-{
-  if (!mFirst)
-    return;
-  shutdown();
-}
-
-void nsPluginInstanceTagList::shutdown()
-{
-  if (!mFirst)
-    return;
-  
-  for (nsPluginInstanceTag * plugin = mFirst; plugin != nsnull;) {
-    nsPluginInstanceTag * next = plugin->mNext;
-    remove(plugin);
-    plugin = next;
-  }
-  mFirst = nsnull;
-  mLast = nsnull;
-}
-
-PRInt32 nsPluginInstanceTagList::add(nsPluginInstanceTag * plugin)
-{
-  if (!mFirst) {
-    mFirst = plugin;
-    mLast = plugin;
-    mFirst->mNext = nsnull;
-  }
-  else {
-    mLast->mNext = plugin;
-    mLast = plugin;
-  }
-  mLast->mNext = nsnull;
-  mCount++;
-  return mCount;
-}
-
-PRBool nsPluginInstanceTagList::IsLastInstance(nsPluginInstanceTag * plugin)
-{
-  if (!plugin)
-    return PR_FALSE;
-  
-  if (!plugin->mPluginTag)
-    return PR_FALSE;
-  
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if ((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
-      return PR_FALSE;
-  }
-  return PR_TRUE;
-}
-
-PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin)
-{
-  if (!mFirst)
-    return PR_FALSE;
-  
-  nsPluginInstanceTag * prev = nsnull;
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (p == plugin) {
-      PRBool lastInstance = IsLastInstance(p);
-      
-      if (p == mFirst)
-        mFirst = p->mNext;
-      else
-        prev->mNext = p->mNext;
-      
-      if (prev && !prev->mNext)
-        mLast = prev;
-      
-      if (lastInstance) {
-        nsRefPtr<nsPluginTag> pluginTag = p->mPluginTag;
-        
-        delete p;
-        
-        if (pluginTag) {
-          nsresult rv;
-          nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
-          NS_ENSURE_SUCCESS(rv, rv);
-          
-          PRBool unloadPluginsASAP = PR_FALSE;
-          rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
-          if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
-            pluginTag->TryUnloadPlugin();
-        } else {
-          NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
-        }
-      } else {
-        delete p;
-      }
-      
-      mCount--;
-      return PR_TRUE;
-    }
-    prev = p;
-  }
-  return PR_FALSE;
-}
-
-// This method terminates all running instances of plugins and collects their
-// documents to be returned through an array. This method is used
-// when we are shutting down or when a plugins.refresh(1) happens.
-// If aPluginTag is given, then only that plugin is terminated
-void nsPluginInstanceTagList::stopRunning(nsISupportsArray* aReloadDocs,
-                                          nsPluginTag* aPluginTag)
-{
-  if (!mFirst)
-    return;
-  
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (p->mInstance->IsRunning() && (!aPluginTag || aPluginTag == p->mPluginTag)) {
-      p->mInstance->SetWindow(nsnull);
-      p->mInstance->Stop();
-      
-      // If we've been passed an array to return, lets collect all our documents,
-      // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
-      // to kickstart our instances.
-      if (aReloadDocs) {
-        nsCOMPtr<nsIPluginInstanceOwner> owner;
-        p->mInstance->GetOwner(getter_AddRefs(owner));
-        if (owner) {
-          nsCOMPtr<nsIDocument> doc;
-          owner->GetDocument(getter_AddRefs(doc));
-          if (doc && aReloadDocs->IndexOf(doc) == -1)  // don't allow for duplicates
-            aReloadDocs->AppendElement(doc);
-        }
-      }
-    }
-  }
-}
-
-void nsPluginInstanceTagList::removeAllStopped()
-{
-  if (!mFirst)
-    return;
-  
-  nsPluginInstanceTag * next = nsnull;
-  
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull;) {
-    next = p->mNext;
-    
-    if (!p->mInstance->IsRunning())
-      remove(p);
-    
-    p = next;
-  }
-  return;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::find(nsIPluginInstance* instance)
-{
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (p->mInstance == instance)
-      return p;
-  }
-  return nsnull;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::find(const char * mimetype)
-{
-  PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
-  
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    // give it some special treatment for the default plugin first
-    // because we cannot tell the default plugin by asking instance for a mime type
-    if (defaultplugin && p->mDefaultPlugin)
-      return p;
-    
-    if (!p->mInstance)
-      continue;
-    
-    const char* mt;
-    nsresult rv = p->mInstance->GetMIMEType(&mt);
-    if (NS_FAILED(rv))
-      continue;
-    
-    if (PL_strcasecmp(mt, mimetype) == 0)
-      return p;
-  }
-  return nsnull;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::findStopped(const char * url)
-{
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (!PL_strcmp(url, p->mURL) && !p->mInstance->IsRunning())
-      return p;
-  }
-  return nsnull;
-}
-
-PRUint32 nsPluginInstanceTagList::getStoppedCount()
-{
-  PRUint32 stoppedCount = 0;
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (!p->mInstance->IsRunning())
-      stoppedCount++;
-  }
-  return stoppedCount;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::findOldestStopped()
-{
-  nsPluginInstanceTag * res = nsnull;
-  TimeStamp oldestTime = TimeStamp::Now();
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (p->mInstance->IsRunning())
-      continue;
-
-    TimeStamp time = p->mInstance->LastStopTime();
-    if (time < oldestTime) {
-      oldestTime = time;
-      res = p;
-    }
-  }
-  
-  return res;
-}
--- a/modules/plugin/base/src/nsPluginTags.h
+++ b/modules/plugin/base/src/nsPluginTags.h
@@ -120,47 +120,23 @@ public:
 private:
   PRUint32      mFlags;
   
   nsresult EnsureMembersAreUTF8();
 };
 
 struct nsPluginInstanceTag
 {
-  nsPluginInstanceTag*   mNext;
   char*                  mURL;
   nsRefPtr<nsPluginTag>  mPluginTag;
   nsNPAPIPluginInstance* mInstance; // this must always be valid
-  PRPackedBool           mDefaultPlugin;
+  PRBool                 mDefaultPlugin;
   // Array holding all opened stream listeners for this entry
   nsCOMPtr <nsISupportsArray> mStreams; 
   
   nsPluginInstanceTag(nsPluginTag* aPluginTag,
                       nsIPluginInstance* aInstance, 
                       const char * url,
                       PRBool aDefaultPlugin);
   ~nsPluginInstanceTag();
 };
 
-class nsPluginInstanceTagList
-{
-public:
-  nsPluginInstanceTag *mFirst;
-  nsPluginInstanceTag *mLast;
-  PRInt32 mCount;
-  
-  nsPluginInstanceTagList();
-  ~nsPluginInstanceTagList();
-  
-  void shutdown();
-  PRBool add(nsPluginInstanceTag *plugin);
-  PRBool remove(nsPluginInstanceTag *plugin);
-  nsPluginInstanceTag *find(nsIPluginInstance *instance);
-  nsPluginInstanceTag *find(const char *mimetype);
-  nsPluginInstanceTag *findStopped(const char *url);
-  PRUint32 getStoppedCount();
-  nsPluginInstanceTag *findOldestStopped();
-  void removeAllStopped();
-  void stopRunning(nsISupportsArray *aReloadDocs, nsPluginTag *aPluginTag);
-  PRBool IsLastInstance(nsPluginInstanceTag *plugin);
-};
-
 #endif // nsPluginTags_h_
--- a/modules/plugin/test/mochitest/Makefile.in
+++ b/modules/plugin/test/mochitest/Makefile.in
@@ -65,20 +65,20 @@ include $(topsrcdir)/config/rules.mk
 		test_pluginstream_post.html \
 		test_pluginstream_poststream.html \
 		test_pluginstream_seek.html \
 		test_pluginstream_newstream.html \
 		test_multipleinstanceobjects.html \
 		test_streamNotify.html \
 		test_instantiation.html \
 		test_cookies.html \
+		test_npn_timers.html \
+		test_npn_asynccall.html \
 		$(NULL)
 
-#		test_npn_timers.html \ disabled for leaking
-#		test_npn_asynccall.html \ disabled for leaking
 #		test_npruntime_npnsetexception.html \ Disabled for e10s
 
 ifdef MOZ_IPC
 _MOCHITEST_FILES += \
 		test_crashing.html \
 		test_crashing2.html \
 		crashing_subpage.html \
 		$(NULL)
--- a/modules/plugin/test/mochitest/test_crashing2.html
+++ b/modules/plugin/test/mochitest/test_crashing2.html
@@ -46,33 +46,35 @@
       })
     });
   }
 
   function reloaded1() {
     var p = iframe.contentDocument.getElementById('plugin1');
     try {
       p.setColor('FF00FF00');
-      ok(true, "Reloading worked");
+      ok(true, "Reloading after crash-on-new worked");
     }
     catch (e) {
-      ok(false, "Reloading didn't give us a usable plugin");
+      ok(false, "Reloading after crash-on-new didn't give us a usable plugin");
     }
     p.crashOnDestroy();
     // the child crash should happen here
     p.parentNode.removeChild(p);
 
     window.frameLoaded = reloaded2;
-    iframe.contentWindow.location.reload();
+    SimpleTest.executeSoon(function() {
+      iframe.contentWindow.location.reload();
+    });
   }
 
   function reloaded2() {
     var p = iframe.contentDocument.getElementById('plugin1');
     try {
       p.setColor('FF00FF00');
-      ok(true, "Reloading worked");
+      ok(true, "Reloading after crash-on-destroy worked");
     }
     catch (e) {
-      ok(false, "Reloading didn't give us a usable plugin");
+      ok(false, "Reloading after crash-on-destroy didn't give us a usable plugin");
     }
     SimpleTest.finish();
   }
   </script>
--- a/modules/plugin/test/mochitest/test_getauthenticationinfo.html
+++ b/modules/plugin/test/mochitest/test_getauthenticationinfo.html
@@ -19,42 +19,42 @@ Test for NPN_GetAuthenticationInfo
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 
 function iframeLoad() {
   var plugin = iframe.contentDocument.getElementById("embedtest");
   // valid request
-  is(plugin.getAuthInfo("http", "localhost", 8888, "http", "testrealm"), 
+  is(plugin.getAuthInfo("http", "localhost", 8888, "basic", "testrealm"), 
       "user1|password1", 
       "correct user/pass retrieved");
   try {
     // invalid request -- wrong host
-    is(plugin.getAuthInfo("http", "example.com", 8888, "http", "testrealm"), 
+    is(plugin.getAuthInfo("http", "example.com", 8888, "basic", "testrealm"), 
         "user1|password1", 
         "correct user/pass retrieved");
     ok(false, "no exception was thrown");
   }
   catch (err) {
     ok(true, "expected exception caught");
   }
   try {
     // invalid request -- wrong port
-    is(plugin.getAuthInfo("http", "localhost", 90, "http", "testrealm"), 
+    is(plugin.getAuthInfo("http", "localhost", 90, "basic", "testrealm"), 
         "user1|password1", 
         "correct user/pass retrieved");
     ok(false, "no exception was thrown");
   }
   catch (err) {
     ok(true, "expected exception caught");
   }
   try {
     // invalid request -- wrong realm
-    is(plugin.getAuthInfo("http", "localhost", 8888, "http", "wrongrealm"), 
+    is(plugin.getAuthInfo("http", "localhost", 8888, "basic", "wrongrealm"), 
         "user1|password1", 
         "correct user/pass retrieved");
     ok(false, "no exception was thrown");
   }
   catch (err) {
     ok(true, "expected exception caught");
   }
   SimpleTest.finish();
--- a/modules/plugin/test/testplugin/nptest.cpp
+++ b/modules/plugin/test/testplugin/nptest.cpp
@@ -59,36 +59,39 @@
 #define PLUGIN_VERSION     "1.0.0.0"
 
 #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
 
 //
 // Intentional crash
 //
 
-static void
-Crash()
+int gCrashCount = 0;
+
+void
+IntentionalCrash()
 {
   char* bloatLog = getenv("XPCOM_MEM_BLOAT_LOG");
   if (bloatLog) {
     char* logExt = strstr(bloatLog, ".log");
     if (logExt) {
       bloatLog[strlen(bloatLog) - strlen(logExt)] = '\0';
     }
     ostringstream bloatName;
     bloatName << bloatLog << "_plugin_pid" << getpid();
     if (logExt) {
       bloatName << ".log";
     }
     FILE* processfd = fopen(bloatName.str().c_str(), "a");
     fprintf(processfd, "==> process %d will purposefully crash\n", getpid());
     fclose(processfd);
   }
-  void (*funcptr)() = NULL;
-  funcptr(); // Crash calling null function pointer
+  int *pi = NULL;
+  *pi = 55; // Crash dereferencing null pointer
+  ++gCrashCount;
 }
 
 //
 // static data
 //
 
 static NPNetscapeFuncs* sBrowserFuncs = NULL;
 static NPClass sNPClass;
@@ -670,17 +673,17 @@ NPP_New(NPMIMEType pluginType, NPP insta
       }
       if (range.length()) addRange(instanceData, range.c_str());
     }
     if (strcmp(argn[i], "newstream") == 0 &&
         strcmp(argv[i], "true") == 0) {
       instanceData->npnNewStream = true;
     }
     if (strcmp(argn[i], "newcrash") == 0) {
-      Crash();
+      IntentionalCrash();
     }
   }
 
   if (!browserSupportsWindowless || !pluginSupportsWindowlessMode()) {
     requestWindow = true;
   } else if (!pluginSupportsWindowMode()) {
     requestWindow = false;
   }
@@ -753,17 +756,17 @@ NPP_New(NPMIMEType pluginType, NPP insta
 
 NPError
 NPP_Destroy(NPP instance, NPSavedData** save)
 {
   printf("NPP_Destroy\n");
   InstanceData* instanceData = (InstanceData*)(instance->pdata);
 
   if (instanceData->crashOnDestroy)
-    Crash();
+    IntentionalCrash();
 
   if (instanceData->streamBuf) {
     free(instanceData->streamBuf);
   }
   if (instanceData->fileBuf) {
     free(instanceData->fileBuf);
   }
 
@@ -2096,17 +2099,17 @@ streamTest(NPObject* npobj, const NPVari
   }
 
   return true;
 }
 
 static bool
 crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
 {
-  Crash();
+  IntentionalCrash();
   VOID_TO_NPVARIANT(*result);
   return true;
 }
 
 static bool
 crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
 {
   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
@@ -2420,16 +2423,17 @@ asyncCallback(void* cookie)
       NPObject* windowObject;
       NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
       if (!windowObject)
         return;
       NPVariant arg, rval;
       BOOLEAN_TO_NPVARIANT(id->asyncCallbackResult, arg);
       NPN_Invoke(npp, windowObject, NPN_GetStringIdentifier(id->asyncTestScriptCallback.c_str()), &arg, 1, &rval);
       NPN_ReleaseVariantValue(&arg);
+      NPN_ReleaseObject(windowObject);
       break;
   }
 }
 
 static bool
 asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
 {
   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
--- a/netwerk/protocol/http/src/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/src/nsHttpChannel.cpp
@@ -662,20 +662,20 @@ nsHttpChannel::SetupTransaction()
 
     // create the transaction object
     mTransaction = new nsHttpTransaction();
     if (!mTransaction)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(mTransaction);
 
     // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer.
-    if (mLoadFlags & LOAD_ANONYMOUS) {
+    if (mLoadFlags & LOAD_ANONYMOUS)
         mCaps |= NS_HTTP_LOAD_ANONYMOUS;
-        mConnectionInfo->SetAnonymous();
-    }
+
+    mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
 
     nsCOMPtr<nsIAsyncInputStream> responseStream;
     rv = mTransaction->Init(mCaps, mConnectionInfo, &mRequestHead,
                             mUploadStream, mUploadStreamHasHeaders,
                             NS_GetCurrentThread(), callbacks, this,
                             getter_AddRefs(responseStream));
     if (NS_FAILED(rv)) {
         NS_RELEASE(mTransaction);
--- a/netwerk/protocol/http/src/nsHttpConnectionInfo.cpp
+++ b/netwerk/protocol/http/src/nsHttpConnectionInfo.cpp
@@ -81,8 +81,21 @@ nsHttpConnectionInfo::SetOriginServer(co
     // type in the hash key (this ensures that we will continue to speak the
     // right protocol even if our proxy preferences change).
     if (!mUsingHttpProxy && ProxyHost()) {
         mHashKey.AppendLiteral(" (");
         mHashKey.Append(ProxyType());
         mHashKey.Append(')');
     }
 }
+
+nsHttpConnectionInfo*
+nsHttpConnectionInfo::Clone() const
+{
+    nsHttpConnectionInfo* clone = new nsHttpConnectionInfo(mHost, mPort, mProxyInfo, mUsingSSL);
+    if (!clone)
+        return nsnull;
+
+    // Make sure the anonymous flag is transferred!
+    clone->SetAnonymous(mHashKey.CharAt(2) == 'A');
+    
+    return clone;
+}
--- a/netwerk/protocol/http/src/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/src/nsHttpConnectionInfo.h
@@ -92,16 +92,18 @@ public:
     const nsAFlatCString &HashKey() const { return mHashKey; }
 
     void SetOriginServer(const nsACString &host, PRInt32 port);
 
     void SetOriginServer(const char *host, PRInt32 port)
     {
         SetOriginServer(nsDependentCString(host), port);
     }
+    
+    nsHttpConnectionInfo* Clone() const;
 
     const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host().get() : nsnull; }
     PRInt32     ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
     const char *ProxyType() const { return mProxyInfo ? mProxyInfo->Type() : nsnull; }
 
     // Compare this connection info to another...
     // Two connections are 'equal' if they end up talking the same
     // protocol to the same server. This is needed to properly manage
@@ -115,17 +117,18 @@ public:
     }
 
     const char   *Host() const           { return mHost.get(); }
     PRInt32       Port() const           { return mPort; }
     nsProxyInfo  *ProxyInfo()            { return mProxyInfo; }
     PRBool        UsingHttpProxy() const { return mUsingHttpProxy; }
     PRBool        UsingSSL() const       { return mUsingSSL; }
     PRInt32       DefaultPort() const    { return mUsingSSL ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT; }
-    void          SetAnonymous()         { mHashKey.SetCharAt('A', 2); }
+    void          SetAnonymous(PRBool anon)         
+                                         { mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
             
 private:
     nsrefcnt               mRef;
     nsCString              mHashKey;
     nsCString              mHost;
     PRInt32                mPort;
     nsCOMPtr<nsProxyInfo>  mProxyInfo;
     PRPackedBool           mUsingHttpProxy;
--- a/netwerk/protocol/http/src/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/src/nsHttpConnectionMgr.cpp
@@ -675,17 +675,20 @@ nsHttpConnectionMgr::ProcessNewTransacti
 
     PRUint8 caps = trans->Caps();
     nsHttpConnectionInfo *ci = trans->ConnectionInfo();
     NS_ASSERTION(ci, "no connection info");
 
     nsCStringKey key(ci->HashKey());
     nsConnectionEntry *ent = (nsConnectionEntry *) mCT.Get(&key);
     if (!ent) {
-        ent = new nsConnectionEntry(ci);
+        nsHttpConnectionInfo *clone = ci->Clone();
+        if (!clone)
+            return NS_ERROR_OUT_OF_MEMORY;
+        ent = new nsConnectionEntry(clone);
         if (!ent)
             return NS_ERROR_OUT_OF_MEMORY;
         mCT.Put(&key, ent);
     }
 
     nsHttpConnection *conn;
 
     // check if the transaction already has a sticky reference to a connection.
--- a/netwerk/protocol/http/src/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/src/nsHttpTransaction.cpp
@@ -175,36 +175,42 @@ nsHttpTransaction::Init(PRUint8 caps,
     nsresult rv;
 
     LOG(("nsHttpTransaction::Init [this=%x caps=%x]\n", this, caps));
 
     NS_ASSERTION(cinfo, "ouch");
     NS_ASSERTION(requestHead, "ouch");
     NS_ASSERTION(target, "ouch");
 
-    // create transport event sink proxy that coalesces all events
-    rv = net_NewTransportEventSinkProxy(getter_AddRefs(mTransportSink),
-                                        eventsink, target, PR_TRUE);
-    if (NS_FAILED(rv)) return rv;
-
     mActivityDistributor = do_GetService(NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID, &rv);
     if (NS_FAILED(rv)) return rv;
 
-    PRBool active;
-    rv = mActivityDistributor->GetIsActive(&active);
-    if (NS_SUCCEEDED(rv) && active) {
+    PRBool activityDistributorActive;
+    rv = mActivityDistributor->GetIsActive(&activityDistributorActive);
+    if (NS_SUCCEEDED(rv) && activityDistributorActive) {
         // there are some observers registered at activity distributor, gather
         // nsISupports for the channel that called Init()
         mChannel = do_QueryInterface(eventsink);
         LOG(("nsHttpTransaction::Init() " \
              "mActivityDistributor is active " \
              "this=%x", this));
-    } else
+    } else {
         // there is no observer, so don't use it
+        activityDistributorActive = PR_FALSE;
         mActivityDistributor = nsnull;
+    }
+
+    // create transport event sink proxy. it coalesces all events if and only 
+    // if the activity observer is not active. when the observer is active
+    // we need not to coalesce any events to get all expected notifications
+    // of the transaction state, necessary for correct debugging and logging.
+    rv = net_NewTransportEventSinkProxy(getter_AddRefs(mTransportSink),
+                                        eventsink, target,
+                                        !activityDistributorActive);
+    if (NS_FAILED(rv)) return rv;
 
     NS_ADDREF(mConnInfo = cinfo);
     mCallbacks = callbacks;
     mConsumerTarget = target;
     mCaps = caps;
 
     if (requestHead->Method() == nsHttp::Head)
         mNoContent = PR_TRUE;
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -138,16 +138,26 @@ Tester.prototype = {
     var msg = "Console message: " + aConsoleMessage.message;
     if (this.currentTest)
       this.currentTest.addResult(new testMessage(msg));
     else
       this.dumper.dump("TEST-INFO | (browser-test.js) | " + msg);
   },
 
   nextTest: function Tester_nextTest() {
+    if (this.currentTest) {
+      // Run cleanup functions for the current test before moving on to the
+      // next one.
+      let testScope = this.currentTest.scope;
+      while (testScope.__cleanupFunctions.length > 0) {
+        let func = testScope.__cleanupFunctions.shift();
+        func.apply(testScope);
+      };
+    }
+
     // Check the window state for the current test before moving to the next one.
     // This also causes us to check before starting any tests, since nextTest()
     // is invoked to start the tests.
     this.waitForWindowsState(this.realNextTest);
   },
 
   realNextTest: function Test_realNextTest() {
     if (this.done) {
@@ -164,16 +174,25 @@ Tester.prototype = {
 
     // Load the tests into a testscope
     this.currentTest.scope = new testScope(this, this.currentTest);
 
     // Import utils in the test scope.
     this.currentTest.scope.EventUtils = this.EventUtils;
     this.currentTest.scope.SimpleTest = this.SimpleTest;
 
+    // Import head.js script if it exists.
+    var currentTestDirPath =
+      this.currentTest.path.substr(0, this.currentTest.path.lastIndexOf("/"));
+    var headPath = currentTestDirPath + "/head.js";
+    try {
+      this._scriptLoader.loadSubScript(headPath, this.currentTest.scope);
+    } catch (ex) { /* no head */ }
+
+    // Import the test script.
     try {
       this._scriptLoader.loadSubScript(this.currentTest.path,
                                        this.currentTest.scope);
 
       // Run the test
       this.currentTest.scope.test();
     } catch (ex) {
       this.currentTest.addResult(new testResult(false, "Exception thrown", ex, false));
@@ -183,16 +202,25 @@ Tester.prototype = {
     // If the test ran synchronously, move to the next test, otherwise the test
     // will trigger the next test when it is done.
     if (this.currentTest.scope.__done) {
       this.nextTest();
     }
     else {
       var self = this;
       this.currentTest.scope.__waitTimer = setTimeout(function() {
+        if (--self.currentTest.scope.__timeoutFactor > 0) {
+          // We were asked to wait a bit longer.
+          self.currentTest.scope.info(
+            "Longer timeout required, waiting longer...  Remaining timeouts: " +
+            self.currentTest.scope.__timeoutFactor);
+          self.currentTest.scope.__waitTimer =
+            setTimeout(arguments.callee, TIMEOUT_SECONDS * 1000);
+          return;
+        }
         self.currentTest.addResult(new testResult(false, "Timed out", "", false));
         self.currentTest.scope.__waitTimer = null;
         self.nextTest();
       }, TIMEOUT_SECONDS * 1000);
     }
   },
 
   QueryInterface: function(aIID) {
@@ -271,36 +299,46 @@ function testScope(aTester, aTest) {
 
     tm.mainThread.dispatch({
       run: function() {
         func();
       }
     }, Ci.nsIThread.DISPATCH_NORMAL);
   };
 
-  this.waitForExplicitFinish = function test_WFEF() {
+  this.waitForExplicitFinish = function test_waitForExplicitFinish() {
     self.__done = false;
   };
 
-  this.waitForFocus = function (callback, targetWindow) {
+  this.waitForFocus = function test_waitForFocus(callback, targetWindow) {
     self.SimpleTest.waitForFocus(callback, targetWindow);
   };
 
+  this.registerCleanupFunction = function test_registerCleanupFunction(aFunction) {
+    self.__cleanupFunctions.push(aFunction);
+  };
+
+  this.requestLongerTimeout = function test_requestLongerTimeout(aFactor) {
+    self.__timeoutFactor = aFactor;
+  };
+
   this.finish = function test_finish() {
     self.__done = true;
     if (self.__waitTimer) {
       self.executeSoon(function() {
         if (self.__done && self.__waitTimer) {
           clearTimeout(self.__waitTimer);
           self.__waitTimer = null;
           self.__tester.nextTest();
         }
       });
     }
   };
 }
 testScope.prototype = {
   __done: true,
   __waitTimer: null,
+  __cleanupFunctions: [],
+  __timeoutFactor: 1,
 
   EventUtils: {},
   SimpleTest: {}
 };
--- a/testing/mochitest/ssltunnel/ssltunnel.cpp
+++ b/testing/mochitest/ssltunnel/ssltunnel.cpp
@@ -62,16 +62,58 @@
 #include "key.h"
 #include "keyt.h"
 #include "ssl.h"
 #include "plhash.h"
 
 using std::string;
 using std::vector;
 
+#define IS_DELIM(m, c)          ((m)[(c) >> 3] & (1 << ((c) & 7)))
+#define SET_DELIM(m, c)         ((m)[(c) >> 3] |= (1 << ((c) & 7)))
+#define DELIM_TABLE_SIZE        32
+
+// Copied from nsCRT
+char* strtok2(char* string, const char* delims, char* *newStr)
+{
+  PR_ASSERT(string);
+  
+  char delimTable[DELIM_TABLE_SIZE];
+  PRUint32 i;
+  char* result;
+  char* str = string;
+  
+  for (i = 0; i < DELIM_TABLE_SIZE; i++)
+    delimTable[i] = '\0';
+  
+  for (i = 0; delims[i]; i++) {
+    SET_DELIM(delimTable, static_cast<PRUint8>(delims[i]));
+  }
+  
+  // skip to beginning
+  while (*str && IS_DELIM(delimTable, static_cast<PRUint8>(*str))) {
+    str++;
+  }
+  result = str;
+  
+  // fix up the end of the token
+  while (*str) {
+    if (IS_DELIM(delimTable, static_cast<PRUint8>(*str))) {
+      *str++ = '\0';
+      break;
+    }
+    str++;
+  }
+  *newStr = str;
+  
+  return str == result ? NULL : result;
+}
+
+
+
 enum client_auth_option {
   caNone = 0,
   caRequire = 1,
   caRequest = 2
 };
 
 // Structs for passing data into jobs on the thread pool
 typedef struct {
@@ -213,41 +255,42 @@ bool ReadConnectRequest(server_info_t* s
     return false;
   }
   
   printf(" parsing initial connect request, dump:\n%.*s\n", (int)buffer.present(), buffer.bufferhead);
 
   *result = 400;
 
   char* token;
-  token = strtok(buffer.bufferhead, " ");
+  char* _caret;
+  token = strtok2(buffer.bufferhead, " ", &_caret);
   if (!token) {
     printf(" no space found");
     return true;
   }
   if (strcmp(token, "CONNECT")) {
     printf(" not CONNECT request but %s", token);
     return true;
   }
 
-  token = strtok(NULL, " ");
+  token = strtok2(_caret, " ", &_caret);
   void* c = PL_HashTableLookup(server_info->host_cert_table, token);
   if (c)
     certificate = static_cast<char*>(c);
 
   host = "https://";
   host += token;
 
   c = PL_HashTableLookup(server_info->host_clientauth_table, token);
   if (c)
     *clientauth = *static_cast<client_auth_option*>(c);
   else
     *clientauth = caNone;
 
-  token = strtok(NULL, "/");
+  token = strtok2(_caret, "/", &_caret);
   if (strcmp(token, "HTTP")) {  
     printf(" not tailed with HTTP but with %s", token);
     return true;
   }
 
   *result = 200;
   return true;
 }
@@ -491,16 +534,18 @@ void HandleConnection(void* data)
 
             // We have to accept and handle the initial CONNECT request here
             PRInt32 response;
             if (!connect_accepted && ReadConnectRequest(ci->server_info, buffers[s],
                 &response, certificateToUse, &clientAuth, fullHost))
             {
               // Clean the request as it would be read
               buffers[s].bufferhead = buffers[s].buffertail = buffers[s].buffer;
+              in_flags |= PR_POLL_WRITE;
+              connect_accepted = true;
 
               // Store response to the oposite buffer
               if (response != 200)
               {
                 printf(" could not read the connect request, closing connection with %d", response);
                 client_done = true;
                 sprintf(buffers[s2].buffer, "HTTP/1.1 %d ERROR\r\nConnection: close\r\n\r\n", response);
                 buffers[s2].buffertail = buffers[s2].buffer + strlen(buffers[s2].buffer);
@@ -514,18 +559,16 @@ void HandleConnection(void* data)
               {
                 printf(" could not open connection to the real server\n");
                 client_error = true;
                 break;
               }
 
               printf(" accepted CONNECT request, connected to the server, sending OK to the client\n");
               // Send the response to the client socket
-              in_flags |= PR_POLL_WRITE;
-              connect_accepted = true;
               break;
             } // end of CONNECT handling
 
             if (!buffers[s].free())
             {
               // Do not poll for read when the buffer is full
               printf(" no place in our read buffer, stop reading");
               in_flags &= ~PR_POLL_READ;
@@ -699,60 +742,61 @@ server_info_t* findServerInfo(int portnu
   return NULL;
 }
 
 int processConfigLine(char* configLine)
 {
   if (*configLine == 0 || *configLine == '#')
     return 0;
 
-  char* keyword = strtok(configLine, ":");
+  char* _caret;
+  char* keyword = strtok2(configLine, ":", &_caret);
 
   // Configure usage of http/ssl tunneling proxy behavior
   if (!strcmp(keyword, "httpproxy"))
   {
-    char* value = strtok(NULL, ":");
+    char* value = strtok2(_caret, ":", &_caret);
     if (!strcmp(value, "1"))
       do_http_proxy = true;
 
     return 0;
   }
 
   // Configure the forward address of the target server
   if (!strcmp(keyword, "forward"))
   {
-    char* ipstring = strtok(NULL, ":");
+    char* ipstring = strtok2(_caret, ":", &_caret);
     if (PR_StringToNetAddr(ipstring, &remote_addr) != PR_SUCCESS) {
       fprintf(stderr, "Invalid remote IP address: %s\n", ipstring);
       return 1;
     }
-    char* serverportstring = strtok(NULL, ":");
+    char* serverportstring = strtok2(_caret, ":", &_caret);
     int port = atoi(serverportstring);
     if (port <= 0) {
       fprintf(stderr, "Invalid remote port: %s\n", serverportstring);
       return 1;
     }
     remote_addr.inet.port = PR_htons(port);
 
     return 0;
   }
 
   // Configure all listen sockets and port+certificate bindings
   if (!strcmp(keyword, "listen"))
   {
-    char* hostname = strtok(NULL, ":");
+    char* hostname = strtok2(_caret, ":", &_caret);
     char* hostportstring = NULL;
     if (strcmp(hostname, "*"))
     {
       any_host_spec_config = true;
-      hostportstring = strtok(NULL, ":");
+      hostportstring = strtok2(_caret, ":", &_caret);
     }
 
-    char* serverportstring = strtok(NULL, ":");
-    char* certnick = strtok(NULL, ":");
+    char* serverportstring = strtok2(_caret, ":", &_caret);
+    char* certnick = strtok2(_caret, ":", &_caret);
 
     int port = atoi(serverportstring);
     if (port <= 0) {
       fprintf(stderr, "Invalid port specified: %s\n", serverportstring);
       return 1;
     }
 
     if (server_info_t* existingServer = findServerInfo(port))
@@ -791,29 +835,29 @@ int processConfigLine(char* configLine)
       servers.push_back(server);
     }
 
     return 0;
   }
   
   if (!strcmp(keyword, "clientauth"))
   {
-    char* hostname = strtok(NULL, ":");
-    char* hostportstring = strtok(NULL, ":");
-    char* serverportstring = strtok(NULL, ":");
+    char* hostname = strtok2(_caret, ":", &_caret);
+    char* hostportstring = strtok2(_caret, ":", &_caret);
+    char* serverportstring = strtok2(_caret, ":", &_caret);
 
     int port = atoi(serverportstring);
     if (port <= 0) {
       fprintf(stderr, "Invalid port specified: %s\n", serverportstring);
       return 1;
     }
 
     if (server_info_t* existingServer = findServerInfo(port))
     {
-      char* authoptionstring = strtok(NULL, ":");
+      char* authoptionstring = strtok2(_caret, ":", &_caret);
       client_auth_option* authoption = new client_auth_option;
       if (!authoption) {
         fprintf(stderr, "Out of memory");
         return 1;
       }
 
       if (!strcmp(authoptionstring, "require"))
         *authoption = caRequire;
@@ -852,17 +896,17 @@ int processConfigLine(char* configLine)
     }
 
     return 0;
   }
 
   // Configure the NSS certificate database directory
   if (!strcmp(keyword, "certdbdir"))
   {
-    nssconfigdir = strtok(NULL, "\n");
+    nssconfigdir = strtok2(_caret, "\n", &_caret);
     return 0;
   }
 
   printf("Error: keyword \"%s\" unexpected\n", keyword);
   return 1;
 }
 
 int parseConfigFile(const char* filePath)
--- a/testing/mochitest/tests/browser/Makefile.in
+++ b/testing/mochitest/tests/browser/Makefile.in
@@ -39,23 +39,28 @@ DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = testing/mochitest/tests/browser
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-_BROWSER_TEST_FILES = 	  browser_pass.js \
+_BROWSER_TEST_FILES = \
+	                  head.js \
+	                  browser_head.js \
+	                  browser_pass.js \
 	                  browser_async.js \
 	                  browser_privileges.js \
 # Disabled, these are only good for testing the harness' failure reporting
 #	                  browser_zz_fail_openwindow.js \
 #	                  browser_fail.js \
 #	                  browser_fail_async_throw.js \
 #	                  browser_fail_fp.js \
 #	                  browser_fail_pf.js \
 #	                  browser_fail_throw.js \
 #	                  browser_fail_timeout.js \
+# Disabled because it would take too long, useful to check functionality though.
+#	                  browser_requestLongerTimeout.js \
 	                  $(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_head.js
@@ -0,0 +1,12 @@
+let testVar;
+
+registerCleanupFunction(function() {
+  ok(true, "I'm a cleanup function in test file");
+  is(this.testVar, "I'm a var in test file", "Test cleanup function scope is correct");
+});
+
+function test() {
+  is(headVar, "I'm a var in head file", "Head variables are set");
+  ok(headMethod(), "Head methods are imported");
+  testVar = "I'm a var in test file";
+}
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_requestLongerTimeout.js
@@ -0,0 +1,9 @@
+function test() {
+  requestLongerTimeout(2);
+  function end() {
+    ok(true, "should not time out");
+    finish();
+  }
+  waitForExplicitFinish();
+  setTimeout(end, 40000);
+}
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/tests/browser/head.js
@@ -0,0 +1,12 @@
+let headVar = "I'm a var in head file";
+
+function headMethod() {
+  return true;
+};
+
+ok(true, "I'm a test in head file");
+
+registerCleanupFunction(function() {
+  ok(true, "I'm a cleanup function in head file");
+  is(this.headVar, "I'm a var in head file", "Head cleanup function scope is correct");
+});
--- a/toolkit/components/downloads/src/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/src/nsDownloadManager.cpp
@@ -71,16 +71,20 @@
 
 #if defined(XP_WIN) && !defined(WINCE)
 #include <shlobj.h>
 #ifdef DOWNLOAD_SCANNER
 #include "nsDownloadScanner.h"
 #endif
 #endif
 
+#ifdef XP_MACOSX
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
 #define DOWNLOAD_MANAGER_BUNDLE "chrome://mozapps/locale/downloads/downloads.properties"
 #define DOWNLOAD_MANAGER_ALERT_ICON "chrome://mozapps/skin/downloads/downloadIcon.png"
 #define PREF_BDM_SHOWALERTONCOMPLETE "browser.download.manager.showAlertOnComplete"
 #define PREF_BDM_SHOWALERTINTERVAL "browser.download.manager.showAlertInterval"
 #define PREF_BDM_RETENTION "browser.download.manager.retention"
 #define PREF_BDM_QUITBEHAVIOR "browser.download.manager.quitBehavior"
 #define PREF_BDM_ADDTORECENTDOCS "browser.download.manager.addToRecentDocs"
 #define PREF_BDM_SCANWHENDONE "browser.download.manager.scanWhenDone"
@@ -2188,39 +2192,52 @@ nsDownload::SetState(DownloadState aStat
               // the items they downloaded will have been removed.
               alerts->ShowAlertNotification(
                   NS_LITERAL_STRING(DOWNLOAD_MANAGER_ALERT_ICON), title,
                   message, !removeWhenDone, EmptyString(), mDownloadManager,
                   EmptyString());
             }
         }
       }
-#if defined(XP_WIN) && !defined(WINCE)
+#if (defined(XP_WIN) && !defined(WINCE)) || defined(XP_MACOSX)
       nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mTarget);
       nsCOMPtr<nsIFile> file;
       nsAutoString path;
 
       if (fileURL &&
           NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(file))) &&
           file &&
           NS_SUCCEEDED(file->GetPath(path))) {
 
+#ifdef XP_WIN
         // On windows, add the download to the system's "recent documents"
         // list, with a pref to disable.
         {
           PRBool addToRecentDocs = PR_TRUE;
           if (pref)
             pref->GetBoolPref(PREF_BDM_ADDTORECENTDOCS, &addToRecentDocs);
 
           if (addToRecentDocs &&
               !nsDownloadManager::gDownloadManagerService->mInPrivateBrowsing)
             ::SHAddToRecentDocs(SHARD_PATHW, path.get());
         }
+#endif
+#ifdef XP_MACOSX
+        // On OS X, make the downloads stack bounce.
+        CFStringRef observedObject = ::CFStringCreateWithCString(kCFAllocatorDefault,
+                                             NS_ConvertUTF16toUTF8(path).get(),
+                                             kCFStringEncodingUTF8);
+        CFNotificationCenterRef center = ::CFNotificationCenterGetDistributedCenter();
+        ::CFNotificationCenterPostNotification(center, CFSTR("com.apple.DownloadFileFinished"),
+                                               observedObject, NULL, TRUE);
+        ::CFRelease(observedObject);
+#endif
       }
 
+#ifdef XP_WIN
       // Adjust file attributes so that by default, new files are indexed
       // by desktop search services. Skip off those that land in the temp
       // folder.
       nsCOMPtr<nsIFile> tempDir, fileDir;
       rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
       NS_ENSURE_SUCCESS(rv, rv);
       (void)file->GetParent(getter_AddRefs(fileDir));
 
@@ -2228,16 +2245,17 @@ nsDownload::SetState(DownloadState aStat
       if (fileDir)
         (void)fileDir->Equals(tempDir, &isTemp);
 
       nsCOMPtr<nsILocalFileWin> localFileWin(do_QueryInterface(file));
       if (!isTemp && localFileWin)
         (void)localFileWin->SetFileAttributesWin(nsILocalFileWin::WFA_SEARCH_INDEXED);
 
 #endif
+#endif
       // Now remove the download if the user's retention policy is "Remove when Done"
       if (mDownloadManager->GetRetentionBehavior() == 0)
         mDownloadManager->RemoveDownload(mID);
     }
     break;
   default:
     break;
   }
--- a/widget/src/cocoa/Makefile.in
+++ b/widget/src/cocoa/Makefile.in
@@ -61,16 +61,17 @@ EXPORTS = \
 CMMSRCS = \
 		nsBidiKeyboard.mm \
 		nsClipboard.mm \
 		nsMenuX.mm \
 		nsMenuBarX.mm \
 		nsMenuItemX.mm \
 		nsMenuItemIconX.mm \
 		nsMenuUtilsX.mm \
+		nsMenuGroupOwnerX.mm \
 		nsFilePicker.mm \
 		nsDragService.mm \
 		nsToolkit.mm \
 		nsAppShell.mm \
 		nsCocoaUtils.mm \
 		nsCocoaWindow.mm \
 		nsChildView.mm \
 		nsWindowMap.mm \
--- a/widget/src/cocoa/nsMenuBarX.h
+++ b/widget/src/cocoa/nsMenuBarX.h
@@ -37,20 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsMenuBarX_h_
 #define nsMenuBarX_h_
 
 #import <Cocoa/Cocoa.h>
 
 #include "nsMenuBaseX.h"
-#include "nsIMutationObserver.h"
-#include "nsHashtable.h"
-#include "nsHashKeys.h"
-#include "nsDataHashtable.h"
+#include "nsMenuGroupOwnerX.h"
 #include "nsINativeMenuService.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 
 class nsMenuX;
 class nsMenuItemX;
 class nsChangeObserver;
 class nsIWidget;
@@ -104,72 +101,56 @@ public:
 - (NSMenuItem *)addItemWithTitle:(NSString *)aString action:(SEL)aSelector keyEquivalent:(NSString *)keyEquiv;
 - (void)insertItem:(NSMenuItem *)newItem atIndex:(NSInteger)index;
 - (NSMenuItem *)insertItemWithTitle:(NSString *)aString action:(SEL)aSelector  keyEquivalent:(NSString *)keyEquiv atIndex:(NSInteger)index;
 - (void) _overrideClassOfMenuItem:(NSMenuItem *)menuItem;
 @end
 
 // Once instantiated, this object lives until its DOM node or its parent window is destroyed.
 // Do not hold references to this, they can become invalid any time the DOM node can be destroyed.
-class nsMenuBarX : public nsMenuObjectX,
-                   public nsIMutationObserver
+class nsMenuBarX : public nsMenuGroupOwnerX
 {
 public:
   nsMenuBarX();
   virtual ~nsMenuBarX();
 
   static NativeMenuItemTarget* sNativeEventTarget;
   static nsMenuBarX*           sLastGeckoMenuBarPainted;
 
   // The following content nodes have been removed from the menu system.
   // We save them here for use in command handling.
   nsCOMPtr<nsIContent> mAboutItemContent;
   nsCOMPtr<nsIContent> mPrefItemContent;
   nsCOMPtr<nsIContent> mQuitItemContent;
 
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIMUTATIONOBSERVER
-
   // nsMenuObjectX
   void*             NativeData()     {return (void*)mNativeMenu;}
   nsMenuObjectTypeX MenuObjectType() {return eMenuBarObjectType;}
 
   // nsMenuBarX
   nsresult          Create(nsIWidget* aParent, nsIContent* aContent);
   void              SetParent(nsIWidget* aParent);
-  void              RegisterForContentChanges(nsIContent* aContent, nsChangeObserver* aMenuObject);
-  void              UnregisterForContentChanges(nsIContent* aContent);
-  PRUint32          RegisterForCommand(nsMenuItemX* aItem);
-  void              UnregisterCommand(PRUint32 aCommandID);
   PRUint32          GetMenuCount();
   bool              MenuContainsAppMenu();
   nsMenuX*          GetMenuAt(PRUint32 aIndex);
-  nsMenuItemX*      GetMenuItemForCommandID(PRUint32 inCommandID);
+  nsMenuX*          GetXULHelpMenu();
+  void              SetSystemHelpMenu();
   nsresult          Paint();
   void              ForceUpdateNativeMenuAt(const nsAString& indexString);
   void              ForceNativeMenuReload(); // used for testing
   static char       GetLocalizedAccelKey(const char *shortcutID);
 
 protected:
   void              ConstructNativeMenus();
   nsresult          InsertMenuAtIndex(nsMenuX* aMenu, PRUint32 aIndex);
   void              RemoveMenuAtIndex(PRUint32 aIndex);
-  nsChangeObserver* LookupContentChangeObserver(nsIContent* aContent);
   void              HideItem(nsIDOMDocument* inDoc, const nsAString & inID, nsIContent** outHiddenNode);
   void              AquifyMenuBar();
   NSMenuItem*       CreateNativeAppMenuItem(nsMenuX* inMenu, const nsAString& nodeID, SEL action,
                                             int tag, NativeMenuItemTarget* target);
   nsresult          CreateApplicationMenu(nsMenuX* inMenu);
 
   nsTArray< nsAutoPtr<nsMenuX> > mMenuArray;
   nsIWidget*         mParentWindow;        // [weak]
-  PRUint32           mCurrentCommandID;    // unique command id (per menu-bar) to give to next item that asks
-  nsIDocument*       mDocument;            // pointer to document
   GeckoNSMenu*       mNativeMenu;            // root menu, representing entire menu bar
-
-  // stores observers for content change notification
-  nsDataHashtable<nsPtrHashKey<nsIContent>, nsChangeObserver *> mContentToObserverTable;
-
-  // stores mapping of command IDs to menu objects
-  nsDataHashtable<nsUint32HashKey, nsMenuItemX *> mCommandToMenuObjectTable;
 };
 
 #endif // nsMenuBarX_h_
--- a/widget/src/cocoa/nsMenuBarX.mm
+++ b/widget/src/cocoa/nsMenuBarX.mm
@@ -16,16 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Josh Aas <josh@mozilla.com>
+ *   Thomas K. Dyas <tom.dyas@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
@@ -39,78 +40,63 @@
 #include <objc/objc-runtime.h>
 
 #include "nsMenuBarX.h"
 #include "nsMenuX.h"
 #include "nsMenuItemX.h"
 #include "nsMenuUtilsX.h"
 #include "nsCocoaUtils.h"
 #include "nsCocoaWindow.h"
+#include "nsToolkit.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsWidgetAtoms.h"
 #include "nsGUIEvent.h"
 #include "nsObjCExceptions.h"
 #include "nsHashtable.h"
 #include "nsThreadUtils.h"
 
 #include "nsIContent.h"
 #include "nsIWidget.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 
-NS_IMPL_ISUPPORTS1(nsMenuBarX, nsIMutationObserver)
-
 NativeMenuItemTarget* nsMenuBarX::sNativeEventTarget = nil;
 nsMenuBarX* nsMenuBarX::sLastGeckoMenuBarPainted = nsnull;
 NSMenu* sApplicationMenu = nil;
 BOOL gSomeMenuBarPainted = NO;
 
 // We keep references to the first quit and pref item content nodes we find, which
 // will be from the hidden window. We use these when the document for the current
 // window does not have a quit or pref item. We don't need strong refs here because
 // these items are always strong ref'd by their owning menu bar (instance variable).
 static nsIContent* sAboutItemContent = nsnull;
 static nsIContent* sPrefItemContent  = nsnull;
 static nsIContent* sQuitItemContent  = nsnull;
 
-// Special command IDs that we know Mac OS X does not use for anything else. We use
-// these in place of carbon's IDs for these commands in order to stop Carbon from
-// messing with our event handlers. See bug 346883.
-enum {
-  eCommand_ID_About = 1,
-  eCommand_ID_Prefs = 2,
-  eCommand_ID_Quit  = 3,
-  eCommand_ID_Last  = 4
-};
-
 NS_IMPL_ISUPPORTS1(nsNativeMenuServiceX, nsINativeMenuService)
 
 NS_IMETHODIMP nsNativeMenuServiceX::CreateNativeMenuBar(nsIWidget* aParent, nsIContent* aMenuBarNode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Attempting to create native menu bar on wrong thread!");
 
   nsRefPtr<nsMenuBarX> mb = new nsMenuBarX();
   if (!mb)
     return NS_ERROR_OUT_OF_MEMORY;
 
   return mb->Create(aParent, aMenuBarNode);
 }
 
 nsMenuBarX::nsMenuBarX()
-: mParentWindow(nsnull),
-  mCurrentCommandID(eCommand_ID_Last),
-  mDocument(nsnull)
+: nsMenuGroupOwnerX(), mParentWindow(nsnull)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
-  mContentToObserverTable.Init();
-  mCommandToMenuObjectTable.Init();
   mNativeMenu = [[GeckoNSMenu alloc] initWithTitle:@"MainMenuBar"];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 nsMenuBarX::~nsMenuBarX()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@@ -147,21 +133,19 @@ nsresult nsMenuBarX::Create(nsIWidget* a
   if (!aParent || !aContent)
     return NS_ERROR_INVALID_ARG;
 
   mParentWindow = aParent;
   mContent = aContent;
 
   AquifyMenuBar();
 
-  nsIDocument* doc = aContent->GetOwnerDoc();
-  if (!doc)
-    return NS_ERROR_FAILURE;
-  doc->AddMutationObserver(this);
-  mDocument = doc;
+  nsresult rv = nsMenuGroupOwnerX::Create(aContent);
+  if (NS_FAILED(rv))
+    return rv;
 
   ConstructNativeMenus();
 
   // Give this to the parent window. The parent takes ownership.
   static_cast<nsCocoaWindow*>(mParentWindow)->SetMenuBar(this);
 
   return NS_OK;
 }
@@ -326,16 +310,44 @@ nsMenuX* nsMenuBarX::GetMenuAt(PRUint32 
 {
   if (mMenuArray.Length() <= aIndex) {
     NS_ERROR("Requesting menu at invalid index!");
     return NULL;
   }
   return mMenuArray[aIndex];
 }
 
+nsMenuX* nsMenuBarX::GetXULHelpMenu()
+{
+  // The Help menu is usually (always?) the last one, so we start there and
+  // count back.
+  for (PRInt32 i = GetMenuCount() - 1; i >= 0; --i) {
+    nsMenuX* aMenu = GetMenuAt(i);
+    if (aMenu && nsMenuX::IsXULHelpMenu(aMenu->Content()))
+      return aMenu;
+  }
+  return nil;
+}
+
+// On SnowLeopard and later we must tell the OS which is our Help menu.
+// Otherwise it will only add Spotlight for Help (the Search item) to our
+// Help menu if its label/title is "Help" -- i.e. if the menu is in English.
+// This resolves bugs 489196 and 539317.
+void nsMenuBarX::SetSystemHelpMenu()
+{
+  if (!nsToolkit::OnSnowLeopardOrLater())
+    return;
+  nsMenuX* xulHelpMenu = GetXULHelpMenu();
+  if (xulHelpMenu) {
+    NSMenu* helpMenu = (NSMenu*)xulHelpMenu->NativeData();
+    if (helpMenu)
+      [NSApp setHelpMenu:helpMenu];
+  }
+}
+
 nsresult nsMenuBarX::Paint()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   // Don't try to optimize anything in this painting by checking
   // sLastGeckoMenuBarPainted because the menubar can be manipulated by
   // native dialogs and sheet code and other things besides this paint method.
 
@@ -346,16 +358,17 @@ nsresult nsMenuBarX::Paint()
 
   NSMenuItem* appMenuItem = [[outgoingMenu itemAtIndex:0] retain];
   [outgoingMenu removeItemAtIndex:0];
   [mNativeMenu insertItem:appMenuItem atIndex:0];
   [appMenuItem release];
 
   // Set menu bar and event target.
   [NSApp setMainMenu:mNativeMenu];
+  SetSystemHelpMenu();
   nsMenuBarX::sLastGeckoMenuBarPainted = this;
 
   gSomeMenuBarPainted = YES;
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
@@ -508,16 +521,20 @@ NSMenuItem* nsMenuBarX::CreateNativeAppM
     keyEquiv = @"";
 
   // put together the actual NSMenuItem
   NSMenuItem* newMenuItem = [[NSMenuItem alloc] initWithTitle:labelString action:action keyEquivalent:keyEquiv];
   
   [newMenuItem setTag:tag];
   [newMenuItem setTarget:target];
   [newMenuItem setKeyEquivalentModifierMask:macKeyModifiers];
+
+  MenuItemInfo * info = [[MenuItemInfo alloc] initWithMenuGroupOwner:this];
+  [newMenuItem setRepresentedObject:info];
+  [info release];
   
   return newMenuItem;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 // build the Application menu shared by all menu bars
 nsresult nsMenuBarX::CreateApplicationMenu(nsMenuX* inMenu)
@@ -672,179 +689,16 @@ nsresult nsMenuBarX::CreateApplicationMe
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 void nsMenuBarX::SetParent(nsIWidget* aParent)
 {
   mParentWindow = aParent;
 }
 
-//
-// nsIMutationObserver
-//
-
-void nsMenuBarX::CharacterDataWillChange(nsIDocument* aDocument,
-                                         nsIContent* aContent,
-                                         CharacterDataChangeInfo* aInfo)
-{
-}
-
-void nsMenuBarX::CharacterDataChanged(nsIDocument* aDocument,
-                                      nsIContent* aContent,
-                                      CharacterDataChangeInfo* aInfo)
-{
-}
-
-void nsMenuBarX::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
-                                 PRInt32 aNewIndexInContainer)
-{
-  PRUint32 childCount = aContainer->GetChildCount();
-  while ((PRUint32)aNewIndexInContainer < childCount) {
-    nsIContent *child = aContainer->GetChildAt(aNewIndexInContainer);
-    ContentInserted(aDocument, aContainer, child, aNewIndexInContainer);
-    aNewIndexInContainer++;
-  }
-}
-
-void nsMenuBarX::NodeWillBeDestroyed(const nsINode * aNode)
-{
-  // our menu bar node is being destroyed
-  mDocument = nsnull;
-}
-
-void nsMenuBarX::AttributeWillChange(nsIDocument* aDocument,
-                                     nsIContent* aContent, PRInt32 aNameSpaceID,
-                                     nsIAtom* aAttribute, PRInt32 aModType)
-{
-}
-
-void nsMenuBarX::AttributeChanged(nsIDocument * aDocument, nsIContent * aContent,
-                                  PRInt32 aNameSpaceID, nsIAtom * aAttribute,
-                                  PRInt32 aModType)
-{
-  nsChangeObserver* obs = LookupContentChangeObserver(aContent);
-  if (obs)
-    obs->ObserveAttributeChanged(aDocument, aContent, aAttribute);
-}
-
-void nsMenuBarX::ContentRemoved(nsIDocument * aDocument, nsIContent * aContainer,
-                                nsIContent * aChild, PRInt32 aIndexInContainer)
-{
-  if (aContainer == mContent) {
-    RemoveMenuAtIndex(aIndexInContainer);
-  }
-  else {
-    nsChangeObserver* obs = LookupContentChangeObserver(aContainer);
-    if (obs) {
-      obs->ObserveContentRemoved(aDocument, aChild, aIndexInContainer);
-    }
-    else {
-      // We do a lookup on the parent container in case things were removed
-      // under a "menupopup" item. That is basically a wrapper for the contents
-      // of a "menu" node.
-      nsCOMPtr<nsIContent> parent = aContainer->GetParent();
-      if (parent) {
-        obs = LookupContentChangeObserver(parent);
-        if (obs)
-          obs->ObserveContentRemoved(aDocument, aChild, aIndexInContainer);
-      }
-    }
-  }
-}
-
-void nsMenuBarX::ContentInserted(nsIDocument * aDocument, nsIContent * aContainer,
-                                 nsIContent * aChild, PRInt32 aIndexInContainer)
-{
-  if (aContainer == mContent) {
-    nsMenuX* newMenu = new nsMenuX();
-    if (newMenu) {
-      nsresult rv = newMenu->Create(this, this, aChild);
-      if (NS_SUCCEEDED(rv))
-        InsertMenuAtIndex(newMenu, aIndexInContainer);
-      else
-        delete newMenu;
-    }
-  }
-  else {
-    nsChangeObserver* obs = LookupContentChangeObserver(aContainer);
-    if (obs)
-      obs->ObserveContentInserted(aDocument, aChild, aIndexInContainer);
-    else {
-      // We do a lookup on the parent container in case things were removed
-      // under a "menupopup" item. That is basically a wrapper for the contents
-      // of a "menu" node.
-      nsCOMPtr<nsIContent> parent = aContainer->GetParent();
-      if (parent) {
-        obs = LookupContentChangeObserver(parent);
-        if (obs)
-          obs->ObserveContentInserted(aDocument, aChild, aIndexInContainer);
-      }
-    }
-  }
-}
-
-void nsMenuBarX::ParentChainChanged(nsIContent *aContent)
-{
-}
-
-// For change management, we don't use a |nsSupportsHashtable| because we know that the
-// lifetime of all these items is bounded by the lifetime of the menubar. No need to add
-// any more strong refs to the picture because the containment hierarchy already uses
-// strong refs.
-void nsMenuBarX::RegisterForContentChanges(nsIContent *aContent, nsChangeObserver *aMenuObject)
-{
-  mContentToObserverTable.Put(aContent, aMenuObject);
-}
-
-void nsMenuBarX::UnregisterForContentChanges(nsIContent *aContent)
-{
-  mContentToObserverTable.Remove(aContent);
-}
-
-nsChangeObserver* nsMenuBarX::LookupContentChangeObserver(nsIContent* aContent)
-{
-  nsChangeObserver * result;
-  if (mContentToObserverTable.Get(aContent, &result))
-    return result;
-  else
-    return nsnull;
-}
-
-// Given a menu item, creates a unique 4-character command ID and
-// maps it to the item. Returns the id for use by the client.
-PRUint32 nsMenuBarX::RegisterForCommand(nsMenuItemX* inMenuItem)
-{
-  // no real need to check for uniqueness. We always start afresh with each
-  // window at 1. Even if we did get close to the reserved Apple command id's,
-  // those don't start until at least '    ', which is integer 538976288. If
-  // we have that many menu items in one window, I think we have other problems.
-
-  // make id unique
-  ++mCurrentCommandID;
-
-  mCommandToMenuObjectTable.Put(mCurrentCommandID, inMenuItem);
-
-  return mCurrentCommandID;
-}
-
-// Removes the mapping between the given 4-character command ID
-// and its associated menu item.
-void nsMenuBarX::UnregisterCommand(PRUint32 inCommandID)
-{
-  mCommandToMenuObjectTable.Remove(inCommandID);
-}
-
-nsMenuItemX* nsMenuBarX::GetMenuItemForCommandID(PRUint32 inCommandID)
-{
-  nsMenuItemX * result;
-  if (mCommandToMenuObjectTable.Get(inCommandID, &result))
-    return result;
-  else
-    return nsnull;
-}
 
 //
 // Objective-C class used to allow us to have keyboard commands
 // look like they are doing something but actually do nothing.
 // We allow mouse actions to work normally.
 //
 
 // This tells us whether or not pKE is on the stack from a GeckoNSMenu. If it
@@ -902,20 +756,29 @@ static BOOL gActOnSpecialCommands = YES;
 @implementation NativeMenuItemTarget
 
 // called when some menu item in this menu gets hit
 -(IBAction)menuItemHit:(id)sender
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   int tag = [sender tag];
-  nsMenuBarX* menuBar = nsMenuBarX::sLastGeckoMenuBarPainted;
-  if (!menuBar)
+
+  MenuItemInfo* info = [sender representedObject];
+  if (!info)
     return;
 
+  nsMenuGroupOwnerX* menuGroupOwner = [info menuGroupOwner];
+  if (!menuGroupOwner)
+    return;
+
+  nsMenuBarX* menuBar = nsnull;
+  if (menuGroupOwner->MenuObjectType() == eMenuBarObjectType)
+    menuBar = static_cast<nsMenuBarX*>(menuGroupOwner);
+
   // We want to avoid processing app-global commands when we are asked to
   // perform native menu effects only. This avoids sending events twice,
   // which can lead to major problems.
   if (gActOnSpecialCommands) {
     // Do special processing if this is for an app-global command.
     if (tag == eCommand_ID_About) {
       nsIContent* mostSpecificContent = sAboutItemContent;
       if (menuBar && menuBar->mAboutItemContent)
@@ -941,32 +804,32 @@ static BOOL gActOnSpecialCommands = YES;
       else {
         [NSApp terminate:nil];
         return;
       }
     }
     // Quit now if the "active" menu bar has changed (as the result of
     // processing an app-global command above).  This resolves bmo bug
     // 430506.
-    if (menuBar != nsMenuBarX::sLastGeckoMenuBarPainted)
+    if (menuBar != nsnull && menuBar != nsMenuBarX::sLastGeckoMenuBarPainted)
       return;
   }
 
   // Don't do anything unless this is not a keyboard command and
   // this isn't for the hidden window menu. We assume that if there
   // is no main window then the hidden window menu bar is up, even
   // if that isn't true for some reason we better play it safe if
   // there is no main window.
   if (gPerformKeyEquivOnStack && !gActOnKeyEquiv && [NSApp mainWindow])
     return;
 
   // given the commandID, look it up in our hashtable and dispatch to
   // that menu item.
-  if (menuBar) {
-    nsMenuItemX* menuItem = menuBar->GetMenuItemForCommandID(static_cast<PRUint32>(tag));
+  if (menuGroupOwner) {
+    nsMenuItemX* menuItem = menuGroupOwner->GetMenuItemForCommandID(static_cast<PRUint32>(tag));
     if (menuItem)
       menuItem->DoCommand();
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 @end
--- a/widget/src/cocoa/nsMenuBaseX.h
+++ b/widget/src/cocoa/nsMenuBaseX.h
@@ -34,16 +34,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsMenuBaseX_h_
 #define nsMenuBaseX_h_
 
+#import <Foundation/Foundation.h>
+
 #include "nsCOMPtr.h"
 #include "nsIContent.h"
 
 enum nsMenuObjectTypeX {
   eMenuBarObjectType,
   eSubmenuObjectType,
   eMenuItemObjectType
 };
@@ -60,9 +62,39 @@ public:
   virtual nsMenuObjectTypeX MenuObjectType()=0;
   virtual void*             NativeData()=0;
   nsIContent*               Content() { return mContent; }
 
 protected:
   nsCOMPtr<nsIContent> mContent;
 };
 
+
+//
+// Object stored as "representedObject" for all menu items
+//
+
+class nsMenuGroupOwnerX;
+
+@interface MenuItemInfo : NSObject
+{
+  nsMenuGroupOwnerX * mMenuGroupOwner;
+}
+
+- (id) initWithMenuGroupOwner:(nsMenuGroupOwnerX *)aMenuGroupOwner;
+- (nsMenuGroupOwnerX *) menuGroupOwner;
+- (void) setMenuGroupOwner:(nsMenuGroupOwnerX *)aMenuGroupOwner;
+
+@end
+
+
+// Special command IDs that we know Mac OS X does not use for anything else.
+// We use these in place of carbon's IDs for these commands in order to stop
+// Carbon from messing with our event handlers. See bug 346883.
+
+enum {
+  eCommand_ID_About = 1,
+  eCommand_ID_Prefs = 2,
+  eCommand_ID_Quit  = 3,
+  eCommand_ID_Last  = 4
+};
+
 #endif // nsMenuBaseX_h_
new file mode 100644
--- /dev/null
+++ b/widget/src/cocoa/nsMenuGroupOwnerX.h
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Josh Aas <josh@mozilla.com>
+ *  Thomas K. Dyas <tom.dyas@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 nsMenuGroupOwnerX_h_
+#define nsMenuGroupOwnerX_h_
+
+#import <Cocoa/Cocoa.h>
+
+#include "nsMenuBaseX.h"
+#include "nsIMutationObserver.h"
+#include "nsHashtable.h"
+#include "nsHashKeys.h"
+#include "nsDataHashtable.h"
+#include "nsAutoPtr.h"
+#include "nsString.h"
+
+
+class nsMenuX;
+class nsMenuItemX;
+class nsChangeObserver;
+class nsIWidget;
+class nsIContent;
+class nsIDocument;
+
+class nsMenuGroupOwnerX : public nsMenuObjectX, public nsIMutationObserver
+{
+public:
+  nsMenuGroupOwnerX();
+  virtual ~nsMenuGroupOwnerX();
+
+  nsresult Create(nsIContent * aContent);
+
+  void RegisterForContentChanges(nsIContent* aContent,
+                                 nsChangeObserver* aMenuObject);
+  void UnregisterForContentChanges(nsIContent* aContent);
+  PRUint32 RegisterForCommand(nsMenuItemX* aItem);
+  void UnregisterCommand(PRUint32 aCommandID);
+  nsMenuItemX* GetMenuItemForCommandID(PRUint32 inCommandID);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMUTATIONOBSERVER
+
+  virtual nsresult InsertMenuAtIndex(nsMenuX* aMenu, PRUint32 aIndex);
+  virtual void RemoveMenuAtIndex(PRUint32 aIndex);
+
+protected:
+  nsChangeObserver* LookupContentChangeObserver(nsIContent* aContent);
+
+  PRUint32  mCurrentCommandID;  // unique command id (per menu-bar) to
+                                // give to next item that asks
+  nsIDocument* mDocument;       // pointer to document
+
+  // stores observers for content change notification
+  nsDataHashtable<nsPtrHashKey<nsIContent>, nsChangeObserver *> mContentToObserverTable;
+
+  // stores mapping of command IDs to menu objects
+  nsDataHashtable<nsUint32HashKey, nsMenuItemX *> mCommandToMenuObjectTable;
+};
+
+#endif // nsMenuBarX_h_
new file mode 100644
--- /dev/null
+++ b/widget/src/cocoa/nsMenuGroupOwnerX.mm
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Aas <josh@mozilla.com>
+ *   Thomas K. Dyas <tom.dyas@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 "nsMenuGroupOwnerX.h"
+#include "nsMenuBarX.h"
+#include "nsMenuX.h"
+#include "nsMenuItemX.h"
+#include "nsMenuUtilsX.h"
+#include "nsCocoaUtils.h"
+#include "nsCocoaWindow.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsWidgetAtoms.h"
+#include "nsGUIEvent.h"
+#include "nsObjCExceptions.h"
+#include "nsHashtable.h"
+#include "nsThreadUtils.h"
+
+#include "nsIContent.h"
+#include "nsIWidget.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMElement.h"
+
+#include "nsINode.h"
+
+NS_IMPL_ISUPPORTS1(nsMenuGroupOwnerX, nsIMutationObserver)
+
+
+nsMenuGroupOwnerX::nsMenuGroupOwnerX()
+: mCurrentCommandID(eCommand_ID_Last),
+  mDocument(nsnull)
+{
+  mContentToObserverTable.Init();
+  mCommandToMenuObjectTable.Init();
+}
+
+
+nsMenuGroupOwnerX::~nsMenuGroupOwnerX()
+{
+  // make sure we unregister ourselves as a document observer
+  if (mDocument)
+    mDocument->RemoveMutationObserver(this);
+}
+
+
+nsresult nsMenuGroupOwnerX::Create(nsIContent* aContent)
+{
+  if (!aContent)
+    return NS_ERROR_INVALID_ARG;
+
+  mContent = aContent;
+
+  nsIDocument* doc = aContent->GetOwnerDoc();
+  if (!doc)
+    return NS_ERROR_FAILURE;
+  doc->AddMutationObserver(this);
+  mDocument = doc;
+
+  return NS_OK;
+}
+
+
+//
+// nsIMutationObserver
+//
+
+
+void nsMenuGroupOwnerX::CharacterDataWillChange(nsIDocument* aDocument,
+                                                nsIContent* aContent,
+                                                CharacterDataChangeInfo* aInfo)
+{
+}
+
+
+void nsMenuGroupOwnerX::CharacterDataChanged(nsIDocument* aDocument,
+                                             nsIContent* aContent,
+                                             CharacterDataChangeInfo* aInfo)
+{
+}
+
+
+void nsMenuGroupOwnerX::ContentAppended(nsIDocument* aDocument,
+                                        nsIContent* aContainer,
+                                        PRInt32 aNewIndexInContainer)
+{
+  PRUint32 childCount = aContainer->GetChildCount();
+  while ((PRUint32)aNewIndexInContainer < childCount) {
+    nsIContent *child = aContainer->GetChildAt(aNewIndexInContainer);
+    ContentInserted(aDocument, aContainer, child, aNewIndexInContainer);
+    aNewIndexInContainer++;
+  }
+}
+
+
+void nsMenuGroupOwnerX::NodeWillBeDestroyed(const nsINode * aNode)
+{
+  // our menu bar node is being destroyed
+  mDocument = nsnull;
+}
+
+
+void nsMenuGroupOwnerX::AttributeWillChange(nsIDocument* aDocument,
+                                            nsIContent* aContent,
+                                            PRInt32 aNameSpaceID,
+                                            nsIAtom* aAttribute,
+                                            PRInt32 aModType)
+{
+}
+
+
+void nsMenuGroupOwnerX::AttributeChanged(nsIDocument * aDocument,
+                                         nsIContent * aContent,
+                                         PRInt32 aNameSpaceID,
+                                         nsIAtom * aAttribute,
+                                         PRInt32 aModType)
+{
+  nsChangeObserver* obs = LookupContentChangeObserver(aContent);
+  if (obs)
+    obs->ObserveAttributeChanged(aDocument, aContent, aAttribute);
+}
+
+
+void nsMenuGroupOwnerX::ContentRemoved(nsIDocument * aDocument,
+                                       nsIContent * aContainer,
+                                       nsIContent * aChild,
+                                       PRInt32 aIndexInContainer)
+{
+  if (aContainer == mContent) {
+    RemoveMenuAtIndex(aIndexInContainer);
+  }
+  else {
+    nsChangeObserver* obs = LookupContentChangeObserver(aContainer);
+    if (obs) {
+      obs->ObserveContentRemoved(aDocument, aChild, aIndexInContainer);
+    }
+    else {
+      // We do a lookup on the parent container in case things were removed
+      // under a "menupopup" item. That is basically a wrapper for the contents
+      // of a "menu" node.
+      nsCOMPtr<nsIContent> parent = aContainer->GetParent();
+      if (parent) {
+        obs = LookupContentChangeObserver(parent);
+        if (obs)
+          obs->ObserveContentRemoved(aDocument, aChild, aIndexInContainer);
+      }
+    }
+  }
+}
+
+
+void nsMenuGroupOwnerX::ContentInserted(nsIDocument * aDocument,
+                                        nsIContent * aContainer,
+                                        nsIContent * aChild,
+                                        PRInt32 aIndexInContainer)
+{
+  if (aContainer == mContent) {
+    nsMenuX* newMenu = new nsMenuX();
+    if (newMenu) {
+      nsresult rv = newMenu->Create(this, this, aChild);
+      if (NS_SUCCEEDED(rv))
+        InsertMenuAtIndex(newMenu, aIndexInContainer);
+      else
+        delete newMenu;
+    }
+  }
+  else {
+    nsChangeObserver* obs = LookupContentChangeObserver(aContainer);
+    if (obs)
+      obs->ObserveContentInserted(aDocument, aChild, aIndexInContainer);
+    else {
+      // We do a lookup on the parent container in case things were removed
+      // under a "menupopup" item. That is basically a wrapper for the contents
+      // of a "menu" node.
+      nsCOMPtr<nsIContent> parent = aContainer->GetParent();
+      if (parent) {
+        obs = LookupContentChangeObserver(parent);
+        if (obs)
+          obs->ObserveContentInserted(aDocument, aChild, aIndexInContainer);
+      }
+    }
+  }
+}
+
+
+void nsMenuGroupOwnerX::ParentChainChanged(nsIContent *aContent)
+{
+}
+
+
+// For change management, we don't use a |nsSupportsHashtable| because
+// we know that the lifetime of all these items is bounded by the
+// lifetime of the menubar. No need to add any more strong refs to the
+// picture because the containment hierarchy already uses strong refs.
+void nsMenuGroupOwnerX::RegisterForContentChanges(nsIContent *aContent,
+                                                  nsChangeObserver *aMenuObject)
+{
+  mContentToObserverTable.Put(aContent, aMenuObject);
+}
+
+
+void nsMenuGroupOwnerX::UnregisterForContentChanges(nsIContent *aContent)
+{
+  mContentToObserverTable.Remove(aContent);
+}
+
+
+nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(nsIContent* aContent)
+{
+  nsChangeObserver * result;
+  if (mContentToObserverTable.Get(aContent, &result))
+    return result;
+  else
+    return nsnull;
+}
+
+
+// Given a menu item, creates a unique 4-character command ID and
+// maps it to the item. Returns the id for use by the client.
+PRUint32 nsMenuGroupOwnerX::RegisterForCommand(nsMenuItemX* inMenuItem)
+{
+  // no real need to check for uniqueness. We always start afresh with each
+  // window at 1. Even if we did get close to the reserved Apple command id's,
+  // those don't start until at least '    ', which is integer 538976288. If
+  // we have that many menu items in one window, I think we have other
+  // problems.
+
+  // make id unique
+  ++mCurrentCommandID;
+
+  mCommandToMenuObjectTable.Put(mCurrentCommandID, inMenuItem);
+
+  return mCurrentCommandID;
+}
+
+
+// Removes the mapping between the given 4-character command ID
+// and its associated menu item.
+void nsMenuGroupOwnerX::UnregisterCommand(PRUint32 inCommandID)
+{
+  mCommandToMenuObjectTable.Remove(inCommandID);
+}
+
+
+nsMenuItemX* nsMenuGroupOwnerX::GetMenuItemForCommandID(PRUint32 inCommandID)
+{
+  nsMenuItemX * result;
+  if (mCommandToMenuObjectTable.Get(inCommandID, &result))
+    return result;
+  else
+    return nsnull;
+}
+
+nsresult nsMenuGroupOwnerX::InsertMenuAtIndex(nsMenuX* aMenu, PRUint32 aIndex)
+{
+  return NS_OK;
+}
+
+void nsMenuGroupOwnerX::RemoveMenuAtIndex(PRUint32 aIndex)
+{
+}
--- a/widget/src/cocoa/nsMenuItemX.h
+++ b/widget/src/cocoa/nsMenuItemX.h
@@ -35,25 +35,25 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsMenuItemX_h_
 #define nsMenuItemX_h_
 
 #include "nsMenuBaseX.h"
+#include "nsMenuGroupOwnerX.h"
 #include "nsChangeObserver.h"
 #include "nsAutoPtr.h"
 
 #import <Cocoa/Cocoa.h>
 
 class nsString;
 class nsMenuItemIconX;
 class nsMenuX;
-class nsMenuBarX;
 
 enum {
   knsMenuItemNoModifier      = 0,
   knsMenuItemShiftModifier   = (1 << 0),
   knsMenuItemAltModifier     = (1 << 1),
   knsMenuItemControlModifier = (1 << 2),
   knsMenuItemCommandModifier = (1 << 3)
 };
@@ -78,31 +78,31 @@ public:
   NS_DECL_CHANGEOBSERVER
 
   // nsMenuObjectX
   void*             NativeData()     {return (void*)mNativeMenuItem;}
   nsMenuObjectTypeX MenuObjectType() {return eMenuItemObjectType;}
 
   // nsMenuItemX
   nsresult      Create(nsMenuX* aParent, const nsString& aLabel, EMenuItemType aItemType,
-                       nsMenuBarX* aMenuBar, nsIContent* aNode);
+                       nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode);
   nsresult      SetChecked(PRBool aIsChecked);
   EMenuItemType GetMenuItemType();
   void          DoCommand();
   nsresult      DispatchDOMEvent(const nsString &eventName, PRBool* preventDefaultCalled);
   void          SetupIcon();
 
 protected:
   void UncheckRadioSiblings(nsIContent* inCheckedElement);
   void SetKeyEquiv(PRUint8 aModifiers, const nsString &aText);
 
   EMenuItemType             mType;
   // nsMenuItemX objects should always have a valid native menu item.
   NSMenuItem*               mNativeMenuItem;      // [strong]
   nsMenuX*                  mMenuParent;          // [weak]
-  nsMenuBarX*               mMenuBar;             // [weak]
+  nsMenuGroupOwnerX*        mMenuGroupOwner;      // [weak]
   nsCOMPtr<nsIContent>      mCommandContent;
   // The icon object should never outlive its creating nsMenuItemX object.
   nsRefPtr<nsMenuItemIconX> mIcon;
   PRBool                    mIsChecked;
 };
 
 #endif // nsMenuItemX_h_
--- a/widget/src/cocoa/nsMenuItemX.mm
+++ b/widget/src/cocoa/nsMenuItemX.mm
@@ -57,17 +57,17 @@
 #include "nsIDOMDocumentEvent.h"
 #include "nsIDOMElement.h"
 
 nsMenuItemX::nsMenuItemX()
 {
   mType           = eRegularMenuItemType;
   mNativeMenuItem = nil;
   mMenuParent     = nsnull;
-  mMenuBar        = nsnull;
+  mMenuGroupOwner = nsnull;
   mIsChecked      = PR_FALSE;
 
   MOZ_COUNT_CTOR(nsMenuItemX);
 }
 
 nsMenuItemX::~nsMenuItemX()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@@ -76,55 +76,55 @@ nsMenuItemX::~nsMenuItemX()
   if (mIcon)
     mIcon->Destroy();
 
   // autorelease the native menu item so that anything else happening to this
   // object happens before the native menu item actually dies
   [mNativeMenuItem autorelease];
 
   if (mContent)
-    mMenuBar->UnregisterForContentChanges(mContent);
+    mMenuGroupOwner->UnregisterForContentChanges(mContent);
   if (mCommandContent)
-    mMenuBar->UnregisterForContentChanges(mCommandContent);
+    mMenuGroupOwner->UnregisterForContentChanges(mCommandContent);
 
   MOZ_COUNT_DTOR(nsMenuItemX);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 nsresult nsMenuItemX::Create(nsMenuX* aParent, const nsString& aLabel, EMenuItemType aItemType,
-                             nsMenuBarX* aMenuBar, nsIContent* aNode)
+                             nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   mType = aItemType;
   mMenuParent = aParent;
   mContent = aNode;
 
-  mMenuBar = aMenuBar;
-  NS_ASSERTION(mMenuBar, "No menu bar given, must have one!");
+  mMenuGroupOwner = aMenuGroupOwner;
+  NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one!");
 
-  mMenuBar->RegisterForContentChanges(mContent, this);
+  mMenuGroupOwner->RegisterForContentChanges(mContent, this);
 
   nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mContent->GetCurrentDoc()));
 
   // if we have a command associated with this menu item, register for changes
   // to the command DOM node
   if (domDoc) {
     nsAutoString ourCommand;
     mContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::command, ourCommand);
 
     if (!ourCommand.IsEmpty()) {
       nsCOMPtr<nsIDOMElement> commandElement;
       domDoc->GetElementById(ourCommand, getter_AddRefs(commandElement));
 
       if (commandElement) {
         mCommandContent = do_QueryInterface(commandElement);
         // register to observe the command DOM element
-        mMenuBar->RegisterForContentChanges(mCommandContent, this);
+        mMenuGroupOwner->RegisterForContentChanges(mCommandContent, this);
       }
     }
   }
 
   // decide enabled state based on command content if it exists, otherwise do it based
   // on our own content
   PRBool isEnabled;
   if (mCommandContent)
@@ -370,17 +370,17 @@ nsMenuItemX::ObserveAttributeChanged(nsI
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 void nsMenuItemX::ObserveContentRemoved(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
 {
   if (aChild == mCommandContent) {
-    mMenuBar->UnregisterForContentChanges(mCommandContent);
+    mMenuGroupOwner->UnregisterForContentChanges(mCommandContent);
     mCommandContent = nsnull;
   }
 
   mMenuParent->SetRebuild(PR_TRUE);
 }
 
 void nsMenuItemX::ObserveContentInserted(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIndexInContainer)
 {
--- a/widget/src/cocoa/nsMenuX.h
+++ b/widget/src/cocoa/nsMenuX.h
@@ -41,16 +41,17 @@
 
 #import <Cocoa/Cocoa.h>
 #if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4)
 #import <Carbon/Carbon.h>
 #endif
 
 #include "nsMenuBaseX.h"
 #include "nsMenuBarX.h"
+#include "nsMenuGroupOwnerX.h"
 #include "nsCOMPtr.h"
 #include "nsChangeObserver.h"
 #include "nsAutoPtr.h"
 
 class nsMenuX;
 class nsMenuItemIconX;
 class nsMenuItemX;
 class nsIWidget;
@@ -83,17 +84,17 @@ public:
 
   NS_DECL_CHANGEOBSERVER
 
   // nsMenuObjectX
   void*             NativeData()     {return (void*)mNativeMenu;}
   nsMenuObjectTypeX MenuObjectType() {return eSubmenuObjectType;}
 
   // nsMenuX
-  nsresult       Create(nsMenuObjectX* aParent, nsMenuBarX* aMenuBar, nsIContent* aNode);
+  nsresult       Create(nsMenuObjectX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode);
   PRUint32       GetItemCount();
   nsMenuObjectX* GetItemAt(PRUint32 aPos);
   nsresult       GetVisibleItemCount(PRUint32 &aCount);
   nsMenuObjectX* GetVisibleItemAt(PRUint32 aPos);
   nsEventStatus  MenuOpened();
   void           MenuClosed();
   void           SetRebuild(PRBool aMenuEvent);
   NSMenuItem*    NativeMenuItem();
@@ -114,17 +115,17 @@ protected:
   void           LoadMenuItem(nsIContent* inMenuItemContent);  
   void           LoadSubMenu(nsIContent* inMenuContent);
   GeckoNSMenu*   CreateMenuWithGeckoString(nsString& menuTitle);
 
   nsTArray< nsAutoPtr<nsMenuObjectX> > mMenuObjectsArray;
   nsString                  mLabel;
   PRUint32                  mVisibleItemsCount; // cache
   nsMenuObjectX*            mParent; // [weak]
-  nsMenuBarX*               mMenuBar; // [weak]
+  nsMenuGroupOwnerX*        mMenuGroupOwner; // [weak]
   // The icon object should never outlive its creating nsMenuX object.
   nsRefPtr<nsMenuItemIconX> mIcon;
   GeckoNSMenu*              mNativeMenu; // [strong]
   MenuDelegate*             mMenuDelegate; // [strong]
   // nsMenuX objects should always have a valid native menu item.
   NSMenuItem*               mNativeMenuItem; // [strong]
   PRPackedBool              mIsEnabled;
   PRPackedBool              mDestroyHandlerCalled;
--- a/widget/src/cocoa/nsMenuX.mm
+++ b/widget/src/cocoa/nsMenuX.mm
@@ -76,18 +76,58 @@
 extern nsIRollupListener * gRollupListener;
 extern nsIWidget         * gRollupWidget;
 
 static PRBool gConstructingMenu = PR_FALSE;
 static PRBool gMenuMethodsSwizzled = PR_FALSE;
 
 PRInt32 nsMenuX::sIndexingMenuLevel = 0;
 
+
+//
+// Objective-C class used for representedObject
+//
+
+@implementation MenuItemInfo
+
+- (id) initWithMenuGroupOwner:(nsMenuGroupOwnerX *)aMenuGroupOwner
+{
+  if ((self = [super init]) != nil) {
+    mMenuGroupOwner = nsnull;
+    [self setMenuGroupOwner:aMenuGroupOwner];
+  }
+  return self;
+}
+
+- (void) dealloc
+{
+  [self setMenuGroupOwner:nsnull];
+  [super dealloc];
+}
+
+- (nsMenuGroupOwnerX *) menuGroupOwner
+{
+  return mMenuGroupOwner;
+}
+
+- (void) setMenuGroupOwner:(nsMenuGroupOwnerX *)aMenuGroupOwner
+{
+  // weak reference as the nsMenuGroupOwnerX owns all of its sub-objects
+  mMenuGroupOwner = aMenuGroupOwner;
+}
+
+@end
+
+
+//
+// nsMenuX
+//
+
 nsMenuX::nsMenuX()
-: mVisibleItemsCount(0), mParent(nsnull), mMenuBar(nsnull),
+: mVisibleItemsCount(0), mParent(nsnull), mMenuGroupOwner(nsnull),
   mNativeMenu(nil), mNativeMenuItem(nil), mIsEnabled(PR_TRUE),
   mDestroyHandlerCalled(PR_FALSE), mNeedsRebuild(PR_TRUE),
   mConstructed(PR_FALSE), mVisible(PR_TRUE), mXBLAttached(PR_FALSE)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (!gMenuMethodsSwizzled) {
     if (nsToolkit::OnLeopardOrLater()) {
@@ -135,35 +175,35 @@ nsMenuX::~nsMenuX()
   [mNativeMenu release];
   [mMenuDelegate release];
   // autorelease the native menu item so that anything else happening to this
   // object happens before the native menu item actually dies
   [mNativeMenuItem autorelease];
 
   // alert the change notifier we don't care no more
   if (mContent)
-    mMenuBar->UnregisterForContentChanges(mContent);
+    mMenuGroupOwner->UnregisterForContentChanges(mContent);
 
   MOZ_COUNT_DTOR(nsMenuX);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
-nsresult nsMenuX::Create(nsMenuObjectX* aParent, nsMenuBarX* aMenuBar, nsIContent* aNode)
+nsresult nsMenuX::Create(nsMenuObjectX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   mContent = aNode;
   mContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::label, mLabel);
   mNativeMenu = CreateMenuWithGeckoString(mLabel);
 
   // register this menu to be notified when changes are made to our content object
-  mMenuBar = aMenuBar; // weak ref
-  NS_ASSERTION(mMenuBar, "No menu bar given, must have one");
-  mMenuBar->RegisterForContentChanges(mContent, this);
+  mMenuGroupOwner = aMenuGroupOwner; // weak ref
+  NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one");
+  mMenuGroupOwner->RegisterForContentChanges(mContent, this);
 
   mParent = aParent;
   // our parent could be either a menu bar (if we're toplevel) or a menu (if we're a submenu)
   nsMenuObjectTypeX parentType = mParent->MenuObjectType();
   NS_ASSERTION((parentType == eMenuBarObjectType || parentType == eSubmenuObjectType),
                "Menu parent not a menu bar or menu!");
 
   if (nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent))
@@ -208,17 +248,20 @@ nsresult nsMenuX::AddMenuItem(nsMenuItem
   // add the menu item to this menu
   [mNativeMenu addItem:newNativeMenuItem];
 
   // set up target/action
   [newNativeMenuItem setTarget:nsMenuBarX::sNativeEventTarget];
   [newNativeMenuItem setAction:@selector(menuItemHit:)];
 
   // set its command. we get the unique command id from the menubar
-  [newNativeMenuItem setTag:mMenuBar->RegisterForCommand(aMenuItem)];
+  [newNativeMenuItem setTag:mMenuGroupOwner->RegisterForCommand(aMenuItem)];
+  MenuItemInfo * info = [[MenuItemInfo alloc] initWithMenuGroupOwner:mMenuGroupOwner];
+  [newNativeMenuItem setRepresentedObject:info];
+  [info release];
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 nsresult nsMenuX::AddMenu(nsMenuX* aMenu)
 {
@@ -301,17 +344,17 @@ nsMenuObjectX* nsMenuX::GetVisibleItemAt
 nsresult nsMenuX::RemoveAll()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   if (mNativeMenu) {
     // clear command id's
     int itemCount = [mNativeMenu numberOfItems];
     for (int i = 0; i < itemCount; i++)
-      mMenuBar->UnregisterCommand((PRUint32)[[mNativeMenu itemAtIndex:i] tag]);
+      mMenuGroupOwner->UnregisterCommand((PRUint32)[[mNativeMenu itemAtIndex:i] tag]);
     // get rid of Cocoa menu items
     for (int i = [mNativeMenu numberOfItems] - 1; i >= 0; i--)
       [mNativeMenu removeItemAtIndex:i];
   }
 
   mMenuObjectsArray.Clear();
   mVisibleItemsCount = 0;
 
@@ -467,23 +510,16 @@ GeckoNSMenu* nsMenuX::CreateMenuWithGeck
   NSString* title = [NSString stringWithCharacters:(UniChar*)menuTitle.get() length:menuTitle.Length()];
   GeckoNSMenu* myMenu = [[GeckoNSMenu alloc] initWithTitle:title];
   [myMenu setDelegate:mMenuDelegate];
 
   // We don't want this menu to auto-enable menu items because then Cocoa
   // overrides our decisions and things get incorrectly enabled/disabled.
   [myMenu setAutoenablesItems:NO];
 
-  // On SnowLeopard and later we must tell the OS which is our Help menu.
-  // Otherwise it will only add Spotlight for Help (the Search item) to our
-  // Help menu if its label/title is "Help" -- i.e. if the menu is in English.
-  // This resolves bug 489196.
-  if (nsToolkit::OnSnowLeopardOrLater() && nsMenuX::IsXULHelpMenu(mContent))
-    [NSApp setHelpMenu:myMenu];
-
   // we used to install Carbon event handlers here, but since NSMenu* doesn't
   // create its underlying MenuRef until just before display, we delay until
   // that happens. Now we install the event handlers when Cocoa notifies
   // us that a menu is about to display - see the Cocoa MenuDelegate class.
 
   return myMenu;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
@@ -513,17 +549,17 @@ void nsMenuX::LoadMenuItem(nsIContent* i
     }
   }
 
   // Create the item.
   nsMenuItemX* menuItem = new nsMenuItemX();
   if (!menuItem)
     return;
 
-  nsresult rv = menuItem->Create(this, menuitemName, itemType, mMenuBar, inMenuItemContent);
+  nsresult rv = menuItem->Create(this, menuitemName, itemType, mMenuGroupOwner, inMenuItemContent);
   if (NS_FAILED(rv)) {
     delete menuItem;
     return;
   }
 
   AddMenuItem(menuItem);
 
   // This needs to happen after the nsIMenuItem object is inserted into
@@ -532,17 +568,17 @@ void nsMenuX::LoadMenuItem(nsIContent* i
 }
 
 void nsMenuX::LoadSubMenu(nsIContent* inMenuContent)
 {
   nsAutoPtr<nsMenuX> menu(new nsMenuX());
   if (!menu)
     return;
 
-  nsresult rv = menu->Create(this, mMenuBar, inMenuContent);
+  nsresult rv = menu->Create(this, mMenuGroupOwner, inMenuContent);
   if (NS_FAILED(rv))
     return;
 
   AddMenu(menu);
 
   // This needs to happen after the nsIMenu object is inserted into
   // our item array in AddMenu()
   menu->SetupIcon();
@@ -784,17 +820,17 @@ void nsMenuX::ObserveAttributeChanged(ns
 
 void nsMenuX::ObserveContentRemoved(nsIDocument *aDocument, nsIContent *aChild,
                                     PRInt32 aIndexInContainer)
 {
   if (gConstructingMenu)
     return;
 
   SetRebuild(PR_TRUE);
-  mMenuBar->UnregisterForContentChanges(aChild);
+  mMenuGroupOwner->UnregisterForContentChanges(aChild);
 }
 
 void nsMenuX::ObserveContentInserted(nsIDocument *aDocument, nsIContent *aChild,
                                      PRInt32 aIndexInContainer)
 {
   if (gConstructingMenu)
     return;
 
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -101,16 +101,18 @@
  **
  ** Include headers.
  **
  **************************************************************
  **************************************************************/
 
 #ifdef MOZ_IPC
 #include "mozilla/ipc/SyncChannel.h"
+#include "mozilla/plugins/PluginInstanceParent.h"
+using mozilla::plugins::PluginInstanceParent;
 #endif
 
 #include "nsWindow.h"
 
 #include <windows.h>
 #include <process.h>
 #include <commctrl.h>
 #include <unknwn.h>
@@ -204,20 +206,16 @@
 #include "npapi.h"
 
 #include "nsWindowDefs.h"
 
 #ifdef WINCE_WINDOWS_MOBILE
 #include "nsGfxCIID.h"
 #endif
 
-// A magic APP message that can be sent to quit, sort of like a QUERYENDSESSION/ENDSESSION,
-// but without the query.
-#define MOZ_WM_APP_QUIT (WM_APP+0x0300)
-
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: Variables
  **
  ** nsWindow Class static initializations and global variables. 
  **
  **************************************************************
@@ -277,16 +275,23 @@ PRBool          nsWindow::sTrackPointHac
 #ifdef ACCESSIBILITY
 BOOL            nsWindow::sIsAccessibilityOn      = FALSE;
 // Accessibility wm_getobject handler
 HINSTANCE       nsWindow::sAccLib                 = 0;
 LPFNLRESULTFROMOBJECT 
                 nsWindow::sLresultFromObject      = 0;
 #endif // ACCESSIBILITY
 
+#ifdef MOZ_IPC
+// Used in OOPP plugin focus processing.
+const PRUnichar* kOOPPPluginFocusEventId   = L"OOPP Plugin Focus Widget Event";
+PRUint32        nsWindow::sOOPPPluginFocusEvent   =
+                  RegisterWindowMessageW(kOOPPPluginFocusEventId);
+#endif
+
 /**************************************************************
  *
  * SECTION: globals variables
  *
  **************************************************************/
 
 static const char *sScreenManagerContractID       = "@mozilla.org/gfx/screenmanager;1";
 
@@ -325,17 +330,16 @@ PRUint32        gLastInputEventTime     
 static void UpdateLastInputEventTime() {
   gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
   nsCOMPtr<nsIIdleService> idleService = do_GetService("@mozilla.org/widget/idleservice;1");
   nsIdleService* is = static_cast<nsIdleService*>(idleService.get());
   if (is)
     is->IdleTimeWasModified();
 }
 
-
 // Global user preference for disabling native theme. Used
 // in NativeWindowTheme.
 PRBool          gDisableNativeTheme               = PR_FALSE;
 
 // Global used in Show window enumerations.
 static PRBool   gWindowsVisible                   = PR_FALSE;
 
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
@@ -2100,17 +2104,17 @@ NS_METHOD nsWindow::Invalidate(PRBool aI
     // We need to keep track of our own invalidated region for Windows CE
     RECT r;
     GetClientRect(mWnd, &r);
     AddRECTToRegion(r, mInvalidatedRegion);
 #endif
     VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
 
     if (aIsSynchronous) {
-      VERIFY(::UpdateWindow(mWnd));
+      UpdateWindowInternal(mWnd);
     }
   }
   return NS_OK;
 }
 
 // Invalidate this component visible area
 NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, PRBool aIsSynchronous)
 {
@@ -2134,30 +2138,30 @@ NS_METHOD nsWindow::Invalidate(const nsI
 
 #ifdef WINCE_WINDOWS_MOBILE
     // We need to keep track of our own invalidated region for Windows CE
     AddRECTToRegion(rect, mInvalidatedRegion);
 #endif
     VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
 
     if (aIsSynchronous) {
-      VERIFY(::UpdateWindow(mWnd));
+      UpdateWindowInternal(mWnd);
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::MakeFullScreen(PRBool aFullScreen)
 {
 #if WINCE_WINDOWS_MOBILE
   RECT rc;
   if (aFullScreen) {
     SetForegroundWindow(mWnd);
-    SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
+    SHFullScreen(mWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
     SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
   }
   else {
     SHFullScreen(mWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
     SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
   }
   MoveWindow(mWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE);
 
@@ -2178,17 +2182,17 @@ nsWindow::MakeFullScreen(PRBool aFullScr
 
 NS_IMETHODIMP nsWindow::Update()
 {
   nsresult rv = NS_OK;
 
   // updates can come through for windows no longer holding an mWnd during
   // deletes triggered by JavaScript in buttons with mouse feedback
   if (mWnd)
-    VERIFY(::UpdateWindow(mWnd));
+    UpdateWindowInternal(mWnd);
 
   return rv;
 }
 
 /**************************************************************
  *
  * SECTION: nsIWidget::Scroll
  *
@@ -3139,17 +3143,22 @@ PRBool nsWindow::DispatchCommandEvent(PR
 BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg)
 {
   LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC);
   if (proc == (LONG_PTR)&nsWindow::WindowProc) {
     // its one of our windows so check to see if it has a
     // invalidated rect. If it does. Dispatch a synchronous
     // paint.
     if (GetUpdateRect(aWnd, NULL, FALSE)) {
-      VERIFY(::UpdateWindow(aWnd));
+      nsWindow* win = GetNSWindowPtr(aWnd);
+      if (win)
+        win->UpdateWindowInternal(aWnd);
+      else
+        // Bad, this could hang a plugin process. Is this possible?
+        VERIFY(::UpdateWindow(aWnd));
     }
   }
   return TRUE;
 }
 
 // Check for pending paints and dispatch any pending paint
 // messages for any nsIWidget which is a descendant of the
 // top-level window that *this* window is embedded within.
@@ -4205,17 +4214,17 @@ PRBool nsWindow::ProcessMessage(UINT msg
     // events once the focus events arrive.
     case WM_ACTIVATE:
       if (mEventCallback) {
         PRInt32 fActive = LOWORD(wParam);
 
 #if defined(WINCE_HAVE_SOFTKB)
         if (mIsTopWidgetWindow && sSoftKeyboardState)
           nsWindowCE::ToggleSoftKB(mWnd, fActive);
-        if (nsWindowCE::sShowSIPButton != TRI_TRUE && WA_INACTIVE != fActive) {
+        if (nsWindowCE::sShowSIPButton == TRI_FALSE && WA_INACTIVE != fActive) {
           HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL ); 
           if (hWndSIPB)
             ShowWindow(hWndSIPB, SW_HIDE);
         }
 
 #endif
 
         if (WA_INACTIVE == fActive) {
@@ -4343,20 +4352,19 @@ PRBool nsWindow::ProcessMessage(UINT msg
     }
     break;
 
     case WM_SETTINGCHANGE:
 #if !defined (WINCE_WINDOWS_MOBILE)
       getWheelInfo = PR_TRUE;
 #else
       switch (wParam) {
-        case SPI_SIPMOVE:
         case SPI_SETSIPINFO:
         case SPI_SETCURRENTIM:
-          nsWindowCE::NotifySoftKbObservers(mWnd);
+          nsWindowCE::OnSoftKbSettingsChange(mWnd);
           break;
         case SETTINGCHANGE_RESET:
           if (mWindowType == eWindowType_invisible) {
             // The OS sees to get confused and think that the invisable window
             // is in the foreground after an orientation change. By actually
             // setting it to the foreground and hiding it, we set it strait.
             // See bug 514007 for details.
             SetForegroundWindow(mWnd);
@@ -4602,16 +4610,25 @@ PRBool nsWindow::ProcessMessage(UINT msg
         HeapDump(msg, wParam, lParam);
         result = PR_TRUE;
       }
 #endif
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
       if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
         SetHasTaskbarIconBeenCreated();
 #endif
+#ifdef MOZ_IPC
+    if (msg == sOOPPPluginFocusEvent) {
+      // With OOPP, the plugin window exists in another process and is a child of
+      // this window. This window is a placeholder plugin window for the dom. We
+      // receive this event when the child window receives focus. (sent from
+      // PluginInstanceParent.cpp)
+      ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp
+    } 
+#endif
     }
     break;
   }
 
   //*aRetValue = result;
   if (mWnd) {
     return result;
   }
@@ -5953,16 +5970,21 @@ void nsWindow::OnDestroy()
     SetCursor(eCursor_standard);
 
 #ifdef MOZ_XUL
   // Reset transparency
   if (eTransparencyTransparent == mTransparencyMode)
     SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque);
 #endif
 
+#if defined(WINCE_HAVE_SOFTKB)
+  // Revert the changes made for the software keyboard settings
+  nsWindowCE::ResetSoftKB(mWnd);
+#endif
+
   // Clear the main HWND.
   mWnd = NULL;
 }
 
 // OnMove
 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
 {
   mBounds.x = aX;
@@ -7090,16 +7112,40 @@ LPARAM nsWindow::lParamToClient(LPARAM l
 {
   POINT pt;
   pt.x = GET_X_LPARAM(lParam);
   pt.y = GET_Y_LPARAM(lParam);
   ::ScreenToClient(mWnd, &pt);
   return MAKELPARAM(pt.x, pt.y);
 }
 
+// If this window hosts a plugin window from another process then we cannot use
+// the windows UpdateWindow function to update it. Doing so sends a synchronous
+// WM_PAINT message to the plugin process which may call back to this process
+// in response. As this process is waiting for the UpdateWindow call to return
+// we deadlock. To work around this we issue an IPC call to the plugin process
+// to force the redraw since the IPC call handles reentrancy properly.
+void nsWindow::UpdateWindowInternal(HWND aWnd)
+{
+  if (aWnd) {
+#ifdef MOZ_IPC
+    if (mWindowType == eWindowType_plugin) {
+      PluginInstanceParent* instance = reinterpret_cast<PluginInstanceParent*>(
+        ::GetPropW(aWnd, L"PluginInstanceParentProperty"));
+      if (instance) {
+        if (!instance->CallUpdateWindow())
+          NS_ERROR("Failed to send message!");
+        return;
+      }
+    }
+#endif
+    VERIFY(::UpdateWindow(aWnd));
+  }
+}
+
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: ChildWindow impl.
  **
  ** Child window overrides.
  **
  **************************************************************
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -398,16 +398,18 @@ protected:
                                            PAINTSTRUCT ps, HDC aDC);
 #if !defined(WINCE)
   static void             ActivateOtherWindowHelper(HWND aWnd);
 #endif
 #ifdef ACCESSIBILITY
   static STDMETHODIMP_(LRESULT) LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc);
 #endif // ACCESSIBILITY
 
+  void                    UpdateWindowInternal(HWND aWnd);
+
 protected:
   nsIntSize             mLastSize;
   nsIntPoint            mLastPoint;
   HWND                  mWnd;
   WNDPROC               mPrevWndProc;
   HBRUSH                mBrush;
   PRPackedBool          mIsTopWidgetWindow;
   PRPackedBool          mHas3DBorder;
@@ -441,16 +443,19 @@ protected:
   static BOOL           sIsOleInitialized;
   static HCURSOR        sHCursor;
   static imgIContainer* sCursorImgContainer;
   static PRBool         sSwitchKeyboardLayout;
   static PRBool         sJustGotDeactivate;
   static PRBool         sJustGotActivate;
   static int            sTrimOnMinimize;
   static PRBool         sTrackPointHack;
+#ifdef MOZ_IPC
+  static PRUint32       sOOPPPluginFocusEvent;
+#endif
 
   // Hook Data Memebers for Dropdowns. sProcessHook Tells the
   // hook methods whether they should be processing the hook
   // messages.
   static HHOOK          sMsgFilterHook;
   static HHOOK          sCallProcHook;
   static HHOOK          sCallMouseHook;
   static PRPackedBool   sProcessHook;
@@ -492,17 +497,16 @@ protected:
   // Weak ref to the nsITaskbarWindowPreview associated with this window
   nsWeakPtr             mTaskbarPreview;
   // True if the taskbar (possibly through the tab preview) tells us that the
   // icon has been created on the taskbar.
   PRBool                mHasTaskbarIconBeenCreated;
 #endif
 
 #if defined(WINCE_HAVE_SOFTKB)
-  static PRBool         sSoftKeyMenuBar;
   static PRBool         sSoftKeyboardState;
 #endif // defined(WINCE_HAVE_SOFTKB)
 
 #ifdef ACCESSIBILITY
   static BOOL           sIsAccessibilityOn;
   static HINSTANCE      sAccLib;
   static LPFNLRESULTFROMOBJECT sLresultFromObject;
 #endif // ACCESSIBILITY
--- a/widget/src/windows/nsWindowCE.cpp
+++ b/widget/src/windows/nsWindowCE.cpp
@@ -57,56 +57,59 @@
 
 /**************************************************************
  *
  * SECTION: nsWindow statics
  *
  **************************************************************/
 
 #if defined(WINCE_HAVE_SOFTKB)
-PRBool          nsWindow::sSoftKeyMenuBar         = PR_FALSE;
 PRBool          nsWindow::sSoftKeyboardState      = PR_FALSE;
 PRBool          nsWindowCE::sSIPInTransition      = PR_FALSE;
 TriStateBool    nsWindowCE::sShowSIPButton        = TRI_UNKNOWN;
 TriStateBool    nsWindowCE::sHardKBPresence       = TRI_UNKNOWN;
+HWND            nsWindowCE::sSoftKeyMenuBarHandle = NULL;
+RECT            nsWindowCE::sDefaultSIPRect       = {0, 0, 0, 0};
+HWND            nsWindowCE::sMainWindowHandle     = NULL;
 #endif
 
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: nsWindowCE helpers
  **
  ** Called by nsWindow for wince specific work.
  **
  **************************************************************
  **************************************************************/
 
 #ifdef WINCE_HAVE_SOFTKB
-void nsWindowCE::NotifySoftKbObservers(HWND wnd, LPRECT visRect)
+void nsWindowCE::OnSoftKbSettingsChange(HWND wnd, LPRECT visRect)
 {
   if (!visRect) {
     SIPINFO sipInfo;
     memset(&sipInfo, 0, sizeof(SIPINFO));
     sipInfo.cbSize = sizeof(SIPINFO);
     if (SipGetInfo(&sipInfo)) 
       visRect = &(sipInfo.rcVisibleDesktop);
     else
       return;
   }
 
   if (wnd) {
     HWND wndMain = nsWindow::GetTopLevelHWND(wnd);
     RECT winRect;
     ::GetWindowRect(wndMain, &winRect);
     if (winRect.bottom != visRect->bottom) {
-      if (winRect.bottom < visRect->bottom && sShowSIPButton != TRI_TRUE) {
+      if (winRect.bottom < visRect->bottom) {
         // Soft keyboard has been hidden, have to hide the SIP button as well
-        HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL ); 
-        if (hWndSIPB)
-          ShowWindow(hWndSIPB, SW_HIDE);
+        if (sSoftKeyMenuBarHandle)
+          ShowWindow(sSoftKeyMenuBarHandle, SW_HIDE);
+
+        SHFullScreen(wndMain, SHFS_HIDESIPBUTTON);
       }
 
       winRect.bottom = visRect->bottom;
       MoveWindow(wndMain, winRect.left, winRect.top, winRect.right - winRect.left, winRect.bottom - winRect.top, TRUE);
     }
   }
   
   nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
@@ -127,112 +130,122 @@ void nsWindowCE::ToggleSoftKB(HWND wnd, 
   if (sHardKBPresence == TRI_TRUE) {
     if (GetSliderStateOpen() != TRI_FALSE) {
       show = PR_FALSE;
       sShowSIPButton = TRI_FALSE;
     }
   }
 
   sSIPInTransition = PR_TRUE;
-  HWND hWndSIP = FindWindowW(L"SipWndClass", NULL );
-  if (hWndSIP)
-    ShowWindow(hWndSIP, show ? SW_SHOW: SW_HIDE);
 
-  HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL ); 
-  if (hWndSIPB)
-      ShowWindow(hWndSIPB, show ? SW_SHOW: SW_HIDE);
-
-  SipShowIM(show ? SIPF_ON : SIPF_OFF);
+  SHSipPreference(wnd, show ? SIP_UP : SIP_DOWN);
 
   if (sShowSIPButton == TRI_UNKNOWN) {
+    // Set it to a known value to avoid checking preferences every time
+    // Note: ui.sip.showSIPButton preference change requires browser restart
+    sShowSIPButton = TRI_TRUE;
+
     PRBool tmpBool = PR_FALSE;
     nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefs) {
       nsCOMPtr<nsIPrefBranch> prefBranch;
       prefs->GetBranch(0, getter_AddRefs(prefBranch));
       if (prefBranch) {
         nsresult rv = prefBranch->GetBoolPref("ui.sip.showSIPButton", &tmpBool);
-        if (NS_SUCCEEDED(rv))
+        if (NS_SUCCEEDED(rv)) {
           sShowSIPButton = tmpBool ? TRI_TRUE : TRI_FALSE;
+
+          if (sShowSIPButton == TRI_FALSE) {
+            // Move the SIP rect to the bottom of the screen
+            SIPINFO sipInfo;
+            memset(&sipInfo, 0, sizeof(SIPINFO));
+            sipInfo.cbSize = sizeof(SIPINFO);
+            if (SipGetInfo(&sipInfo)) {
+              // Store the original rect
+              sDefaultSIPRect = sipInfo.rcSipRect;
+
+              // Move the SIP to the bottom of the screen
+              RECT sipRect = sipInfo.rcSipRect;
+              int sipShift = GetSystemMetrics(SM_CYSCREEN) - sipRect.bottom;
+              sipRect.top += sipShift;
+              sipRect.bottom += sipShift;
+              SipSetDefaultRect(&sipRect);
+
+              // Re-select the IM to apply the change
+              CLSID clsid;
+              if (SipGetCurrentIM(&clsid))
+                SipSetCurrentIM(&clsid);
+            }
+          }
+        }
       }
     }
   }
-  if (sShowSIPButton != TRI_TRUE && hWndSIPB && hWndSIP) {
-    ShowWindow(hWndSIPB, SW_HIDE);
-    int sX = GetSystemMetrics(SM_CXSCREEN);
-    int sY = GetSystemMetrics(SM_CYSCREEN);
-    RECT sipRect;
-    GetWindowRect(hWndSIP, &sipRect);
-    int sipH = sipRect.bottom - sipRect.top;
-    int sipW = sipRect.right - sipRect.left;
-    sipRect.left = (sX - sipW)/2;
-    sipRect.top =  sY - sipH;
-    sipRect.bottom = sY;
-    sipRect.right = sipRect.left + sipW;
-    MoveWindow(hWndSIP, (sX - sipW)/2, sY - sipH, sipW, sipH, TRUE);
-    SIPINFO sipInfo;
-    RECT visRect;
-    visRect.top = 0;
-    visRect.left = 0;
-    visRect.bottom = show ? sipRect.top : sY;
-    visRect.right = sX;
-    sipInfo.cbSize = sizeof(SIPINFO);
-    sipInfo.fdwFlags = SIPF_DOCKED | SIPF_LOCKED | (show ? SIPF_ON : SIPF_OFF);
-    sipInfo.rcSipRect = sipRect;
-    sipInfo.rcVisibleDesktop = visRect;
-    sipInfo.dwImDataSize = 0;
-    sipInfo.pvImData = NULL;
-    SipSetInfo(&sipInfo);
-    NotifySoftKbObservers(wnd, &visRect);
-  } else {
-    NotifySoftKbObservers(wnd);
+
+  PRBool showSIPButton = show;
+  if (sShowSIPButton == TRI_FALSE)
+    showSIPButton = PR_FALSE;
+
+  if (!showSIPButton) {
+    HWND hWndSIPB = FindWindowW(L"MS_SIPBUTTON", NULL);
+    if (hWndSIPB)
+      ShowWindow(hWndSIPB, SW_HIDE);
   }
+
+  if (sSoftKeyMenuBarHandle) {
+    ShowWindow(sSoftKeyMenuBarHandle, showSIPButton ? SW_SHOW: SW_HIDE);
+    if (showSIPButton)
+      SetWindowPos(sSoftKeyMenuBarHandle, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+  }
+
   sSIPInTransition = PR_FALSE;
 }
 
 void nsWindowCE::CreateSoftKeyMenuBar(HWND wnd)
 {
   if (!wnd)
     return;
+
+  sMainWindowHandle = wnd;
   
-  static HWND sSoftKeyMenuBar = nsnull;
-  
-  if (sSoftKeyMenuBar != nsnull)
+  if (sSoftKeyMenuBarHandle != NULL)
     return;
   
   SHMENUBARINFO mbi;
   ZeroMemory(&mbi, sizeof(SHMENUBARINFO));
   mbi.cbSize = sizeof(SHMENUBARINFO);
   mbi.hwndParent = wnd;
   
   //  On windows ce smartphone, events never occur if the
   //  menubar is empty.  This doesn't work: 
   //  mbi.dwFlags = SHCMBF_EMPTYBAR;
   
-  mbi.nToolBarId = IDC_DUMMY_CE_MENUBAR;
-  mbi.hInstRes   = GetModuleHandle(NULL);
+  HMENU dummyMenu = CreateMenu();
+  AppendMenu(dummyMenu, MF_STRING, 0, L"");
+
+  mbi.nToolBarId = (UINT)dummyMenu;
+  mbi.dwFlags = SHCMBF_HMENU | SHCMBF_HIDDEN;
+  mbi.hInstRes = GetModuleHandle(NULL);
   
   if (!SHCreateMenuBar(&mbi))
     return;
-  
-  SetWindowPos(mbi.hwndMB, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE);
-  
+
   SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK,
               MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY,
                          SHMBOF_NODEFAULT | SHMBOF_NOTIFY));
   
   SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TSOFT1, 
               MAKELPARAM (SHMBOF_NODEFAULT | SHMBOF_NOTIFY, 
                           SHMBOF_NODEFAULT | SHMBOF_NOTIFY));
   
   SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TSOFT2, 
               MAKELPARAM (SHMBOF_NODEFAULT | SHMBOF_NOTIFY, 
                           SHMBOF_NODEFAULT | SHMBOF_NOTIFY));
-  
-  sSoftKeyMenuBar = mbi.hwndMB;
+
+  sSoftKeyMenuBarHandle = mbi.hwndMB;
 }
 
 void nsWindowCE::CheckKeyboardStatus()
 {
   HKEY  hKey = 0;
   LONG  result = 0;
   DWORD entryType = 0;
   DWORD hwkbd = 0;
@@ -296,16 +309,39 @@ TriStateBool nsWindowCE::GetSliderStateO
   {
      RegCloseKey(hKey);
      return TRI_UNKNOWN;
   }
     
   return  sliderStateOpen ? TRI_TRUE : TRI_FALSE;
 }
 
+
+void nsWindowCE::ResetSoftKB(HWND wnd)
+{
+  if (!wnd || wnd != sMainWindowHandle)
+    return;
+
+  // Main window is being destroyed - reset all the soft-keyboard settings
+  sMainWindowHandle = NULL;
+  sSoftKeyMenuBarHandle = NULL;
+
+  if (sDefaultSIPRect.top > 0) {
+    SipSetDefaultRect(&sDefaultSIPRect);
+    // Re-select the IM to apply the change
+    CLSID clsid;
+    if (SipGetCurrentIM(&clsid))
+      SipSetCurrentIM(&clsid);
+    ZeroMemory(&sDefaultSIPRect, sizeof(sDefaultSIPRect));
+  }
+
+  // This will make it re-read the pref next time
+  sShowSIPButton = TRI_UNKNOWN;
+}
+
 #endif  //defined(WINCE_HAVE_SOFTKB)
 
 typedef struct ECWWindows
 {
   LPARAM      params;
   WNDENUMPROC func;
   HWND        parent;
 } ECWWindows;
--- a/widget/src/windows/nsWindowCE.h
+++ b/widget/src/windows/nsWindowCE.h
@@ -81,22 +81,25 @@ inline BOOL IsIconic(HWND inWnd){return 
 
 class nsWindowCE {
 public:
   static BOOL EnumChildWindows(HWND inParent, WNDENUMPROC inFunc, LPARAM inParam);
 
 #if defined(WINCE_HAVE_SOFTKB)
   static void ToggleSoftKB(HWND wnd, PRBool show);
   static void CreateSoftKeyMenuBar(HWND wnd);
-  static void NotifySoftKbObservers(HWND wnd, LPRECT = NULL);
+  static void OnSoftKbSettingsChange(HWND wnd, LPRECT = NULL);
   static PRBool sSIPInTransition;
   static TriStateBool sShowSIPButton;
   static void CheckKeyboardStatus();
   static TriStateBool GetSliderStateOpen();
+  static void ResetSoftKB(HWND wnd);
 private:
   static TriStateBool sHardKBPresence;
-
+  static HWND sSoftKeyMenuBarHandle;
+  static RECT sDefaultSIPRect;
+  static HWND sMainWindowHandle;
 #endif
 };
 
 #endif /* WINCE */
 
 #endif /* WindowCE_h__ */
--- a/widget/src/windows/nsWindowDefs.h
+++ b/widget/src/windows/nsWindowDefs.h
@@ -48,16 +48,20 @@
 #include "resource.h"
 
 /**************************************************************
  *
  * SECTION: defines
  * 
  **************************************************************/
 
+// A magic APP message that can be sent to quit, sort of like a QUERYENDSESSION/ENDSESSION,
+// but without the query.
+#define MOZ_WM_APP_QUIT                   (WM_APP+0x0300)
+
 // GetWindowsVersion constants
 #define WIN2K_VERSION                     0x500
 #define WINXP_VERSION                     0x501
 #define WIN2K3_VERSION                    0x502
 #define VISTA_VERSION                     0x600
 #define WIN7_VERSION                      0x601
 
 #define WM_XP_THEMECHANGED                0x031A
--- a/xpcom/base/nsTraceRefcntImpl.cpp
+++ b/xpcom/base/nsTraceRefcntImpl.cpp
@@ -615,16 +615,22 @@ static void RecycleSerialNumberPtr(void*
   PL_HashTableRemove(gSerialNumbers, aPtr);
 }
 
 static PRBool LogThisObj(PRInt32 aSerialNumber)
 {
   return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(aSerialNumber));
 }
 
+#ifdef XP_WIN
+#define FOPEN_NO_INHERIT "N"
+#else
+#define FOPEN_NO_INHERIT
+#endif
+
 static PRBool InitLog(const char* envVar, const char* msg, FILE* *result)
 {
   const char* value = getenv(envVar);
   if (value) {
     if (nsCRT::strcmp(value, "1") == 0) {
       *result = stdout;
       fprintf(stdout, "### %s defined -- logging %s to stdout\n",
               envVar, msg);
@@ -648,17 +654,17 @@ static PRBool InitLog(const char* envVar
         fname.AppendLiteral("_");
         fname.Append((char*)XRE_ChildProcessTypeToString(XRE_GetProcessType()));
         fname.AppendLiteral("_pid");
         fname.AppendInt((PRUint32)getpid());
         if (hasLogExtension)
           fname.AppendLiteral(".log");
       }
 #endif
-      stream = ::fopen(fname.get(), "w");
+      stream = ::fopen(fname.get(), "w" FOPEN_NO_INHERIT);
       if (stream != NULL) {
         *result = stream;
         fprintf(stdout, "### %s defined -- logging %s to %s\n",
                 envVar, msg, fname.get());
       }
       else {
         fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
                 envVar, msg, fname.get());