Merge mozilla-central into electrolysis.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Thu, 19 Nov 2009 12:41:46 -0500
changeset 36095 2a59cefc5791dd6bbd68dd15e804322b726f1bec
parent 36094 785d2f84f4c484c258c5a7060318eaa4f20e9067 (current diff)
parent 35139 3b7b772a2f9815ccaa934d119099cfc8b62f1d05 (diff)
child 36096 82ce02c1243b86241ad424b32810fd786573bab7
push idunknown
push userunknown
push dateunknown
milestone1.9.3a1pre
Merge mozilla-central into electrolysis.
accessible/tests/mochitest/test_nsIAccessible_applicationAccessible.html
browser/app/profile/firefox.js
browser/installer/package-manifest.in
build/automation.py.in
config/autoconf.mk.in
configure.in
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/events/src/nsDOMUIEvent.cpp
docshell/base/nsDocShell.cpp
js/src/tests/ecma_3_1/extensions/regress-478047.js
layout/build/nsLayoutStatics.cpp
modules/plugin/base/src/nsPluginsDirWin.cpp
netwerk/build/Makefile.in
netwerk/build/nsNetModule.cpp
nsprpub/configure
parser/html/nsHtml5StackNodeCppSupplement.h
parser/html/nsHtml5StackNodeHSupplement.h
toolkit/toolkit-makefiles.sh
toolkit/toolkit-tiers.mk
toolkit/xre/nsAppRunner.cpp
widget/src/gtk2/nsWindow.cpp
widget/src/windows/nsWindow.cpp
--- a/Makefile.in
+++ b/Makefile.in
@@ -126,26 +126,16 @@ tier_necko::
 	$(foreach tier,$(TIERS),$(MAKE) tools_tier_$(tier); )
 endif
 
 distclean::
 	cat unallmakefiles | $(XARGS) rm -f
 	rm -f unallmakefiles $(DIST_GARBAGE)
 
 ifeq ($(OS_ARCH),WINNT)
-rebase:
-ifdef MOZILLA_OFFICIAL
-	echo rebasing $(DIST)
-	/bin/find $(DIST) -name "*.dll" -a -not -name "msvc*" > rebase.lst
-	rebase -b 60000000 -R . -G rebase.lst
-	rm rebase.lst
-endif
-endif # WINNT
-
-ifeq ($(OS_ARCH),WINNT)
 # we want to copy PDB files on Windows
 MAKE_SYM_STORE_ARGS := -c
 ifdef PDBSTR_PATH
 MAKE_SYM_STORE_ARGS += -i
 endif
 ifeq (,$(CYGWIN_WRAPPER))
 # this doesn't work with Cygwin Python
 MAKE_SYM_STORE_ARGS += --vcs-info
@@ -201,29 +191,16 @@ ifdef MOZ_CRASHREPORTER
           zip -r9D "../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip" .
 endif # MOZ_CRASHREPORTER
 
 uploadsymbols:
 ifdef MOZ_CRASHREPORTER
 	$(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh "$(DIST)/$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip"
 endif
 
-ifeq ($(OS_ARCH),WINNT)
-signnss:
-ifdef MOZILLA_OFFICIAL
-	echo signing NSS libs
-	cd $(DIST)/bin; ./shlibsign.exe -v -i softokn3.dll
-	cd $(DIST)/bin; ./shlibsign.exe -v -i freebl3.dll
-	cd $(DIST)/bin; ./shlibsign.exe -v -i nssdbm3.dll
-endif # MOZILLA_OFFICIAL
-
-deliver: rebase signnss
-
-endif # WINNT
-
 ifneq (,$(wildcard $(DIST)/bin/application.ini))
 BUILDID = $(shell $(PYTHON) $(srcdir)/config/printconfigsetting.py $(DIST)/bin/application.ini App BuildID)
 else
 BUILDID = $(shell $(PYTHON) $(srcdir)/config/printconfigsetting.py $(DIST)/bin/platform.ini Build BuildID)
 endif
 
 #XXX: this is a hack, since we don't want to clobber for MSVC
 # PGO support, but we can't do this test in client.mk
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -357,20 +357,24 @@ NS_IMETHODIMP nsAccessibilityService::On
   return NS_OK;
 }
 
 
 nsresult
 nsAccessibilityService::GetInfo(nsIFrame* aFrame, nsIWeakReference** aShell, nsIDOMNode** aNode)
 {
   NS_ASSERTION(aFrame,"Error -- 1st argument (aFrame) is null!!");
+  if (!aFrame) {
+    return NS_ERROR_FAILURE;
+  }
   nsCOMPtr<nsIContent> content = aFrame->GetContent();
   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
   if (!content || !node)
     return NS_ERROR_FAILURE;
+
   *aNode = node;
   NS_IF_ADDREF(*aNode);
 
   nsCOMPtr<nsIDocument> document = content->GetDocument();
   if (!document)
     return NS_ERROR_FAILURE;
 
   NS_ASSERTION(document->GetPrimaryShell(),"Error no shells!");
@@ -1321,16 +1325,22 @@ NS_IMETHODIMP nsAccessibilityService::Ge
   if (!aPresShell || !aWeakShell || gIsShutdown) {
     return NS_ERROR_FAILURE;
   }
 
   NS_ASSERTION(aNode, "GetAccessible() called with no node.");
 
   *aIsHidden = PR_FALSE;
 
+  // Frames can be deallocated when we flush layout, or when we call into code
+  // that can flush layout, either directly, or via DOM manipulation, or some
+  // CSS styles like :hover. We use the weak frame checks to avoid calling
+  // methods on a dead frame pointer.
+  nsWeakFrame weakFrame(*aFrameHint);
+
 #ifdef DEBUG_A11Y
   // Please leave this in for now, it's a convenient debugging method
   nsAutoString name;
   aNode->GetLocalName(name);
   if (name.LowerCaseEqualsLiteral("h1")) 
     printf("## aaronl debugging tag name\n");
 
   nsAutoString attrib;
@@ -1391,124 +1401,140 @@ NS_IMETHODIMP nsAccessibilityService::Ge
     return NS_ERROR_FAILURE;
   }
   NS_ASSERTION(content->GetDocument() == aPresShell->GetDocument(), "Creating accessible for wrong pres shell");
   if (content->GetDocument() != aPresShell->GetDocument()) {
     return NS_ERROR_FAILURE;
   }
 
   // We have a content node
-  nsIFrame *frame = *aFrameHint;
 #ifdef DEBUG_A11Y
   static int frameHintFailed, frameHintTried, frameHintNonexistant, frameHintFailedForText;
   ++frameHintTried;
 #endif
-  if (!frame || content != frame->GetContent()) {
+
+  if (!weakFrame.GetFrame() || content != weakFrame.GetFrame()->GetContent()) {
     // Frame hint not correct, get true frame, we try to optimize away from this
-    frame = aPresShell->GetRealPrimaryFrameFor(content);
-    if (frame) {
+    weakFrame = aPresShell->GetRealPrimaryFrameFor(content);
+    if (weakFrame.GetFrame()) {
 #ifdef DEBUG_A11Y_FRAME_OPTIMIZATION
       // Frame hint debugging
       ++frameHintFailed;
       if (content->IsNodeOfType(nsINode::eTEXT)) {
         ++frameHintFailedForText;
       }
       frameHintNonexistant += !*aFrameHint;
       printf("Frame hint failures: %d / %d . Text fails = %d. No hint fails = %d \n", frameHintFailed, frameHintTried, frameHintFailedForText, frameHintNonexistant);
       if (frameHintTried >= 354) {
         printf("* "); // Aaron's break point
       }
 #endif
-      if (frame->GetContent() != content) {
+      if (weakFrame.GetFrame()->GetContent() != content) {
         // Not the main content for this frame!
         // For example, this happens because <area> elements return the
         // image frame as their primary frame. The main content for the 
         // image frame is the image content.
 
         // Check if frame is an image frame, and content is <area>
-        nsIImageFrame *imageFrame = do_QueryFrame(frame);
+        nsIImageFrame *imageFrame = do_QueryFrame(weakFrame.GetFrame());
         nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(content);
         if (imageFrame && areaElmt) {
           nsCOMPtr<nsIAccessible> imageAcc;
-          CreateHTMLImageAccessible(frame, getter_AddRefs(imageAcc));
+          CreateHTMLImageAccessible(weakFrame.GetFrame(), getter_AddRefs(imageAcc));
           if (imageAcc) {
             // cache children
             PRInt32 childCount;
             imageAcc->GetChildCount(&childCount);
             // area accessible should be in cache now
             return GetCachedAccessible(aNode, aWeakShell, aAccessible);
           }
         }
 
         return NS_OK;
       }
-      *aFrameHint = frame;
+      *aFrameHint = weakFrame.GetFrame();
     }
   }
 
   // Check frame to see if it is hidden
-  if (!frame || !frame->GetStyleVisibility()->IsVisible()) {
+  if (!weakFrame.GetFrame() ||
+      !weakFrame.GetFrame()->GetStyleVisibility()->IsVisible()) {
     *aIsHidden = PR_TRUE;
   }
 
-  if (*aIsHidden)
+  if (*aIsHidden) {
+    *aFrameHint = weakFrame.GetFrame();
     return NS_OK;
+  }
 
   /**
    * Attempt to create an accessible based on what we know
    */
   if (content->IsNodeOfType(nsINode::eTEXT)) {
     // --- Create HTML for visible text frames ---
-    if (frame->IsEmpty()) {
+    nsIFrame* f = weakFrame.GetFrame();
+    if (f && f->IsEmpty()) {
       nsAutoString renderedWhitespace;
-      frame->GetRenderedText(&renderedWhitespace, nsnull, nsnull, 0, 1);
+      f->GetRenderedText(&renderedWhitespace, nsnull, nsnull, 0, 1);
       if (renderedWhitespace.IsEmpty()) {
         // Really empty -- nothing is rendered
         *aIsHidden = PR_TRUE;
+        *aFrameHint = weakFrame.GetFrame();
         return NS_OK;
       }
     }
-    frame->GetAccessible(getter_AddRefs(newAcc));
-    return InitAccessible(newAcc, aAccessible, nsnull);
+    if (weakFrame.IsAlive()) {
+      weakFrame.GetFrame()->GetAccessible(getter_AddRefs(newAcc));
+    }
+
+    nsresult rv = InitAccessible(newAcc, aAccessible, nsnull);
+    *aFrameHint = weakFrame.GetFrame();
+    return rv;
   }
 
   PRBool isHTML = content->IsHTML();
   if (isHTML && content->Tag() == nsAccessibilityAtoms::map) {
     // Create hyper text accessible for HTML map if it is used to group links
     // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
     // map doesn't have 'name' attribute (or has empty name attribute) then we
     // suppose it is used for links grouping. Otherwise we think it is used in
     // conjuction with HTML image element and in this case we don't create any
     // accessible for it and don't walk into it. The accessibles for HTML area
     // (nsHTMLAreaAccessible) the map contains are attached as children of the
     // appropriate accessible for HTML image (nsHTMLImageAccessible).
     nsAutoString name;
     content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::name, name);
     if (!name.IsEmpty()) {
       *aIsHidden = PR_TRUE;
+      *aFrameHint = weakFrame.GetFrame();
       return NS_OK;
     }
     
-    nsresult rv = CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsresult rv =
+      CreateHyperTextAccessible(weakFrame.GetFrame(), getter_AddRefs(newAcc));
+    if (NS_FAILED(rv)) {
+      *aFrameHint = weakFrame.GetFrame();
+      return rv;
+    }
   }
 
   nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
   if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation") &&
       !content->IsFocusable()) { // For presentation only
     // Only create accessible for role of "presentation" if it is focusable --
     // in that case we need an accessible in case it gets focused, we
     // don't want focus ever to be 'lost'
+    *aFrameHint = weakFrame.GetFrame();
     return NS_OK;
   }
 
-  if (!newAcc && isHTML) {  // HTML accessibles
+  if (weakFrame.IsAlive() && !newAcc && isHTML) {  // HTML accessibles
     PRBool tryTagNameOrFrame = PR_TRUE;
 
-    nsIAtom *frameType = frame->GetType();
+    nsIAtom *frameType = weakFrame.GetFrame()->GetType();
 
     PRBool partOfHTMLTable =
       frameType == nsAccessibilityAtoms::tableCaptionFrame ||
       frameType == nsAccessibilityAtoms::tableCellFrame ||
       frameType == nsAccessibilityAtoms::tableRowGroupFrame ||
       frameType == nsAccessibilityAtoms::tableRowFrame;
 
     if (partOfHTMLTable) {
@@ -1549,16 +1575,17 @@ NS_IMETHODIMP nsAccessibilityService::Ge
                        "No accessible for parent table and it didn't have role of presentation");
 #endif
 
           if (!roleMapEntry && !content->IsFocusable()) {
             // Table-related descendants of presentation table are also
             // presentation if they aren't focusable and have not explicit ARIA
             // role (don't create accessibles for them unless they need to fire
             // focus events).
+            *aFrameHint = weakFrame.GetFrame();
             return NS_OK;
           }
 
           // otherwise create ARIA based accessible.
           tryTagNameOrFrame = PR_FALSE;
           break;
         }
 
@@ -1593,44 +1620,56 @@ NS_IMETHODIMP nsAccessibilityService::Ge
     }
 
     if (!newAcc && tryTagNameOrFrame) {
       // Prefer to use markup (mostly tag name, perhaps attributes) to
       // decide if and what kind of accessible to create.
       // The method creates accessibles for table related content too therefore
       // we do not call it if accessibles for table related content are
       // prevented above.
-      nsresult rv = CreateHTMLAccessibleByMarkup(frame, aWeakShell, aNode,
-                                                 getter_AddRefs(newAcc));
-      NS_ENSURE_SUCCESS(rv, rv);
+      nsresult rv =
+        CreateHTMLAccessibleByMarkup(weakFrame.GetFrame(), aWeakShell, aNode,
+                                     getter_AddRefs(newAcc));
+      if (NS_FAILED(rv)) {
+        *aFrameHint = weakFrame.GetFrame();
+        return rv;
+      }
 
       if (!newAcc) {
         // Do not create accessible object subtrees for non-rendered table
         // captions. This could not be done in
         // nsTableCaptionFrame::GetAccessible() because the descendants of
         // the table caption would still be created. By setting
         // *aIsHidden = PR_TRUE we ensure that no descendant accessibles are
         // created.
-        if (frame->GetType() == nsAccessibilityAtoms::tableCaptionFrame &&
-           frame->GetRect().IsEmpty()) {
+        nsIFrame* f = weakFrame.GetFrame();
+        if (!f) {
+          f = aPresShell->GetRealPrimaryFrameFor(content);
+        }
+        if (f->GetType() == nsAccessibilityAtoms::tableCaptionFrame &&
+           f->GetRect().IsEmpty()) {
           // XXX This is not the ideal place for this code, but right now there
           // is no better place:
           *aIsHidden = PR_TRUE;
+          *aFrameHint = weakFrame.GetFrame();
           return NS_OK;
         }
-        frame->GetAccessible(getter_AddRefs(newAcc)); // Try using frame to do it
+        f->GetAccessible(getter_AddRefs(newAcc)); // Try using frame to do it
       }
     }
   }
 
   if (!newAcc) {
     // Elements may implement nsIAccessibleProvider via XBL. This allows them to
     // say what kind of accessible to create.
     nsresult rv = GetAccessibleByType(aNode, getter_AddRefs(newAcc));
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) {
+      *aFrameHint = weakFrame.GetFrame();
+      return rv;
+    }
   }
 
   if (!newAcc) {
     // Create generic accessibles for SVG and MathML nodes.
     if (content->GetNameSpaceID() == kNameSpaceID_SVG &&
         content->Tag() == nsAccessibilityAtoms::svg) {
       newAcc = new nsEnumRoleAccessible(aNode, aWeakShell,
                                         nsIAccessibleRole::ROLE_DIAGRAM);
@@ -1646,34 +1685,36 @@ NS_IMETHODIMP nsAccessibilityService::Ge
     GetAccessibleForDeckChildren(aNode, getter_AddRefs(newAcc));
   }
 
   // If no accessible, see if we need to create a generic accessible because
   // of some property that makes this object interesting
   // We don't do this for <body>, <html>, <window>, <dialog> etc. which 
   // correspond to the doc accessible and will be created in any case
   if (!newAcc && content->Tag() != nsAccessibilityAtoms::body && content->GetParent() && 
-      (frame->IsFocusable() ||
+      ((weakFrame.GetFrame() && weakFrame.GetFrame()->IsFocusable()) ||
        (isHTML && nsCoreUtils::HasListener(content, NS_LITERAL_STRING("click"))) ||
        HasUniversalAriaProperty(content, aWeakShell) || roleMapEntry ||
        HasRelatedContent(content) || nsCoreUtils::IsXLink(content))) {
     // This content is focusable or has an interesting dynamic content accessibility property.
     // If it's interesting we need it in the accessibility hierarchy so that events or
     // other accessibles can point to it, or so that it can hold a state, etc.
     if (isHTML) {
       // Interesting HTML container which may have selectable text and/or embedded objects
-      CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
+      CreateHyperTextAccessible(weakFrame.GetFrame(), getter_AddRefs(newAcc));
     }
     else {  // XUL, SVG, MathML etc.
       // Interesting generic non-HTML container
       newAcc = new nsAccessibleWrap(aNode, aWeakShell);
     }
   }
 
-  return InitAccessible(newAcc, aAccessible, roleMapEntry);
+  nsresult rv = InitAccessible(newAcc, aAccessible, roleMapEntry);
+  *aFrameHint = weakFrame.GetFrame();
+  return rv;
 }
 
 PRBool
 nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent,
                                                  nsIWeakReference *aWeakShell)
 {
   // ARIA attributes that take token values (NMTOKEN, bool) are special cased.
   return nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_atomic) ||
--- a/accessible/src/base/nsAccessibleTreeWalker.cpp
+++ b/accessible/src/base/nsAccessibleTreeWalker.cpp
@@ -41,30 +41,28 @@
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessNode.h"
 
 #include "nsIAnonymousContentCreator.h"
 #include "nsIServiceManager.h"
 #include "nsIContent.h"
 #include "nsIDOMXULElement.h"
 #include "nsIPresShell.h"
-#include "nsIFrame.h"
 #include "nsWeakReference.h"
 
 nsAccessibleTreeWalker::nsAccessibleTreeWalker(nsIWeakReference* aPresShell, nsIDOMNode* aNode, PRBool aWalkAnonContent): 
   mWeakShell(aPresShell), 
   mAccService(do_GetService("@mozilla.org/accessibilityService;1")),
   mWalkAnonContent(aWalkAnonContent)
 {
   mState.domNode = aNode;
   mState.prevState = nsnull;
   mState.siblingIndex = eSiblingsUninitialized;
   mState.siblingList = nsnull;
   mState.isHidden = false;
-  mState.frame = nsnull;
 
   MOZ_COUNT_CTOR(nsAccessibleTreeWalker);
 }
 
 nsAccessibleTreeWalker::~nsAccessibleTreeWalker()
 {
   // Clear state stack from memory
   while (NS_SUCCEEDED(PopState()))
@@ -116,22 +114,23 @@ void nsAccessibleTreeWalker::GetKids(nsI
     }
   }
 
   mState.siblingList->Item(0 /* 0 == mState.siblingIndex */, getter_AddRefs(mState.domNode));
 }
 
 NS_IMETHODIMP nsAccessibleTreeWalker::PopState()
 {
-  nsIFrame *frameParent = mState.frame? mState.frame->GetParent(): nsnull;
+  nsIFrame *frameParent =
+    mState.frame.GetFrame() ? mState.frame.GetFrame()->GetParent() : nsnull;
   if (mState.prevState) {
     WalkState *toBeDeleted = mState.prevState;
     mState = *mState.prevState; // deep copy
     mState.isHidden = PR_FALSE; // If we were in a child, the parent wasn't hidden
-    if (!mState.frame) {
+    if (!mState.frame.GetFrame()) {
       mState.frame = frameParent;
     }
     delete toBeDeleted;
     return NS_OK;
   }
   ClearState();
   mState.frame = frameParent;
   mState.isHidden = PR_FALSE;
@@ -161,18 +160,18 @@ NS_IMETHODIMP nsAccessibleTreeWalker::Pu
 
 void nsAccessibleTreeWalker::GetNextDOMNode()
 {
   // Get next DOM node
   if (mState.parentContent) {
     mState.domNode = do_QueryInterface(mState.parentContent->GetChildAt(++mState.siblingIndex));
   }
   else if (mState.siblingIndex == eSiblingsWalkFrames) {
-    if (mState.frame) {
-      mState.domNode = do_QueryInterface(mState.frame->GetContent());
+    if (mState.frame.GetFrame()) {
+      mState.domNode = do_QueryInterface(mState.frame.GetFrame()->GetContent());
     } else {
       mState.domNode = nsnull;
     }
   }
   else { 
     mState.siblingList->Item(++mState.siblingIndex, getter_AddRefs(mState.domNode));
   }
 }
@@ -225,28 +224,30 @@ NS_IMETHODIMP nsAccessibleTreeWalker::Ge
   }
 
   PopState();  // Return to previous state
   return NS_ERROR_FAILURE;
 }
 
 void nsAccessibleTreeWalker::UpdateFrame(PRBool aTryFirstChild)
 {
-  if (!mState.frame) {
+  nsIFrame *curFrame = mState.frame.GetFrame();
+  if (!curFrame) {
     return;
   }
 
   if (aTryFirstChild) {
     // If the frame implements nsIAnonymousContentCreator interface then go down
     // through the frames and obtain anonymous nodes for them.
-    nsIAnonymousContentCreator* creator = do_QueryFrame(mState.frame);
-    mState.frame = mState.frame->GetFirstChild(nsnull);
+    nsIAnonymousContentCreator* creator = do_QueryFrame(curFrame);
+    nsIFrame *child = curFrame->GetFirstChild(nsnull);
+    mState.frame = child;
 
-    if (creator && mState.frame && mState.siblingIndex < 0) {
-      mState.domNode = do_QueryInterface(mState.frame->GetContent());
+    if (creator && child && mState.siblingIndex < 0) {
+      mState.domNode = do_QueryInterface(child->GetContent());
       mState.siblingIndex = eSiblingsWalkFrames;
     }
 // temporary workaround for Bug 359210. We never want to walk frames.
 // Aaron Leventhal will refix :before and :after content later without walking frames.
 #if 0
     if (mState.frame && mState.siblingIndex < 0) {
       // Container frames can contain generated content frames from
       // :before and :after style rules, so we walk their frame trees
@@ -263,31 +264,33 @@ void nsAccessibleTreeWalker::UpdateFrame
       //   pseudoContext = presContext->StyleSet()->
       //     ProbePseudoStyleFor(content, nsAccessibilityAtoms::after, aStyleContext);
       mState.domNode = do_QueryInterface(mState.frame->GetContent());
       mState.siblingIndex = eSiblingsWalkFrames;
     }
 #endif
   }
   else {
-    mState.frame = mState.frame->GetNextSibling();
+    mState.frame = curFrame->GetNextSibling();
   }
 }
 
 /**
  * If the DOM node's frame has an accessible or the DOMNode
  * itself implements nsIAccessible return it.
  */
 PRBool nsAccessibleTreeWalker::GetAccessible()
 {
   if (!mAccService) {
     return PR_FALSE;
   }
 
   mState.accessible = nsnull;
   nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
 
+  nsIFrame *frame = mState.frame.GetFrame();
   mAccService->GetAccessible(mState.domNode, presShell, mWeakShell,
-                             &mState.frame, &mState.isHidden,
+                             &frame, &mState.isHidden,
                              getter_AddRefs(mState.accessible));
+  mState.frame = frame;
   return mState.accessible ? PR_TRUE : PR_FALSE;
 }
 
--- a/accessible/src/base/nsAccessibleTreeWalker.h
+++ b/accessible/src/base/nsAccessibleTreeWalker.h
@@ -34,36 +34,38 @@
  * 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 _nsAccessibleTreeWalker_H_
 #define _nsAccessibleTreeWalker_H_
 
-/* For documentation of the accessibility architecture,  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
+/* For documentation of the accessibility architecture, see
+ * http://www.mozilla.org/access/architecture
  */
 
 #include "nsCOMPtr.h"
 #include "nsIDocument.h"
 #include "nsIAccessible.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIAccessibilityService.h"
 #include "nsIWeakReference.h"
+#include "nsIFrame.h"
 
 enum { eSiblingsUninitialized = -1, eSiblingsWalkFrames = -2 };
 
 struct WalkState {
   nsCOMPtr<nsIAccessible> accessible;
   nsCOMPtr<nsIDOMNode> domNode;
   nsCOMPtr<nsIDOMNodeList> siblingList;
   nsIContent *parentContent; // For walking normal DOM
   WalkState *prevState;
-  nsIFrame *frame;     // Helps avoid GetPrimaryFrameFor() calls
+  nsWeakFrame frame;       // Helps avoid GetPrimaryFrameFor() calls
   PRInt32 siblingIndex;    // Holds a state flag or an index into the siblingList
   PRBool isHidden;         // Don't enter subtree if hidden
 };
  
 /** This class is used to walk the DOM tree. It skips
   * everything but nodes that either implement nsIAccessibleProvider
   * or have primary frames that implement "GetAccessible"
   */
--- a/accessible/src/xul/nsXULListboxAccessible.cpp
+++ b/accessible/src/xul/nsXULListboxAccessible.cpp
@@ -1152,18 +1152,17 @@ nsXULListCellAccessible::GetColumnHeader
   NS_ENSURE_ARG_POINTER(aHeaderCells);
   *aHeaderCells = nsnull;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIAccessibleTable> table;
   GetTable(getter_AddRefs(table));
-  if (!table)
-    return NS_OK;
+  NS_ENSURE_STATE(table); // we expect to be in a listbox (table)
 
   // Get column header cell from XUL listhead.
   nsCOMPtr<nsIAccessible> tableAcc(do_QueryInterface(table));
 
   nsCOMPtr<nsIAccessible> list, nextChild;
   tableAcc->GetFirstChild(getter_AddRefs(list));
   while (list) {
     if (nsAccUtils::Role(list) == nsIAccessibleRole::ROLE_LIST)
@@ -1204,18 +1203,17 @@ nsXULListCellAccessible::GetRowHeaderCel
   NS_ENSURE_ARG_POINTER(aHeaderCells);
   *aHeaderCells = nsnull;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIAccessibleTable> table;
   GetTable(getter_AddRefs(table));
-  if (!table)
-    return NS_OK;
+  NS_ENSURE_STATE(table); // we expect to be in a listbox (table)
 
   // Calculate row header cells from ARIA markup.
   return nsAccUtils::GetHeaderCellsFor(table, this,
                                        nsAccUtils::eRowHeaderCells,
                                        aHeaderCells);
 }
 
 NS_IMETHODIMP
@@ -1224,18 +1222,17 @@ nsXULListCellAccessible::IsSelected(PRBo
   NS_ENSURE_ARG_POINTER(aIsSelected);
   *aIsSelected = PR_FALSE;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIAccessibleTable> table;
   GetTable(getter_AddRefs(table));
-  if (!table)
-    return NS_OK;
+  NS_ENSURE_STATE(table); // we expect to be in a listbox (table)
 
   PRInt32 rowIdx = -1;
   GetRowIndex(&rowIdx);
 
   return table->IsRowSelected(rowIdx, aIsSelected);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1254,16 +1251,17 @@ nsXULListCellAccessible::GetAttributesIn
   NS_ENSURE_ARG_POINTER(aAttributes);
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   // "table-cell-index" attribute
   nsCOMPtr<nsIAccessibleTable> table;
   GetTable(getter_AddRefs(table));
+  NS_ENSURE_STATE(table); // we expect to be in a listbox (table)
 
   PRInt32 rowIdx = -1;
   GetRowIndex(&rowIdx);
   PRInt32 colIdx = -1;
   GetColumnIndex(&colIdx);
 
   PRInt32 cellIdx = -1;
   table->GetCellIndexAt(rowIdx, colIdx, &cellIdx);
--- a/accessible/tests/mochitest/test_name_nsRootAcc.xul
+++ b/accessible/tests/mochitest/test_name_nsRootAcc.xul
@@ -20,19 +20,23 @@
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/events.js"></script>
 
   <script type="application/javascript">
   <![CDATA[
     // var gA11yEventDumpID = "eventdump"; // debug stuff
 
     SimpleTest.waitForExplicitFinish();
-    window.openDialog("chrome://mochikit/content/a11y/accessible/name_nsRootAcc_wnd.xul",
-                      "nsRootAcc_name_test", 
-                      "chrome,width=600,height=600");
+    var w = window.openDialog("chrome://mochikit/content/a11y/accessible/name_nsRootAcc_wnd.xul",
+                              "nsRootAcc_name_test", 
+                              "chrome,width=600,height=600");
+    if (LINUX) {
+      w.focus();
+    }
+    
   ]]>
   </script>
 
   <vbox flex="1" style="overflow: auto;">
   <body xmlns="http://www.w3.org/1999/xhtml">
     <a target="_blank"
        href="https://bugzilla.mozilla.org/show_bug.cgi?id=507382"
        title="focus is fired earlier than root accessible name is changed when switching between tabs">
--- a/browser/Makefile.in
+++ b/browser/Makefile.in
@@ -30,24 +30,34 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-DEPTH		= ..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
+DEPTH     = ..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
 
 include $(topsrcdir)/config/config.mk
 
-DIRS = base components locales themes fuel app
+PARALLEL_DIRS = \
+  base \
+  components \
+  fuel \
+  locales \
+  themes \
+  $(NULL)
+
+DIRS = \
+  app \
+  $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 ifdef MOZ_INSTALLER
 DIRS += installer/windows
 endif
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -160,29 +160,29 @@ pref("app.update.incompatible.mode", 0);
 //  extensions.{GUID}.update.url
 //  .. etc ..
 //
 pref("extensions.update.enabled", true);
 pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
 pref("extensions.update.interval", 86400);  // Check for updates to Extensions and 
                                             // Themes every day
 // Non-symmetric (not shared by extensions) extension-specific [update] preferences
-pref("extensions.getMoreExtensionsURL", "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/%APP%/%VERSION%/extensions/");
-pref("extensions.getMoreThemesURL", "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/%APP%/%VERSION%/themes/");
-pref("extensions.getMorePluginsURL", "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/%APP%/%VERSION%/plugins/");
+pref("extensions.getMoreThemesURL", "https://addons.mozilla.org/%LOCALE%/%APP%/getpersonas");
 pref("extensions.dss.enabled", false);          // Dynamic Skin Switching                                               
 pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
                                                 // restart.
 
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
 
 pref("xpinstall.whitelist.add", "addons.mozilla.org");
 pref("xpinstall.whitelist.add.36", "getpersonas.com");
 
+pref("lightweightThemes.update.enabled", true);
+
 pref("keyword.enabled", true);
 pref("keyword.URL", "chrome://browser-region/locale/region.properties");
 
 pref("general.useragent.locale", "@AB_CD@");
 pref("general.skins.selectedSkin", "classic/1.0");
 pref("general.useragent.extra.firefox", "@APP_UA_NAME@/@APP_VERSION@");
 
 pref("general.smoothScroll", false);
--- a/browser/base/content/baseMenuOverlay.xul
+++ b/browser/base/content/baseMenuOverlay.xul
@@ -87,18 +87,18 @@
 #endif
 # Show IE Users menu item on Windows only
 #ifdef XP_WIN
         <menuitem label="&helpForIEUsers.label;"
                   accesskey="&helpForIEUsers.accesskey;"
                   oncommand="openHelpLink('ieusers');"/>
 #endif
         <menuitem id="troubleShooting"
-                  accesskey="&helpTroubleshooting.accesskey;"
-                  label="&helpTroubleshooting.label;"
+                  accesskey="&helpTroubleshootingInfo.accesskey;"
+                  label="&helpTroubleshootingInfo.label;"
                   oncommand="openTroubleshootingPage()"
                   onclick="checkForMiddleClick(this, event);"/>
         <menuitem id="releaseNotes"
                   accesskey="&helpReleaseNotes.accesskey;"
                   label="&helpReleaseNotes.label;"
                   oncommand="openReleaseNotes()"
                   onclick="checkForMiddleClick(this, event);"/>
         <menuseparator id="updateSeparator"/>
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -884,22 +884,22 @@ var BookmarksEventHandler = {
       target._endMarker = target.childNodes.length;
       target.appendChild(target._endOptSeparator);
     }
 
     if (siteURIString && !target._endOptOpenSiteURI) {
       // Add "Open (Feed Name)" menuitem if it's a livemark with a siteURI
       target._endOptOpenSiteURI = document.createElement("menuitem");
       target._endOptOpenSiteURI.className = "openlivemarksite-menuitem";
-      target._endOptOpenSiteURI.setAttribute("siteURI", siteURIString);
+      target._endOptOpenSiteURI.setAttribute("targetURI", siteURIString);
       target._endOptOpenSiteURI.setAttribute("oncommand",
-          "openUILink(this.getAttribute('siteURI'), event);");
+          "openUILink(this.getAttribute('targetURI'), event);");
       // If a user middle-clicks this item we serve the oncommand event
       // We are using checkForMiddleClick because of Bug 246720
-      // Note: stopPropagation is needed to avoid serving middle-click 
+      // Note: stopPropagation is needed to avoid serving middle-click
       // with BT_onClick that would open all items in tabs
       target._endOptOpenSiteURI.setAttribute("onclick",
           "checkForMiddleClick(this, event); event.stopPropagation();");
       target._endOptOpenSiteURI.setAttribute("label",
           PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label",
           [target.parentNode.getAttribute("label")]));
       target.appendChild(target._endOptOpenSiteURI);
     }
@@ -917,39 +917,50 @@ var BookmarksEventHandler = {
             gNavigatorBundle.getString("menuOpenAllInTabs.label"));
         target.appendChild(target._endOptOpenAllInTabs);
     }
   },
 
   fillInBHTooltip: function(aDocument, aEvent) {
     var node;
     var cropped = false;
+    var targetURI;
 
     if (aDocument.tooltipNode.localName == "treechildren") {
       var tree = aDocument.tooltipNode.parentNode;
       var row = {}, column = {};
       var tbo = tree.treeBoxObject;
       tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, column, {});
       if (row.value == -1)
         return false;
       node = tree.view.nodeForTreeIndex(row.value);
       cropped = tbo.isCellCropped(row.value, column.value);
     }
-    else
-      node = aDocument.tooltipNode.node;
+    else {
+      // Check whether the tooltipNode is a Places node.
+      // In such a case use it, otherwise check for targetURI attribute.
+      var tooltipNode = aDocument.tooltipNode;
+      if (tooltipNode.node)
+        node = tooltipNode.node;
+      else {
+        // This is a static non-Places node.
+        targetURI = tooltipNode.getAttribute("targetURI");
+      }
+    }
 
-    if (!node)
+    if (!node && !targetURI)
       return false;
 
-    var title = node.title;
-    var url;
+    // Show node.label as tooltip's title for non-Places nodes.
+    var title = node ? node.title : tooltipNode.label;
 
-    // Show URL only for URI-type nodes.
-    if (PlacesUtils.nodeIsURI(node))
-      url = node.uri;
+    // Show URL only for Places URI-nodes or nodes with a targetURI attribute.
+    var url;
+    if (targetURI || PlacesUtils.nodeIsURI(node))
+      url = targetURI || node.uri;
 
     // Show tooltip for containers only if their title is cropped.
     if (!cropped && !url)
       return false;
 
     var tooltipTitle = aDocument.getElementById("bhtTitleText");
     tooltipTitle.hidden = (!title || (title == url));
     if (!tooltipTitle.hidden)
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -43,16 +43,17 @@
 #   Johnathan Nightingale <johnath@mozilla.com>
 #   Ehsan Akhgari <ehsan.akhgari@gmail.com>
 #   Dão Gottwald <dao@mozilla.com>
 #   Thomas K. Dyas <tdyas@zecador.org>
 #   Edward Lee <edward.lee@engineering.uiuc.edu>
 #   Paul O’Shannessy <paul@oshannessy.com>
 #   Nils Maier <maierman@web.de>
 #   Rob Arnold <robarnold@cmu.edu>
+#   Dietrich Ayala <dietrich@mozilla.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -147,16 +148,22 @@ XPCOMUtils.defineLazyGetter(this, "Win7F
       }
     };
   }
 #endif
 #endif
   return null;
 });
 
+#ifdef MOZ_CRASHREPORTER
+XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter",
+                                   "@mozilla.org/xre/app-info;1",
+                                   "nsICrashReporter");
+#endif
+
 /**
 * We can avoid adding multiple load event listeners and save some time by adding
 * one listener that calls all real handlers.
 */
 function pageShowEventHandlers(event) {
   // Filter out events that are not about the document load we are interested in
   if (event.originalTarget == content.document) {
     charsetLoadListener(event);
@@ -4313,16 +4320,24 @@ var XULBrowserWindow = {
 
 var TabsProgressListener = {
   onProgressChange: function (aBrowser, aWebProgress, aRequest,
                               aCurSelfProgress, aMaxSelfProgress,
                               aCurTotalProgress, aMaxTotalProgress) {
   },
 
   onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
+#ifdef MOZ_CRASHREPORTER
+    if (!aRequest.URI)
+      aRequest.QueryInterface(Ci.nsIChannel);
+    if (aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
+        aStateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT) {
+      gCrashReporter.annotateCrashReport("URL", aRequest.URI.spec);
+    }
+#endif
   },
 
   onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
     // Filter out any sub-frame loads
     if (aBrowser.contentWindow == aWebProgress.DOMWindow)
       FullZoom.onLocationChange(aLocationURI, false, aBrowser);
   },
   
@@ -6835,35 +6850,58 @@ let gPrivateBrowsingUI = {
   _privateBrowsingService: null,
   _searchBarValue: null,
   _findBarValue: null,
 
   init: function PBUI_init() {
     this._observerService = Cc["@mozilla.org/observer-service;1"].
                             getService(Ci.nsIObserverService);
     this._observerService.addObserver(this, "private-browsing", false);
+    this._observerService.addObserver(this, "private-browsing-transition-complete", false);
 
     this._privateBrowsingService = Cc["@mozilla.org/privatebrowsing;1"].
                                    getService(Ci.nsIPrivateBrowsingService);
 
     if (this.privateBrowsingEnabled)
       this.onEnterPrivateBrowsing();
   },
 
   uninit: function PBUI_unint() {
     this._observerService.removeObserver(this, "private-browsing");
+    this._observerService.removeObserver(this, "private-browsing-transition-complete");
+  },
+
+  get _disableUIOnToggle PBUI__disableUIOnTogle() {
+    if (this._privateBrowsingService.autoStarted)
+      return false;
+
+    try {
+      return !gPrefService.getBoolPref("browser.privatebrowsing.keep_current_session");
+    }
+    catch (e) {
+      return true;
+    }
   },
 
   observe: function PBUI_observe(aSubject, aTopic, aData) {
     if (aTopic == "private-browsing") {
       if (aData == "enter")
         this.onEnterPrivateBrowsing();
       else if (aData == "exit")
         this.onExitPrivateBrowsing();
     }
+    else if (aTopic == "private-browsing-transition-complete") {
+      if (this._disableUIOnToggle) {
+        // use setTimeout here in order to make the code testable
+        setTimeout(function() {
+          document.getElementById("Tools:PrivateBrowsing")
+                  .removeAttribute("disabled");
+        }, 0);
+      }
+    }
   },
 
   _shouldEnter: function PBUI__shouldEnter() {
     try {
       // Never prompt if the session is not going to be closed, or if user has
       // already requested not to be prompted.
       if (gPrefService.getBoolPref("browser.privatebrowsing.dont_prompt_on_enter") ||
           gPrefService.getBoolPref("browser.privatebrowsing.keep_current_session"))
@@ -6949,16 +6987,20 @@ let gPrivateBrowsingUI = {
         docElement.getAttribute("titlemodifier_privatebrowsing"));
       docElement.setAttribute("browsingmode", "private");
       gBrowser.updateTitlebar();
     }
 
     setTimeout(function () {
       DownloadMonitorPanel.updateStatus();
     }, 0);
+
+    if (this._disableUIOnToggle)
+      document.getElementById("Tools:PrivateBrowsing")
+              .setAttribute("disabled", "true");
   },
 
   onExitPrivateBrowsing: function PBUI_onExitPrivateBrowsing() {
     if (BrowserSearch.searchBar) {
       let searchBox = BrowserSearch.searchBar.textbox;
       searchBox.reset();
       if (this._searchBarValue) {
         searchBox.value = this._searchBarValue;
@@ -6999,16 +7041,20 @@ let gPrivateBrowsingUI = {
     document.getElementById("Tools:PrivateBrowsing")
             .removeAttribute("disabled");
 
     gLastOpenDirectory.reset();
 
     setTimeout(function () {
       DownloadMonitorPanel.updateStatus();
     }, 0);
+
+    if (this._disableUIOnToggle)
+      document.getElementById("Tools:PrivateBrowsing")
+              .setAttribute("disabled", "true");
   },
 
   _setPBMenuTitle: function PBUI__setPBMenuTitle(aMode) {
     let pbMenuItem = document.getElementById("privateBrowsingItem");
     pbMenuItem.setAttribute("label", pbMenuItem.getAttribute(aMode + "label"));
     pbMenuItem.setAttribute("accesskey", pbMenuItem.getAttribute(aMode + "accesskey"));
   },
 
@@ -7119,19 +7165,21 @@ var LightWeightThemeWebInstaller = {
       callback: function () {
         LightWeightThemeWebInstaller._install(data);
       }
     }];
 
     this._removePreviousNotifications();
 
     var notificationBox = gBrowser.getNotificationBox();
-    notificationBox.appendNotification(message, "lwtheme-install-request", "",
-                                       notificationBox.PRIORITY_INFO_MEDIUM,
-                                       buttons);
+    var notificationBar =
+      notificationBox.appendNotification(message, "lwtheme-install-request", "",
+                                         notificationBox.PRIORITY_INFO_MEDIUM,
+                                         buttons);
+    notificationBar.persistence = 1;
   },
 
   _install: function (newTheme) {
     var previousTheme = this._manager.currentTheme;
     this._manager.currentTheme = newTheme;
     if (this._manager.currentTheme &&
         this._manager.currentTheme.id == newTheme.id)
       this._postInstallNotification(newTheme, previousTheme);
@@ -7155,20 +7203,23 @@ var LightWeightThemeWebInstaller = {
       callback: function () {
         BrowserOpenAddonsMgr("themes");
       }
     }];
 
     this._removePreviousNotifications();
 
     var notificationBox = gBrowser.getNotificationBox();
-    notificationBox.appendNotification(text("message"),
-                                       "lwtheme-install-notification", "",
-                                       notificationBox.PRIORITY_INFO_MEDIUM,
-                                       buttons);
+    var notificationBar =
+      notificationBox.appendNotification(text("message"),
+                                         "lwtheme-install-notification", "",
+                                         notificationBox.PRIORITY_INFO_MEDIUM,
+                                         buttons);
+    notificationBar.persistence = 1;
+    notificationBar.timeout = Date.now() + 20000; // 20 seconds
   },
 
   _removePreviousNotifications: function () {
     var box = gBrowser.getNotificationBox();
 
     ["lwtheme-install-request",
      "lwtheme-install-notification"].forEach(function (value) {
         var notification = box.getNotificationWithValue(value);
@@ -7227,49 +7278,12 @@ var LightWeightThemeWebInstaller = {
       }
     });
 
     var uri = node.ownerDocument.documentURIObject;
     return pm.testPermission(uri, "install") == pm.ALLOW_ACTION;
   },
 
   _getThemeFromNode: function (node) {
-    const MANDATORY = ["id", "name", "headerURL"];
-    const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL",
-                      "previewURL", "author", "description", "homepageURL"];
-
-    try {
-      var data = JSON.parse(node.getAttribute("data-browsertheme"));
-    } catch (e) {
-      return null;
-    }
-
-    if (!data || typeof data != "object")
-      return null;
-
-    for (let prop in data) {
-      if (!data[prop] ||
-          typeof data[prop] != "string" ||
-          MANDATORY.indexOf(prop) == -1 && OPTIONAL.indexOf(prop) == -1) {
-        delete data[prop];
-        continue;
-      }
-
-      if (/URL$/.test(prop)) {
-        try {
-          data[prop] = makeURLAbsolute(node.baseURI, data[prop]);
-
-          if (/^https?:/.test(data[prop]))
-            continue;
-        } catch (e) {}
-
-        delete data[prop];
-      }
-    }
-
-    for (let i = 0; i < MANDATORY.length; i++) {
-      if (!(MANDATORY[i] in data)) 
-        return null;
-    }
-
-    return data;
+    return this._manager.parseTheme(node.getAttribute("data-browsertheme"),
+                                    node.baseURI);
   }
 }
--- a/browser/base/content/openLocationLastURL.jsm
+++ b/browser/base/content/openLocationLastURL.jsm
@@ -48,23 +48,31 @@ let observer = {
   QueryInterface: function (aIID) {
     if (aIID.equals(Components.interfaces.nsIObserver) ||
         aIID.equals(Components.interfaces.nsISupports) ||
         aIID.equals(Components.interfaces.nsISupportsWeakReference))
       return this;
     throw Components.results.NS_NOINTERFACE;
   },
   observe: function (aSubject, aTopic, aData) {
-    gOpenLocationLastURLData = "";
+    switch (aTopic) {
+      case "private-browsing":
+        gOpenLocationLastURLData = "";
+        break;
+      case "browser:purge-session-history":
+        gOpenLocationLastURL.reset();
+        break;
+    }
   }
 };
 
-Components.classes["@mozilla.org/observer-service;1"]
-          .getService(Components.interfaces.nsIObserverService)
-          .addObserver(observer, "private-browsing", true);
+let os = Components.classes["@mozilla.org/observer-service;1"]
+                   .getService(Components.interfaces.nsIObserverService);
+os.addObserver(observer, "private-browsing", true);
+os.addObserver(observer, "browser:purge-session-history", true);
 
 let gOpenLocationLastURLData = "";
 let gOpenLocationLastURL = {
   get value() {
     if (pbSvc.privateBrowsingEnabled)
       return gOpenLocationLastURLData;
     else {
       try {
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -80,17 +80,17 @@ pageInfoTreeView.prototype = {
   {
     this.data[row][column.index] = value;
   },
 
   addRow: function(row)
   {
     this.rows = this.data.push(row);
     this.rowCountChanged(this.rows - 1, 1);
-    if (this.selection.count == 0 && this.rowCount)
+    if (this.selection.count == 0 && this.rowCount && !gImageElement)
       this.selection.select(0);
   },
 
   rowCountChanged: function(index, count)
   {
     this.tree.rowCountChanged(index, count);
   },
 
--- a/browser/base/content/test/browser_bug441778.js
+++ b/browser/base/content/test/browser_bug441778.js
@@ -35,70 +35,43 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * Test the fix for bug 441778 to ensure site-specific page zoom doesn't get
  * modified by sub-document loads of content from a different domain.
  */
 
-let testPage = 'data:text/html,<body><iframe id="a" src=""></iframe></body>';
-
 function test() {
   waitForExplicitFinish();
 
-  // The zoom level before the sub-document load.  We set this in continueTest
-  // and then compare it to the current zoom level in finishTest to make sure
-  // it hasn't changed.
-  let zoomLevel;
+  const TEST_PAGE_URL = 'data:text/html,<body><iframe src=""></iframe></body>';
+  const TEST_IFRAME_URL = "http://test2.example.org/";
 
   // Prepare the test tab
   gBrowser.selectedTab = gBrowser.addTab();
   let testBrowser = gBrowser.selectedBrowser;
 
-  let finishTest = function() {
-    testBrowser.removeProgressListener(progressListener);
-    is(ZoomManager.zoom, zoomLevel, "zoom is retained after sub-document load");
-    gBrowser.removeCurrentTab();
-    finish();
-  };
+  testBrowser.addEventListener("load", function () {
+    testBrowser.removeEventListener("load", arguments.callee, true);
 
-  let progressListener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                           Ci.nsISupportsWeakReference]),
-    onStateChange: function() {},
-    onProgressChange: function() {},
-    onLocationChange: function() {
-      window.setTimeout(finishTest, 0);
-    },
-    onStatusChange: function() {},
-    onSecurityChange: function() {}
-  };
-
-  let continueTest = function() {
     // Change the zoom level and then save it so we can compare it to the level
     // after loading the sub-document.
     FullZoom.enlarge();
-    zoomLevel = ZoomManager.zoom;
-
-    // Finish the test in a timeout after the sub-document location change
-    // to give the zoom controller time to respond to it.
-    testBrowser.addProgressListener(progressListener);
+    var zoomLevel = ZoomManager.zoom;
 
     // Start the sub-document load.
-    content.document.getElementById("a").src = "http://test2.example.org/";
-  };
+    executeSoon(function () {
+      testBrowser.addEventListener("load", function (e) {
+        testBrowser.removeEventListener("load", arguments.callee, true);
+
+        is(e.target.defaultView.location, TEST_IFRAME_URL, "got the load event for the iframe");
+        is(ZoomManager.zoom, zoomLevel, "zoom is retained after sub-document load");
 
-  // Continue the test after the test page has loaded.
-  // Note: in order for the sub-document load to trigger a location change
-  // the way it does under real world usage scenarios, we have to continue
-  // the test in a timeout for some unknown reason.
-  let continueListener = function() {
-    window.setTimeout(continueTest, 0);
-    
-    // Remove the load listener so it doesn't get called for the sub-document.
-    testBrowser.removeEventListener("load", continueListener, true);
-  };
-  testBrowser.addEventListener("load", continueListener, true);
+        gBrowser.removeCurrentTab();
+        finish();
+      }, true);
+      content.document.querySelector("iframe").src = TEST_IFRAME_URL;
+    });
+  }, true);
 
-  // Start the test by loading the test page.
-  testBrowser.contentWindow.location = testPage;
+  content.location = TEST_PAGE_URL;
 }
--- a/browser/base/content/test/browser_bug517902.js
+++ b/browser/base/content/test/browser_bug517902.js
@@ -26,13 +26,13 @@ function test() {
           finish();
         });
       });
     }, true);
   }, true);
 
   content.location =
     "data:text/html," +
+    "<img src='about:logo?b' height=300 width=350 alt=2>" +
     "<img src='about:logo?a' height=200 width=250>" +
     "<img src='about:logo?b' height=200 width=250 alt=1>" +
-    "<img src='about:logo?b' height=200 width=250 alt=2>" +
     "<img src='about:logo?b' height=100 width=150 alt=2 id='test-image'>";
 }
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -470,27 +470,27 @@ function buildHelpMenu()
   // Enable/disable the "Report Web Forgery" menu item.  safebrowsing object
   // may not exist in OSX
   if (typeof safebrowsing != "undefined")
     safebrowsing.setReportPhishingMenu();
 
 #ifdef MOZ_UPDATER
   var updates = 
       Components.classes["@mozilla.org/updates/update-service;1"].
-      getService(Components.interfaces.nsIApplicationUpdateService);
+      getService(Components.interfaces.nsIApplicationUpdateService2);
   var um = 
       Components.classes["@mozilla.org/updates/update-manager;1"].
       getService(Components.interfaces.nsIUpdateManager);
 
   // Disable the UI if the update enabled pref has been locked by the 
   // administrator or if we cannot update for some other reason
   var checkForUpdates = document.getElementById("checkForUpdates");
-  var canUpdate = updates.canUpdate;
-  checkForUpdates.setAttribute("disabled", !canUpdate);
-  if (!canUpdate)
+  var canCheckForUpdates = updates.canCheckForUpdates;
+  checkForUpdates.setAttribute("disabled", !canCheckForUpdates);
+  if (!canCheckForUpdates)
     return; 
 
   var strings = document.getElementById("bundle_browser");
   var activeUpdate = um.activeUpdate;
   
   // If there's an active update, substitute its name into the label
   // we show for this item, otherwise display a generic label.
   function getStringWithUpdateName(key) {
--- a/browser/components/Makefile.in
+++ b/browser/components/Makefile.in
@@ -30,65 +30,65 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-DEPTH		= ../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
+DEPTH     = ../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = browsercomps
 XPIDL_MODULE = browsercompsbase
 
 XPIDLSRCS = \
-	nsIBrowserHandler.idl \
-	nsIBrowserGlue.idl \
-	$(NULL)
+  nsIBrowserGlue.idl \
+  nsIBrowserHandler.idl \
+  $(NULL)
 
 EXTRA_PP_COMPONENTS = \
-	nsBrowserContentHandler.js \
-	nsBrowserGlue.js \
-	$(NULL)
+  nsBrowserContentHandler.js \
+  nsBrowserGlue.js \
+  $(NULL)
 
 EXTRA_JS_MODULES = distribution.js
 
-DIRS = \
-	about \
-	certerror \
-	dirprovider \
-	microsummaries \
-	preferences \
-	search \
-	sessionstore \
-	shell \
-	sidebar \
-	feeds \
-	places \
-	privatebrowsing \
-	$(NULL)
+PARALLEL_DIRS = \
+  about \
+  certerror \
+  dirprovider \
+  feeds \
+  microsummaries \
+  places \
+  preferences \
+  privatebrowsing \
+  search \
+  sessionstore \
+  shell \
+  sidebar \
+  $(NULL)
 
 ifndef WINCE
-DIRS += migration
+PARALLEL_DIRS += migration
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows) 
 ifndef WINCE
-DIRS += wintaskbar
+PARALLEL_DIRS += wintaskbar
 endif
 endif
 
 ifdef MOZ_SAFE_BROWSING
-DIRS += safebrowsing
+PARALLEL_DIRS += safebrowsing
 endif
 
 DIRS += build
 
 ifdef MOZILLA_OFFICIAL
 DEFINES += -DOFFICIAL_BUILD=1
 endif
 
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -505,18 +505,25 @@
             return;
 
           node = node.parentNode;
         }
 #endif
 
         if (window.XULBrowserWindow) {
           var nodeItem = event.target.node;
+
+          var linkURI;
           if (nodeItem && PlacesUtils.nodeIsURI(nodeItem))
-            window.XULBrowserWindow.setOverLink(nodeItem.uri, null);
+            linkURI = nodeItem.uri;
+          else if (node.hasAttribute("targetURI"))
+            linkURI = node.getAttribute("targetURI");
+
+          if (linkURI)
+            window.XULBrowserWindow.setOverLink(linkURI, null);
         }
       ]]></handler>
       <handler event="DOMMenuItemInactive"><![CDATA[
         var node = event.target;
         if (node.parentNode != this)
           return;
 
         if (window.XULBrowserWindow)
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -1193,17 +1193,17 @@ var PlacesUIUtils = {
         return true;
       }
       catch(e) {
         return false;
       }
     }
 
     // Get all items marked as being the left pane folder.
-    let items = as.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO, {});
+    let items = as.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO);
     if (items.length > 1) {
       // Something went wrong, we cannot have more than one left pane folder,
       // remove all left pane folders and continue.  We will create a new one.
       items.forEach(safeRemoveItem);
     }
     else if (items.length == 1 && items[0] != -1) {
       leftPaneRoot = items[0];
 
@@ -1218,17 +1218,17 @@ var PlacesUIUtils = {
 
     if (leftPaneRoot != -1) {
       // A valid left pane folder has been found.
       // Build the leftPaneQueries Map.  This is used to quickly access them,
       // associating a mnemonic name to the real item ids.
       delete this.leftPaneQueries;
       this.leftPaneQueries = {};
 
-      let items = as.getItemsWithAnnotation(ORGANIZER_QUERY_ANNO, {});
+      let items = as.getItemsWithAnnotation(ORGANIZER_QUERY_ANNO);
       // While looping through queries we will also check for their validity.
       let queriesCount = 0;
       for(let i = 0; i < items.length; i++) {
         let queryName = as.getItemAnnotation(items[i], ORGANIZER_QUERY_ANNO);
         // Some extension did use our annotation to decorate their items
         // with icons, so we should check only our elements, to avoid dataloss.
         if (!(queryName in queries))
           continue;
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -69,24 +69,30 @@ String.prototype.hasRootDomain = functio
 ////////////////////////////////////////////////////////////////////////////////
 //// Constants
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
+const STATE_IDLE = 0;
+const STATE_TRANSITION_STARTED = 1;
+const STATE_WAITING_FOR_RESTORE = 2;
+const STATE_RESTORE_FINISHED = 3;
+
 ////////////////////////////////////////////////////////////////////////////////
 //// PrivateBrowsingService
 
 function PrivateBrowsingService() {
   this._obs.addObserver(this, "profile-after-change", true);
   this._obs.addObserver(this, "quit-application-granted", true);
   this._obs.addObserver(this, "private-browsing", true);
   this._obs.addObserver(this, "command-line-startup", true);
+  this._obs.addObserver(this, "sessionstore-browser-state-restored", true);
 }
 
 PrivateBrowsingService.prototype = {
   // Observer Service
   __obs: null,
   get _obs() {
     if (!this.__obs)
       this.__obs = Cc["@mozilla.org/observer-service;1"].
@@ -110,18 +116,18 @@ PrivateBrowsingService.prototype = {
   _savedBrowserState: null,
 
   // Whether we're in the process of shutting down
   _quitting: false,
 
   // How to treat the non-private session
   _saveSession: true,
 
-  // Make sure we don't allow re-enterant changing of the private mode
-  _alreadyChangingMode: false,
+  // The current status of the private browsing service
+  _currentStatus: STATE_IDLE,
 
   // Whether the private browsing mode has been started automatically (ie. always-on)
   _autoStarted: false,
 
   // List of view source window URIs for restoring later
   _viewSrcURLs: [],
 
   // List of nsIXULWindows we are going to be closing during the transition
@@ -229,16 +235,17 @@ PrivateBrowsingService.prototype = {
     // nothing to do here if we're enabling at startup or the current session is being
     // used
     if (!this._autoStarted && this._saveSession) {
       let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                getService(Ci.nsISessionStore);
       // if we have transitioned out of private browsing mode and the session is
       // to be restored, do it now
       if (!this._inPrivateBrowsing) {
+        this._currentStatus = STATE_WAITING_FOR_RESTORE;
         ss.setBrowserState(this._savedBrowserState);
         this._savedBrowserState = null;
 
         this._closePageInfoWindows();
 
         // re-open all view-source windows
         let windowWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                             getService(Ci.nsIWindowWatcher);
@@ -270,21 +277,45 @@ PrivateBrowsingService.prototype = {
               "entries": [{
                 "url": "about:privatebrowsing"
               }]
             }],
             "_closedTabs": []
           }]
         };
         // Transition into private browsing mode
+        this._currentStatus = STATE_WAITING_FOR_RESTORE;
         ss.setBrowserState(JSON.stringify(privateBrowsingState));
       }
     }
   },
 
+  _notifyIfTransitionComplete: function PBS__notifyIfTransitionComplete() {
+    switch (this._currentStatus) {
+      case STATE_TRANSITION_STARTED:
+        // no session store operation was needed, so just notify of transition completion
+      case STATE_RESTORE_FINISHED:
+        // restore has been completed
+        this._currentStatus = STATE_IDLE;
+        this._obs.notifyObservers(null, "private-browsing-transition-complete", "");
+        break;
+      case STATE_WAITING_FOR_RESTORE:
+        // too soon to notify...
+        break;
+      case STATE_IDLE:
+        // no need to notify
+        break;
+      default:
+        // unexpected state observed
+        Cu.reportError("Unexpected private browsing status reached: " +
+                       this._currentStatus);
+        break;
+    }
+  },
+
   _canEnterPrivateBrowsingMode: function PBS__canEnterPrivateBrowsingMode() {
     let cancelEnter = Cc["@mozilla.org/supports-PRBool;1"].
                       createInstance(Ci.nsISupportsPRBool);
     cancelEnter.data = false;
     this._obs.notifyObservers(cancelEnter, "private-browsing-cancel-vote", "enter");
     return !cancelEnter.data;
   },
 
@@ -377,16 +408,22 @@ PrivateBrowsingService.prototype = {
           consoleService.reset();
         }
         break;
       case "command-line-startup":
         this._obs.removeObserver(this, "command-line-startup");
         aSubject.QueryInterface(Ci.nsICommandLine);
         this.handle(aSubject);
         break;
+      case "sessionstore-browser-state-restored":
+        if (this._currentStatus == STATE_WAITING_FOR_RESTORE) {
+          this._currentStatus = STATE_RESTORE_FINISHED;
+          this._notifyIfTransitionComplete();
+        }
+        break;
     }
   },
 
   // nsICommandLineHandler
 
   handle: function PBS_handle(aCmdLine) {
     if (aCmdLine.handleFlag("private", false)) {
       this.privateBrowsingEnabled = true;
@@ -411,21 +448,21 @@ PrivateBrowsingService.prototype = {
    * Enter or leave private browsing mode.
    */
   set privateBrowsingEnabled PBS_set_privateBrowsingEnabled(val) {
     // Allowing observers to set the private browsing status from their
     // notification handlers is not desired, because it will change the
     // status of the service while it's in the process of another transition.
     // So, we detect a reentrant call here and throw an error.
     // This is documented in nsIPrivateBrowsingService.idl.
-    if (this._alreadyChangingMode)
+    if (this._currentStatus != STATE_IDLE)
       throw Cr.NS_ERROR_FAILURE;
 
     try {
-      this._alreadyChangingMode = true;
+      this._currentStatus = STATE_TRANSITION_STARTED;
 
       if (val != this._inPrivateBrowsing) {
         if (val) {
           if (!this._canEnterPrivateBrowsingMode())
             return;
         }
         else {
           if (!this._canLeavePrivateBrowsingMode())
@@ -460,17 +497,17 @@ PrivateBrowsingService.prototype = {
       for (let i = 0; i < this._windowsToClose.length; i++)
         this._windowsToClose[i].docShell.contentViewer.resetCloseWindow();
       // We don't log an error when the transition is canceled from beforeunload
       if (ex != Cr.NS_ERROR_ABORT)
         Cu.reportError("Exception thrown while processing the " +
           "private browsing mode change request: " + ex.toString());
     } finally {
       this._windowsToClose = [];
-      this._alreadyChangingMode = false;
+      this._notifyIfTransitionComplete();
     }
   },
 
   /**
    * Whether private browsing has been started automatically.
    */
   get autoStarted PBS_get_autoStarted() {
     return this._inPrivateBrowsing && this._autoStarted;
--- a/browser/components/privatebrowsing/test/browser/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -45,16 +45,17 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES =  \
 		browser_console_clear.js \
 		browser_privatebrowsing_beforeunload.js \
 		browser_privatebrowsing_certexceptionsui.js \
 		browser_privatebrowsing_crh.js \
 		browser_privatebrowsing_downloadmonitor.js \
+		browser_privatebrowsing_fastswitch.js \
 		browser_privatebrowsing_findbar.js \
 		browser_privatebrowsing_forgetthissite.js \
 		browser_privatebrowsing_geoprompt.js \
 		browser_privatebrowsing_geoprompt_page.html \
 		browser_privatebrowsing_import.js \
 		browser_privatebrowsing_opendir.js \
 		browser_privatebrowsing_openlocation.js \
 		browser_privatebrowsing_pageinfo.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_fastswitch.js
@@ -0,0 +1,90 @@
+/* ***** 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 Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *    Ehsan Akhgari <ehsan@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This test makes sure that users are prevented from toggling the private
+// browsing mode too quickly, hence be proctected from symptoms in bug 526194.
+
+function test() {
+  // initialization
+  let pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  let os = Cc["@mozilla.org/observer-service;1"].
+           getService(Ci.nsIObserverService);
+  let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+           getService(Ci.nsISessionStore);
+  let pbCmd = document.getElementById("Tools:PrivateBrowsing");
+  waitForExplicitFinish();
+
+  let observer = {
+    pass: 1,
+    observe: function(aSubject, aTopic, aData) {
+      switch (aTopic) {
+        case "private-browsing":
+          setTimeout(function() {
+            ok(document.getElementById("Tools:PrivateBrowsing").hasAttribute("disabled"),
+               "The private browsing command should be disabled immediately after the mode switch");
+          }, 0);
+          break;
+
+        case "private-browsing-transition-complete":
+          if (this.pass++ == 1) {
+            setTimeout(function() {
+              ok(!pbCmd.hasAttribute("disabled"),
+                 "The private browsing command should be re-enabled after entering the private browsing mode");
+
+              pb.privateBrowsingEnabled = false;
+            }, 100);
+          }
+          else {
+            setTimeout(function() {
+              ok(!pbCmd.hasAttribute("disabled"),
+                 "The private browsing command should be re-enabled after exiting the private browsing mode");
+
+              os.removeObserver(observer, "private-browsing");
+              os.removeObserver(observer, "private-browsing-transition-complete");
+              finish();
+            }, 100);
+          }
+          break;
+      }
+    }
+  };
+  os.addObserver(observer, "private-browsing", false);
+  os.addObserver(observer, "private-browsing-transition-complete", false);
+
+  pb.privateBrowsingEnabled = true;
+}
--- a/browser/components/privatebrowsing/test/unit/do_test_privatebrowsing_exit.js
+++ b/browser/components/privatebrowsing/test/unit/do_test_privatebrowsing_exit.js
@@ -39,19 +39,16 @@
 // shutdown.
 
 function do_test() {
   // initialization
   var os = Cc["@mozilla.org/observer-service;1"].
            getService(Ci.nsIObserverService);
   var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
            getService(Ci.nsIPrivateBrowsingService);
-  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                   getService(Ci.nsIPrefBranch);
-  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
 
   var expectedQuitting;
   var called = 0;
   var observer = {
     observe: function(aSubject, aTopic, aData) {
       if (aTopic == kPrivateBrowsingNotification &&
           aData == kExit) {
         // increment the call counter
@@ -64,17 +61,16 @@ function do_test() {
           do_throw("aSubject was not null, but wasn't an nsISupportsPRBool");
         }
         // check the "quitting" argument
         do_check_eq(aSubject.data, expectedQuitting);
 
         // finish up the test
         if (expectedQuitting) {
           os.removeObserver(this, kPrivateBrowsingNotification);
-          prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
           do_test_finished();
         }
       }
     }
   };
 
   // set the observer
   os.addObserver(observer, kPrivateBrowsingNotification, false);
--- a/browser/components/privatebrowsing/test/unit/head_privatebrowsing.js
+++ b/browser/components/privatebrowsing/test/unit/head_privatebrowsing.js
@@ -37,16 +37,17 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 const kPrivateBrowsingNotification = "private-browsing";
 const kPrivateBrowsingCancelVoteNotification = "private-browsing-cancel-vote";
+const kPrivateBrowsingTransitionCompleteNotification = "private-browsing-transition-complete";
 const kEnter = "enter";
 const kExit = "exit";
 
 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
 const NS_APP_HISTORY_50_FILE = "UHist";
 
 function LOG(aMsg) {
   aMsg = ("*** PRIVATEBROWSING TESTS: " + aMsg);
@@ -89,16 +90,21 @@ if (!profileDir) {
         return this;
       }
       throw Cr.NS_ERROR_NO_INTERFACE;
     }
   };
   dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
 }
 
+// Do not attempt to restore any session since we don't have any windows
+Cc["@mozilla.org/preferences-service;1"].
+  getService(Ci.nsIPrefBranch).
+  setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
 /**
  * Removes any files that could make our tests fail.
  */
 function cleanUp()
 {
   let files = [
     "downloads.sqlite",
     "places.sqlite",
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/unit/tail_privatebrowsing.js
@@ -0,0 +1,41 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ehsan Akhgari <ehsan@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 ***** */
+
+// Be neat: clear the pref that we have set
+Cc["@mozilla.org/preferences-service;1"].
+  getService(Ci.nsIPrefBranch).
+  clearUserPref("browser.privatebrowsing.keep_current_session");
--- a/browser/components/privatebrowsing/test/unit/test_0-privatebrowsing.js
+++ b/browser/components/privatebrowsing/test/unit/test_0-privatebrowsing.js
@@ -40,19 +40,16 @@
 
 // This test should run before the rest of private browsing service unit tests,
 // hence the naming used for this file.
 
 function run_test_on_service() {
   // initialization
   var os = Cc["@mozilla.org/observer-service;1"].
            getService(Ci.nsIObserverService);
-  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                   getService(Ci.nsIPrefBranch);
-  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
 
   // the contract ID should be available
   do_check_true(PRIVATEBROWSING_CONTRACT_ID in Cc);
 
   // the interface should be available
   do_check_true("nsIPrivateBrowsingService" in Ci);
 
   // it should be possible to initialize the component
@@ -215,15 +212,35 @@ function run_test_on_service() {
       "enter phase 1",
       kPrivateBrowsingNotification + " " + kEnter,
       kPrivateBrowsingCancelVoteNotification + " " + kExit,
       "enter phase 2",
       kPrivateBrowsingNotification + " " + kExit,
     ];
   do_check_eq(observer.notifications.join(","), reference_order.join(","));
 
-  prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
+  // make sure that the private browsing transition complete notification is
+  // raised correctly.
+  observer = {
+    observe: function(aSubject, aTopic, aData) {
+      this.notifications.push(aTopic + " " + aData);
+    },
+    notifications: []
+  };
+  os.addObserver(observer, kPrivateBrowsingNotification, false);
+  os.addObserver(observer, kPrivateBrowsingTransitionCompleteNotification, false);
+  pb.privateBrowsingEnabled = true;
+  pb.privateBrowsingEnabled = false;
+  os.removeObserver(observer, kPrivateBrowsingNotification);
+  os.removeObserver(observer, kPrivateBrowsingTransitionCompleteNotification);
+  reference_order = [
+    kPrivateBrowsingNotification + " " + kEnter,
+    kPrivateBrowsingTransitionCompleteNotification + " ",
+    kPrivateBrowsingNotification + " " + kExit,
+    kPrivateBrowsingTransitionCompleteNotification + " ",
+  ];
+  do_check_eq(observer.notifications.join(","), reference_order.join(","));
 }
 
 // Support running tests on both the service itself and its wrapper
 function run_test() {
   run_test_on_all_services();
 }
--- a/browser/components/privatebrowsing/test/unit/test_aboutprivatebrowsing.js
+++ b/browser/components/privatebrowsing/test/unit/test_aboutprivatebrowsing.js
@@ -58,36 +58,29 @@ function is_about_privatebrowsing_availa
 
   return false;
 }
 
 function run_test_on_service() {
   // initialization
   var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
            getService(Ci.nsIPrivateBrowsingService);
-  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                   getService(Ci.nsIPrefBranch);
-  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
 
-  try {
-    // about:privatebrowsing should be available before entering the private mode
-    do_check_true(is_about_privatebrowsing_available());
+  // about:privatebrowsing should be available before entering the private mode
+  do_check_true(is_about_privatebrowsing_available());
 
-    // enter the private browsing mode
-    pb.privateBrowsingEnabled = true;
+  // enter the private browsing mode
+  pb.privateBrowsingEnabled = true;
 
-    // about:privatebrowsing should be available inside the private mode
-    do_check_true(is_about_privatebrowsing_available());
-
-    // exit the private browsing mode
-    pb.privateBrowsingEnabled = false;
+  // about:privatebrowsing should be available inside the private mode
+  do_check_true(is_about_privatebrowsing_available());
 
-    // about:privatebrowsing should be available after leaving the private mode
-    do_check_true(is_about_privatebrowsing_available());
-  } finally {
-    prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
-  }
+  // exit the private browsing mode
+  pb.privateBrowsingEnabled = false;
+
+  // about:privatebrowsing should be available after leaving the private mode
+  do_check_true(is_about_privatebrowsing_available());
 }
 
 // Support running tests on both the service itself and its wrapper
 function run_test() {
   run_test_on_all_services();
 }
--- a/browser/components/privatebrowsing/test/unit/test_httpauth.js
+++ b/browser/components/privatebrowsing/test/unit/test_httpauth.js
@@ -34,20 +34,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // This test makes sure the HTTP authenticated sessions are correctly cleared
 // when entering and leaving the private browsing mode.
 
 function run_test_on_service() {
-  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                   getService(Ci.nsIPrefBranch);
-  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-
   var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
            getService(Ci.nsIPrivateBrowsingService);
 
   var am = Cc["@mozilla.org/network/http-auth-manager;1"].
            getService(Ci.nsIHttpAuthManager);
 
   const kHost1 = "pbtest3.example.com";
   const kHost2 = "pbtest4.example.com";
@@ -103,17 +99,15 @@ function run_test_on_service() {
       do_throw("Auth entry should not be retrievable after exiting the private browsing mode");
     } catch (e) {
       do_check_eq(domain.value, kEmpty);
       do_check_eq(user.value, kEmpty);
       do_check_eq(pass.value, kEmpty);
     }
   } catch (e) {
     do_throw("Unexpected exception while testing HTTP auth manager: " + e);
-  } finally {
-    prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
   }
 }
 
 // Support running tests on both the service itself and its wrapper
 function run_test() {
   run_test_on_all_services();
 }
--- a/browser/components/privatebrowsing/test/unit/test_openLocationLastURL.js
+++ b/browser/components/privatebrowsing/test/unit/test_openLocationLastURL.js
@@ -38,16 +38,23 @@
 
 function run_test_on_service()
 {
   let Cc = Components.classes;
   let Ci = Components.interfaces;
   let Cu = Components.utils;
   Cu.import("resource:///modules/openLocationLastURL.jsm");
 
+  function clearHistory() {
+    // simulate clearing the private data
+    Cc["@mozilla.org/observer-service;1"].
+    getService(Ci.nsIObserverService).
+    notifyObservers(null, "browser:purge-session-history", "");
+  }
+
   let pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
            getService(Ci.nsIPrivateBrowsingService);
   let pref = Cc["@mozilla.org/preferences-service;1"].
              getService(Ci.nsIPrefBranch);
   gOpenLocationLastURL.reset();
 
   do_check_eq(typeof gOpenLocationLastURL, "object");
   do_check_eq(gOpenLocationLastURL.value, "");
@@ -59,26 +66,39 @@ function run_test_on_service()
   do_check_eq(gOpenLocationLastURL.value, url1);
 
   gOpenLocationLastURL.value = "";
   do_check_eq(gOpenLocationLastURL.value, "");
 
   gOpenLocationLastURL.value = url2;
   do_check_eq(gOpenLocationLastURL.value, url2);
 
+  clearHistory();
+  do_check_eq(gOpenLocationLastURL.value, "");
+  gOpenLocationLastURL.value = url2;
+
   pb.privateBrowsingEnabled = true;
   do_check_eq(gOpenLocationLastURL.value, "");
 
   pb.privateBrowsingEnabled = false;
   do_check_eq(gOpenLocationLastURL.value, url2);
   pb.privateBrowsingEnabled = true;
 
   gOpenLocationLastURL.value = url1;
   do_check_eq(gOpenLocationLastURL.value, url1);
 
   pb.privateBrowsingEnabled = false;
   do_check_eq(gOpenLocationLastURL.value, url2);
+
+  pb.privateBrowsingEnabled = true;
+  gOpenLocationLastURL.value = url1;
+  do_check_neq(gOpenLocationLastURL.value, "");
+  clearHistory();
+  do_check_eq(gOpenLocationLastURL.value, "");
+
+  pb.privateBrowsingEnabled = false;
+  do_check_eq(gOpenLocationLastURL.value, "");
 }
 
 // Support running tests on both the service itself and its wrapper
 function run_test() {
   run_test_on_all_services();
 }
--- a/browser/components/privatebrowsing/test/unit/test_transition_nooffline.js
+++ b/browser/components/privatebrowsing/test/unit/test_transition_nooffline.js
@@ -39,19 +39,16 @@
 // the offline status (see bug 463256).
 
 function run_test_on_service() {
   // initialization
   var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
            getService(Ci.nsIPrivateBrowsingService);
   var os = Cc["@mozilla.org/observer-service;1"].
            getService(Ci.nsIObserverService);
-  var prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                   getService(Ci.nsIPrefBranch);
-  prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
 
   var observer = {
     observe: function (aSubject, aTopic, aData) {
       if (aTopic == "network:offline-status-changed")
         this.events.push(aData);
     },
     events: []
   };
@@ -61,15 +58,14 @@ function run_test_on_service() {
   pb.privateBrowsingEnabled = true;
   do_check_eq(observer.events.length, 0);
 
   // leave the private browsing mode, and wait for the SSL page to load again
   pb.privateBrowsingEnabled = false;
   do_check_eq(observer.events.length, 0);
 
   os.removeObserver(observer, "network:offline-status-changed", false);
-  prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
 }
 
 // Support running tests on both the service itself and its wrapper
 function run_test() {
   run_test_on_all_services();
 }
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -105,16 +105,20 @@ eg: browser.docShell["allow" + aCapabili
 XXX keep these in sync with all the attributes starting
     with "allow" in /docshell/base/nsIDocShell.idl
 */
 const CAPABILITIES = [
   "Subframes", "Plugins", "Javascript", "MetaRedirects", "Images",
   "DNSPrefetch", "Auth"
 ];
 
+#ifndef XP_WIN
+#define BROKEN_WM_Z_ORDER
+#endif
+
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function debug(aMsg) {
   aMsg = ("SessionStore: " + aMsg).replace(/\S{80}/g, "$&\n");
   Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
                                      .logStringMessage(aMsg);
 }
 
@@ -177,16 +181,19 @@ SessionStoreService.prototype = {
   _recentCrashes: 0,
 
   // whether we are in private browsing mode
   _inPrivateBrowsing: false,
 
   // whether we clearing history on shutdown
   _clearingOnShutdown: false,
 
+  // List of windows that are being closed during setBrowserState.
+  _closingWindows: [],
+
 #ifndef XP_MACOSX
   // whether the last window was closed and should be restored
   _restoreLastWindow: false,
 #endif
 
 /* ........ Global Event Handlers .............. */
 
   /**
@@ -331,16 +338,24 @@ SessionStoreService.prototype = {
     switch (aTopic) {
     case "domwindowopened": // catch new windows
       aSubject.addEventListener("load", function(aEvent) {
         aEvent.currentTarget.removeEventListener("load", arguments.callee, false);
         _this.onLoad(aEvent.currentTarget);
         }, false);
       break;
     case "domwindowclosed": // catch closed windows
+      if (this._closingWindows.length > 0) {
+        let index = this._closingWindows.indexOf(aSubject);
+        if (index != -1) {
+          this._closingWindows.splice(index, 1);
+          if (this._closingWindows.length == 0)
+            this._sendRestoreCompletedNotifications(true);
+        }
+      }
       this.onClose(aSubject);
       break;
     case "quit-application-requested":
       // get a current snapshot of all windows
       this._forEachBrowserWindow(function(aWindow) {
         this._collectWindowData(aWindow);
       });
       this._dirtyWindows = [];
@@ -895,29 +910,31 @@ SessionStoreService.prototype = {
 
     var window = this._getMostRecentBrowserWindow();
     if (!window) {
       this._restoreCount = 1;
       this._openWindowWithState(state);
       return;
     }
 
-    // close all other browser windows
-    this._forEachBrowserWindow(function(aWindow) {
-      if (aWindow != window) {
-        aWindow.close();
-      }
-    });
-
     // make sure closed window data isn't kept
     this._closedWindows = [];
 
     // determine how many windows are meant to be restored
     this._restoreCount = state.windows ? state.windows.length : 0;
 
+    var self = this;
+    // close all other browser windows
+    this._forEachBrowserWindow(function(aWindow) {
+      if (aWindow != window) {
+        self._closingWindows.push(aWindow);
+        aWindow.close();
+      }
+    });
+
     // restore to the given state
     this.restoreWindow(window, state, true);
   },
 
   getWindowState: function sss_getWindowState(aWindow) {
     if (!aWindow.__SSi && !aWindow.__SS_dyingCache)
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
     
@@ -1186,25 +1203,26 @@ SessionStoreService.prototype = {
       if (!aFullData)
         browser.__SS_data = tabData;
     }
     else if (browser.currentURI.spec != "about:blank" ||
              browser.contentDocument.body.hasChildNodes()) {
       tabData.entries[0] = { url: browser.currentURI.spec };
       tabData.index = 1;
     }
-    else if (browser.currentURI.spec == "about:blank" &&
-             browser.userTypedValue) {
-      // This can happen if the user opens a lot of tabs simultaneously and we
-      // try to save state before all of them are properly loaded. If we crash
-      // then we get a bunch of about:blank tabs which isn't what we want.
-      tabData.entries[0] = { url: browser.userTypedValue };
-      tabData.index = 1;
+
+    // If there is a userTypedValue set, then either the user has typed something
+    // in the URL bar, or a new tab was opened with a URI to load. userTypedClear
+    // is used to indicate whether the tab was in some sort of loading state with
+    // userTypedValue.
+    if (browser.userTypedValue) {
+      tabData.userTypedValue = browser.userTypedValue;
+      tabData.userTypedClear = browser.userTypedClear;
     }
-    
+
     var disallow = [];
     for (var i = 0; i < CAPABILITIES.length; i++)
       if (!browser.docShell["allow" + CAPABILITIES[i]])
         disallow.push(CAPABILITIES[i]);
     if (disallow.length > 0)
       tabData.disallow = disallow.join(",");
     else if (tabData.disallow)
       delete tabData.disallow;
@@ -2117,17 +2135,25 @@ SessionStoreService.prototype = {
       // (mainly scroll state and text data)
       browser.__SS_restore_data = tabData.entries[activeIndex] || {};
       browser.__SS_restore_text = tabData.text || "";
       browser.__SS_restore_pageStyle = tabData.pageStyle || "";
       browser.__SS_restore_tab = tab;
       browser.__SS_restore = this.restoreDocument_proxy;
       browser.addEventListener("load", browser.__SS_restore, true);
     }
-    
+
+    // Handle userTypedValue. Setting userTypedValue seems to update gURLbar
+    // as needed. Calling loadURI will cancel form filling in restoreDocument_proxy
+    if (tabData.userTypedValue) {
+      browser.userTypedValue = tabData.userTypedValue;
+      if (tabData.userTypedClear)
+        browser.loadURI(tabData.userTypedValue, null, null, true);
+    }
+
     aWindow.setTimeout(function(){ _this.restoreHistory(aWindow, aTabs, aTabData, aIdMap); }, 0);
   },
 
   /**
    * expands serialized history data into a session-history-entry instance
    * @param aEntry
    *        Object containing serialized history data for a URL
    * @param aIdMap
@@ -2593,30 +2619,55 @@ SessionStoreService.prototype = {
    */
   _forEachBrowserWindow: function sss_forEachBrowserWindow(aFunc) {
     var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
                          getService(Ci.nsIWindowMediator);
     var windowsEnum = windowMediator.getEnumerator("navigator:browser");
     
     while (windowsEnum.hasMoreElements()) {
       var window = windowsEnum.getNext();
-      if (window.__SSi) {
+      if (window.__SSi && !window.closed) {
         aFunc.call(this, window);
       }
     }
   },
 
   /**
    * Returns most recent window
    * @returns Window reference
    */
   _getMostRecentBrowserWindow: function sss_getMostRecentBrowserWindow() {
-    var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
-                         getService(Ci.nsIWindowMediator);
-    return windowMediator.getMostRecentWindow("navigator:browser");
+    var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
+             getService(Ci.nsIWindowMediator);
+
+    var win = wm.getMostRecentWindow("navigator:browser");
+    if (!win)
+      return null;
+    if (!win.closed)
+      return win;
+
+#ifdef BROKEN_WM_Z_ORDER
+    win = null;
+    var windowsEnum = wm.getEnumerator("navigator:browser");
+    // this is oldest to newest, so this gets a bit ugly
+    while (windowsEnum.hasMoreElements()) {
+      let nextWin = windowsEnum.getNext();
+      if (!nextWin.closed)
+        win = nextWin;
+    }
+    return win;
+#else
+    var windowsEnum = wm.getZOrderDOMWindowEnumerator("navigator:browser", true);
+    while (windowsEnum.hasMoreElements()) {
+      win = windowsEnum.getNext();
+      if (!win.closed)
+        return win;
+    }
+    return null;
+#endif
   },
 
   /**
    * open a new browser window for a given session state
    * called when restoring a multi-window session
    * @param aState
    *        Object containing session data
    */
@@ -2820,26 +2871,27 @@ SessionStoreService.prototype = {
       // instead of evalInSandbox everywhere
       jsonString = jsonString.replace(/[\u2028\u2029]/g,
                                       function($0) "\\u" + $0.charCodeAt(0).toString(16));
     }
     
     return jsonString;
   },
 
-  _sendRestoreCompletedNotifications: function sss_sendRestoreCompletedNotifications() {
-    if (this._restoreCount) {
+  _sendRestoreCompletedNotifications:
+  function sss_sendRestoreCompletedNotifications(aOnWindowClose) {
+    if (this._restoreCount && !aOnWindowClose)
       this._restoreCount--;
-      if (this._restoreCount == 0) {
-        // This was the last window restored at startup, notify observers.
-        this._observerService.notifyObservers(null,
-          this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED,
-          "");
-        this._browserSetState = false;
-      }
+
+    if (this._restoreCount == 0 && this._closingWindows.length == 0) {
+      // This was the last window restored at startup, notify observers.
+      this._observerService.notifyObservers(null,
+        this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED,
+        "");
+      this._browserSetState = false;
     }
   },
 
   /**
    * @param aWindow
    *        Window reference
    * @returns whether this window's data is still cached in _statesToRestore
    *          because it's not fully loaded yet
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -40,19 +40,16 @@ DEPTH		= ../../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = browser/components/sessionstore/test/browser 
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-# browser_477657.js is disabled, because it's unreliable (bug 482975).
-# browser_480148.js is disabled, because it breaks browser_420786.js (see bug 483382).
-
 _BROWSER_TEST_FILES = \
 	browser_248970_a.js \
 	browser_248970_b.js \
 	browser_248970_b_sample.html \
 	browser_339445.js \
 	browser_339445_sample.html \
 	browser_345898.js \
 	browser_346337.js \
@@ -92,24 +89,27 @@ include $(topsrcdir)/config/rules.mk
 	browser_464620_b.html \
 	browser_464620_xd.html \
 	browser_465215.js \
 	browser_465223.js \
 	browser_466937.js \
 	browser_466937_sample.html \
 	browser_476161.js \
 	browser_476161_sample.html \
+	browser_477657.js \
+	browser_480148.js \
 	browser_480893.js \
 	browser_483330.js \
 	browser_485482.js \
 	browser_485482_sample.html \
 	browser_485563.js \
 	browser_490040.js \
 	browser_491168.js \
 	browser_491577.js \
 	browser_493467.js \
 	browser_495495.js \
 	browser_514751.js \
+	browser_522545.js \
 	browser_526613.js \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/components/sessionstore/test/browser/browser_354894.js
+++ b/browser/components/sessionstore/test/browser/browser_354894.js
@@ -99,17 +99,32 @@
  * @note Mac only tests the new notifications, as restoring the last window is
  * not enabled on that platform (platform shim; the application is kept running
  * although there are no windows left)
  * @note There is a difference when closing a browser window with
  * BrowserTryToCloseWindow() as opposed to close(). The former will make
  * nsSessionStore restore a window next time it gets a chance and will post
  * notifications. The latter won't.
  */
+
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
+
   waitForExplicitFinish();
 
   // Some urls that might be opened in tabs and/or popups
   // Do not use about:blank:
   // That one is reserved for special purposes in the tests
   const TEST_URLS = ["about:mozilla", "about:buildconfig"];
 
   // Number of -request notifications to except
@@ -212,19 +227,19 @@ function test() {
     setPrefs();
 
     // Prepare a window; open it and add more tabs
     let newWin = openDialog(location, "_blank", CHROME_FEATURES, "about:config");
     newWin.addEventListener("load", function(aEvent) {
       newWin.removeEventListener("load", arguments.callee, false);
       newWin.gBrowser.addEventListener("load", function(aEvent) {
         newWin.gBrowser.removeEventListener("load", arguments.callee, true);
-        for each (let url in TEST_URLS) {
+        TEST_URLS.forEach(function (url) {
           newWin.gBrowser.addTab(url);
-        }
+        });
 
         executeSoon(function() testFn(newWin));
       }, true);
     }, false);
   }
 
   /**
    * Test 1: Normal in-session restore
@@ -493,29 +508,37 @@ function test() {
 
   // Execution starts here
 
   setupTestsuite();
   if (navigator.platform.match(/Mac/)) {
     // Mac tests
     testMacNotifications(
       function() testNotificationCount(
-        function() cleanupTestsuite() + finish()
+        function() {
+          cleanupTestsuite();
+          is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
+          finish();
+        }
       )
     );
   }
   else {
     // Non-Mac Tests
     testOpenCloseNormal(
       function() testOpenClosePrivateBrowsing(
         function() testOpenCloseWindowAndPopup(
           function() testOpenCloseOnlyPopup(
             function() testOpenCloseRestoreFromPopup (
               function() testNotificationCount(
-                function() cleanupTestsuite() + finish()
+                function() {
+                  cleanupTestsuite();
+                  is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
+                  finish();
+                }
               )
             )
           )
         )
       )
     );
   }
 }
--- a/browser/components/sessionstore/test/browser/browser_394759.js
+++ b/browser/components/sessionstore/test/browser/browser_394759.js
@@ -30,16 +30,28 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 394759 **/
   
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   let pb = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService);
   waitForExplicitFinish();
   
@@ -51,19 +63,18 @@ function test() {
     let uniqueText = "pi != " + Math.random();
   
   
     // make sure that the next closed window will increase getClosedWindowCount
     let max_windows_undo = gPrefService.getIntPref("browser.sessionstore.max_windows_undo");
     gPrefService.setIntPref("browser.sessionstore.max_windows_undo", max_windows_undo + 1);
     let closedWindowCount = ss.getClosedWindowCount();
   
-    let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", testURL);
+    let newWin = openDialog(location, "", "chrome,all,dialog=no", testURL);
     newWin.addEventListener("load", function(aEvent) {
-      newWin.removeEventListener("load", arguments.callee, false);
       newWin.gBrowser.addEventListener("load", function(aEvent) {
         newWin.gBrowser.removeEventListener("load", arguments.callee, true);
 
         executeSoon(function() {
           newWin.gBrowser.addTab().linkedBrowser.stop();
           executeSoon(function() {
             // mark the window with some unique data to be restored later on
             ss.setWindowValue(newWin, uniqueKey, uniqueValue);
@@ -82,17 +93,16 @@ function test() {
             let newWin2 = ss.undoCloseWindow(0);
 
             ok(newWin2 instanceof ChromeWindow,
                "undoCloseWindow actually returned a window");
             is(ss.getClosedWindowCount(), closedWindowCount,
                "The reopened window was removed from Recently Closed Windows");
 
             newWin2.addEventListener("load", function(aEvent) {
-              this.removeEventListener("load", arguments.callee, false);
               newWin2.gBrowser.addEventListener("SSTabRestored", function(aEvent) {
                 newWin2.gBrowser.removeEventListener("SSTabRestored", arguments.callee, true);
 
                 is(newWin2.gBrowser.tabContainer.childNodes.length, 2,
                    "The window correctly restored 2 tabs");
                 is(newWin2.gBrowser.currentURI.spec, testURL,
                    "The window correctly restored the URL");
 
@@ -137,28 +147,27 @@ function test() {
         executeSoon(recCallback);
         return;
       }
       // hack to force window to be considered a popup (toolbar=no didn't work)
       let winData = windowsToOpen.shift();
       let settings = "chrome,dialog=no," +
                      (winData.isPopup ? "all=no" : "all");
       let url = "http://window" + windowsToOpen.length + ".example.com";
-      let window = openDialog(location, "_blank", settings, url);
-      window.addEventListener("load", function(aEvent) {
-        this.removeEventListener("load", arguments.callee, true);
-        window.gBrowser.addEventListener("load", function(aEvent) {
-          this.removeEventListener("load", arguments.callee, true);
+      let win = openDialog(location, "", settings, url);
+      win.addEventListener("load", function(aEvent) {
+        win.gBrowser.addEventListener("load", function(aEvent) {
+          win.gBrowser.removeEventListener("load", arguments.callee, true);
           // the window _should_ have state with a tab of url, but it doesn't
           // always happend before window.close(). addTab ensure we don't treat
           // this window as a stateless window
-          window.gBrowser.addTab();
+          win.gBrowser.addTab();
 
           executeSoon(function() {
-            window.close();
+            win.close();
             executeSoon(function() {
               openWindowRec(windowsToOpen, expectedResults, recCallback);
             });
           });
         }, true);
       }, true);
     }
 
@@ -186,16 +195,22 @@ function test() {
     function countClosedTabsByTitle(aClosedTabList, aTitle)
       aClosedTabList.filter(function(aData) aData.title == aTitle).length;
 
     function countOpenTabsByTitle(aOpenTabList, aTitle)
       aOpenTabList.filter(function(aData) aData.entries.some(function(aEntry) aEntry.title == aTitle) ).length
 
     // backup old state
     let oldState = ss.getBrowserState();
+    let oldState_wins = JSON.parse(oldState).windows.length;
+    if (oldState_wins != 1) {
+      ok(false, "oldState in test_purge has " + oldState_wins + " windows instead of 1");
+      info(oldState);
+    }
+
     // create a new state for testing
     const REMEMBER = Date.now(), FORGET = Math.random();
     let testState = {
       windows: [ { tabs: [{ entries: [{ url: "http://example.com/" }] }], selected: 1 } ],
       _closedWindows : [
         // _closedWindows[0]
         {
           tabs: [
@@ -252,47 +267,51 @@ function test() {
     ss.setBrowserState(JSON.stringify(testState));
 
     // purge domain & check that we purged correctly for closed windows
     pb.removeDataFromDomain("mozilla.org");
 
     let closedWindowData = JSON.parse(ss.getClosedWindowData());
 
     // First set of tests for _closedWindows[0] - tests basics
-    let window = closedWindowData[0];
-    is(window.tabs.length, 1, "1 tab was removed");
-    is(countOpenTabsByTitle(window.tabs, FORGET), 0,
+    let win = closedWindowData[0];
+    is(win.tabs.length, 1, "1 tab was removed");
+    is(countOpenTabsByTitle(win.tabs, FORGET), 0,
        "The correct tab was removed");
-    is(countOpenTabsByTitle(window.tabs, REMEMBER), 1,
+    is(countOpenTabsByTitle(win.tabs, REMEMBER), 1,
        "The correct tab was remembered");
-    is(window.selected, 1, "Selected tab has changed");
-    is(window.title, REMEMBER, "The window title was correctly updated");
+    is(win.selected, 1, "Selected tab has changed");
+    is(win.title, REMEMBER, "The window title was correctly updated");
 
     // Test more complicated case 
-    window = closedWindowData[1];
-    is(window.tabs.length, 3, "2 tabs were removed");
-    is(countOpenTabsByTitle(window.tabs, FORGET), 0,
+    win = closedWindowData[1];
+    is(win.tabs.length, 3, "2 tabs were removed");
+    is(countOpenTabsByTitle(win.tabs, FORGET), 0,
        "The correct tabs were removed");
-    is(countOpenTabsByTitle(window.tabs, REMEMBER), 3,
+    is(countOpenTabsByTitle(win.tabs, REMEMBER), 3,
        "The correct tabs were remembered");
-    is(window.selected, 3, "Selected tab has changed");
-    is(window.title, REMEMBER, "The window title was correctly updated");
+    is(win.selected, 3, "Selected tab has changed");
+    is(win.title, REMEMBER, "The window title was correctly updated");
 
     // Tests handling of _closedTabs
-    window = closedWindowData[2];
-    is(countClosedTabsByTitle(window._closedTabs, REMEMBER), 1,
+    win = closedWindowData[2];
+    is(countClosedTabsByTitle(win._closedTabs, REMEMBER), 1,
        "The correct number of tabs were removed, and the correct ones");
-    is(countClosedTabsByTitle(window._closedTabs, FORGET), 0,
+    is(countClosedTabsByTitle(win._closedTabs, FORGET), 0,
        "All tabs to be forgotten were indeed removed");
 
     // restore pre-test state
     ss.setBrowserState(oldState);
     executeSoon(callback);
   }
   
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
   test_basic(function() {
+    is(browserWindowsCount(), 1, "number of browser windows after test_basic");
     test_behavior(function() {
+      is(browserWindowsCount(), 1, "number of browser windows after test_behavior");
       test_purge(function() {
+        is(browserWindowsCount(), 1, "number of browser windows after test_purge");
         finish();
       });
     });
   });
 }
--- a/browser/components/sessionstore/test/browser/browser_394759_privatebrowsing.js
+++ b/browser/components/sessionstore/test/browser/browser_394759_privatebrowsing.js
@@ -32,18 +32,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Private Browsing Test for Bug 394759 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
 
   waitForExplicitFinish();
 
   // Set interval to a large time so state won't be written while we setup env.
   gPrefService.setIntPref("browser.sessionstore.interval", 100000);
 
   // Set up the browser in a blank state. Popup windows in previous tests result
   // in different states on different platforms.
@@ -80,18 +93,16 @@ function test() {
   info("sessionstore.js was correctly removed: " + (!sessionStoreJS.exists()));
 
   // Make sure that sessionstore.js can be forced to be created by setting
   // the interval pref to 0.
   gPrefService.setIntPref("browser.sessionstore.interval", 0);
 }
 
 function continue_test() {
-  let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
-           getService(Ci.nsIWindowWatcher);
   let pb = Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
   // Ensure Private Browsing mode is disabled.
   ok(!pb.privateBrowsingEnabled, "Private Browsing is disabled");
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
 
   let closedWindowCount = ss.getClosedWindowCount();
@@ -103,31 +114,24 @@ function continue_test() {
     { url: "about:config",
       key: "bug 394759 Non-PB",
       value: "uniq" + (++now) },
     { url: "about:mozilla",
       key: "bug 394759 PB",
       value: "uniq" + (++now) },
   ];
 
-  let loadWasCalled = false;
   function openWindowAndTest(aTestIndex, aRunNextTestInPBMode) {
     info("Opening new window");
-    let windowObserver = {
-      observe: function(aSubject, aTopic, aData) {
-        if (aTopic === "domwindowopened") {
-          info("New window has been opened");
-          let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
-          win.addEventListener("load", function onLoad(event) {
+    function onLoad(event) {
             win.removeEventListener("load", onLoad, false);
             info("New window has been loaded");
             win.gBrowser.addEventListener("load", function(aEvent) {
               win.gBrowser.removeEventListener("load", arguments.callee, true);
               info("New window browser has been loaded");
-              loadWasCalled = true;
               executeSoon(function() {
                 // Add a tab.
                 win.gBrowser.addTab();
 
                 executeSoon(function() {
                   // Mark the window with some unique data to be restored later on.
                   ss.setWindowValue(win, TESTS[aTestIndex].key, TESTS[aTestIndex].value);
 
@@ -167,36 +171,26 @@ function continue_test() {
                     ok(data.toSource().indexOf(TESTS[aTestIndex - 1].value) > -1,
                        "The data associated with the recently closed window was " +
                        "restored when exiting PB mode");
                   }
 
                   if (aTestIndex == TESTS.length - 1) {
                     if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
                       gPrefService.clearUserPref("browser.sessionstore.interval");
+                    is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
                     finish();
                   }
                   else {
                     // Run next test.
                     openWindowAndTest(aTestIndex + 1, !aRunNextTestInPBMode);
                   }
                 });
               });
             }, true);
-          }, false);
-        }
-        else if (aTopic === "domwindowclosed") {
-          info("Window closed");
-          ww.unregisterNotification(this);
-          if (!loadWasCalled) {
-            ok(false, "Window was closed before load could fire!");
-            finish();
-          }
-        }
-      }
-    };
-    ww.registerNotification(windowObserver);
+    }
     // Open a window.
-    openDialog(location, "_blank", "chrome,all,dialog=no", TESTS[aTestIndex].url);
+    var win = openDialog(location, "", "chrome,all,dialog=no", TESTS[aTestIndex].url);
+    win.addEventListener("load", onLoad, false);
   }
 
   openWindowAndTest(0, true);
 }
--- a/browser/components/sessionstore/test/browser/browser_408470.js
+++ b/browser/components/sessionstore/test/browser/browser_408470.js
@@ -40,26 +40,26 @@ function test() {
   waitForExplicitFinish();
   
   let pendingCount = 1;
   let testUrl = "chrome://mochikit/content/browser/" +
     "browser/components/sessionstore/test/browser/browser_408470_sample.html";
   let tab = gBrowser.addTab(testUrl);
   
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     // enable all stylesheets and verify that they're correctly persisted
     Array.forEach(tab.linkedBrowser.contentDocument.styleSheets, function(aSS, aIx) {
       pendingCount++;
       let ssTitle = aSS.title;
       stylesheetSwitchAll(tab.linkedBrowser.contentWindow, ssTitle);
       
       let newTab = gBrowser.duplicateTab(tab);
       newTab.linkedBrowser.addEventListener("load", function(aEvent) {
-        this.removeEventListener("load", arguments.callee, true);
+        newTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
         let states = Array.map(newTab.linkedBrowser.contentDocument.styleSheets,
                                function(aSS) !aSS.disabled);
         let correct = states.indexOf(true) == aIx && states.indexOf(true, aIx + 1) == -1;
         
         if (/^fail_/.test(ssTitle))
           ok(!correct, "didn't restore stylesheet " + ssTitle);
         else
           ok(correct, "restored stylesheet " + ssTitle);
@@ -69,17 +69,17 @@ function test() {
           finish();
       }, true);
     });
     
     // disable all styles and verify that this is correctly persisted
     tab.linkedBrowser.markupDocumentViewer.authorStyleDisabled = true;
     let newTab = gBrowser.duplicateTab(tab);
     newTab.linkedBrowser.addEventListener("load", function(aEvent) {
-      this.removeEventListener("load", arguments.callee, true);
+      newTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
       is(newTab.linkedBrowser.markupDocumentViewer.authorStyleDisabled, true,
          "disabled all stylesheets");
       
       gBrowser.removeTab(newTab);
       if (--pendingCount == 0)
         finish();
     }, true);
     
--- a/browser/components/sessionstore/test/browser/browser_423132.js
+++ b/browser/components/sessionstore/test/browser/browser_423132.js
@@ -29,19 +29,32 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   // test that cookies are stored and restored correctly by sessionstore,
   // bug 423132.
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
 
   // test setup
   waitForExplicitFinish();
 
   let cs = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
   cs.removeAll();
 
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
@@ -96,13 +109,14 @@ function test() {
       is(cookie.value, cookie2.value, "cookie value successfully restored");
       is(cookie.path, cookie2.path, "cookie path successfully restored");
 
       // clean up
       if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
         gPrefService.clearUserPref("browser.sessionstore.interval");
       cs.removeAll();
       newWin.close();
+      is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
       finish();
     }, true);
   }, false);
 }
 
--- a/browser/components/sessionstore/test/browser/browser_447951.js
+++ b/browser/components/sessionstore/test/browser/browser_447951.js
@@ -40,26 +40,26 @@ function test() {
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   const baseURL = "http://localhost:8888/browser/" +
     "browser/components/sessionstore/test/browser/browser_447951_sample.html#";
     
   let tab = gBrowser.addTab();
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     
     let tabState = { entries: [] };
     let max_entries = gPrefService.getIntPref("browser.sessionhistory.max_entries");
     for (let i = 0; i < max_entries; i++)
       tabState.entries.push({ url: baseURL + i });
     
     ss.setTabState(tab, JSON.stringify(tabState));
     tab.addEventListener("SSTabRestored", function(aEvent) {
-      this.removeEventListener("SSTabRestored", arguments.callee, false);
+      tab.removeEventListener("SSTabRestored", arguments.callee, false);
       tabState = eval("(" + ss.getTabState(tab) + ")");
       is(tabState.entries.length, max_entries, "session history filled to the limit");
       is(tabState.entries[0].url, baseURL + 0, "... but not more");
       
       // visit yet another anchor (appending it to session history)
       let doc = tab.linkedBrowser.contentDocument;
       let event = doc.createEvent("MouseEvents");
       event.initMouseEvent("click", true, true, doc.defaultView, 1,
--- a/browser/components/sessionstore/test/browser/browser_448741.js
+++ b/browser/components/sessionstore/test/browser/browser_448741.js
@@ -55,25 +55,25 @@ function test() {
   let cleaningObserver = {
     observe: function(aSubject, aTopic, aData) {
       ok(aTopic == "sessionstore-state-write", "observed correct topic?");
       ok(aSubject instanceof Ci.nsISupportsString, "subject is a string?");
       ok(aSubject.data.indexOf(uniqueValue) > -1, "data contains our value?");
       
       // find the data for the newly added tab and delete it
       let state = eval(aSubject.data);
-      for each (let winData in state.windows) {
-        for each (let tabData in winData.tabs) {
+      state.windows.forEach(function (winData) {
+        winData.tabs.forEach(function (tabData) {
           if (tabData.extData && uniqueName in tabData.extData &&
               tabData.extData[uniqueName] == uniqueValue) {
             delete tabData.extData[uniqueName];
             valueWasCleaned = true;
           }
-        }
-      }
+        });
+      });
       
       ok(valueWasCleaned, "found and removed the specific tab value");
       aSubject.data = uneval(state);
       os.removeObserver(this, aTopic, false);
     }
   };
   
   // make sure that all later observers don't see that value any longer
--- a/browser/components/sessionstore/test/browser/browser_454908.js
+++ b/browser/components/sessionstore/test/browser/browser_454908.js
@@ -46,26 +46,26 @@ function test() {
   
   // make sure we do save form data
   gPrefService.setIntPref("browser.sessionstore.privacy_level", 0);
   
   let testURL = "chrome://mochikit/content/browser/" +
     "browser/components/sessionstore/test/browser/browser_454908_sample.html";
   let tab = gBrowser.addTab(testURL);
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     let doc = tab.linkedBrowser.contentDocument;
     for (let id in fieldValues)
       doc.getElementById(id).value = fieldValues[id];
     
     gBrowser.removeTab(tab);
     
     tab = undoCloseTab();
     tab.linkedBrowser.addEventListener("load", function(aEvent) {
-      this.removeEventListener("load", arguments.callee, true);
+      tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
       let doc = tab.linkedBrowser.contentDocument;
       for (let id in fieldValues) {
         let node = doc.getElementById(id);
         if (node.type == "password")
           is(node.value, "", "password wasn't saved/restored");
         else
           is(node.value, fieldValues[id], "username was saved/restored");
       }
--- a/browser/components/sessionstore/test/browser/browser_459906.js
+++ b/browser/components/sessionstore/test/browser/browser_459906.js
@@ -31,63 +31,55 @@
  * 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 ***** */
 
 function test() {
   /** Test for Bug 459906 **/
-  
+
   waitForExplicitFinish();
-  
+
   let testURL = "http://localhost:8888/browser/" +
     "browser/components/sessionstore/test/browser/browser_459906_sample.html";
   let uniqueValue = "<b>Unique:</b> " + Date.now();
-  
+
   var frameCount = 0;
   let tab = gBrowser.addTab(testURL);
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
     // wait for all frames to load completely
     if (frameCount++ < 2)
       return;
-    this.removeEventListener("load", arguments.callee, true);
-    
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+
     let iframes = tab.linkedBrowser.contentWindow.frames;
     iframes[1].document.body.innerHTML = uniqueValue;
-    
+
     frameCount = 0;
     let tab2 = gBrowser.duplicateTab(tab);
     tab2.linkedBrowser.addEventListener("load", function(aEvent) {
       // wait for all frames to load (and reload!) completely
       if (frameCount++ < 2)
         return;
-      this.removeEventListener("load", arguments.callee, true);
+      tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
 
-      let pass = 0;
-      const MAX_PASS = 6;
       executeSoon(function() {
-        info("Checking innerHTML, pass: " + (pass + 1));
         let iframes = tab2.linkedBrowser.contentWindow.frames;
-        if (iframes[1].document.body.innerHTML != uniqueValue &&
-            ++pass <= MAX_PASS) {
-          setTimeout(arguments.callee, 500);
-          return;
-        }
         is(iframes[1].document.body.innerHTML, uniqueValue,
            "rich textarea's content correctly duplicated");
-        
+
         let innerDomain = null;
         try {
           innerDomain = iframes[0].document.domain;
         }
         catch (ex) { /* throws for chrome: documents */ }
         is(innerDomain, "localhost", "XSS exploit prevented!");
-        
+
         // clean up
         gBrowser.removeTab(tab2);
         gBrowser.removeTab(tab);
-        
+
         finish();
       });
     }, true);
   }, true);
 }
--- a/browser/components/sessionstore/test/browser/browser_459906_sample.html
+++ b/browser/components/sessionstore/test/browser/browser_459906_sample.html
@@ -3,34 +3,40 @@
 <!DOCTYPE html>
 <title>Test for bug 459906</title>
 
 <body>
 <iframe src="data:text/html,not_on_localhost"></iframe>
 <iframe></iframe>
 
 <script type="application/javascript">
-  frames[0].addEventListener("DOMContentLoaded", function() {
-    frames[0].removeEventListener("DOMContentLoaded", arguments.callee, false);
+  var loadCount = 0;
+  frames[0].addEventListener("DOMContentLoaded", handleLoad, false);
+  frames[1].addEventListener("DOMContentLoaded", handleLoad, false);
+  function handleLoad() {
+    if (++loadCount < 2)
+      return;
+    frames[0].removeEventListener("DOMContentLoaded", handleLoad, false);
+    frames[1].removeEventListener("DOMContentLoaded", handleLoad, false);
     frames[0].document.designMode = "on";
     frames[0].document.__defineGetter__("designMode", function() {
       // inject a cross domain file ...
       var documentInjected = false;
       document.getElementsByTagName("iframe")[0].onload =
         function() { documentInjected = true; };
       frames[0].location = "chrome://mochikit/content/browser/" +
         "browser/components/sessionstore/test/browser/browser_459906_empty.html";
       
       // ... and ensure that it has time to load
       for (var c = 0; !documentInjected && c < 20; c++) {
         var r = new XMLHttpRequest();
         r.open("GET", location.href, false);
         r.overrideMimeType("text/plain");
         r.send(null);
       }
-      
+
       return "on";
     });
-    
+
     frames[1].document.designMode = "on";
-  }, false);
+  };
 </script>
 </body>
--- a/browser/components/sessionstore/test/browser/browser_461634.js
+++ b/browser/components/sessionstore/test/browser/browser_461634.js
@@ -30,18 +30,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 461634 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
   
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   
   const REMEMBER = Date.now(), FORGET = Math.random();
   let test_state = { windows: [{ "tabs": [{ "entries": [] }], _closedTabs: [
     { state: { entries: [{ url: "http://www.example.net/" }] }, title: FORGET },
@@ -60,19 +73,18 @@ function test() {
       return false;
     }
     catch (ex) {
       return ex.name == "NS_ERROR_ILLEGAL_VALUE";
     }
   }
   
   // open a window and add the above closed tab list
-  let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
+  let newWin = open(location, "", "chrome,all");
   newWin.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, false);
     gPrefService.setIntPref("browser.sessionstore.max_tabs_undo",
                             test_state.windows[0]._closedTabs.length);
     ss.setWindowState(newWin, JSON.stringify(test_state), true);
     
     let closedTabs = eval("(" + ss.getClosedTabData(newWin) + ")");
     is(closedTabs.length, test_state.windows[0]._closedTabs.length,
        "Closed tab list has the expected length");
     is(countByTitle(closedTabs, FORGET),
@@ -98,12 +110,13 @@ function test() {
        "The correct amout of tabs was removed");
     is(countByTitle(closedTabs, FORGET), 0,
        "All tabs specifically forgotten were indeed removed");
     is(countByTitle(closedTabs, REMEMBER), remember_count,
        "... and tabs not specifically forgetten weren't.");
 
     // clean up
     newWin.close();
+    is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
     gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
     finish();
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_461743.js
+++ b/browser/components/sessionstore/test/browser/browser_461743.js
@@ -31,42 +31,41 @@
  * 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 ***** */
 
 function test() {
   /** Test for Bug 461743 **/
-  
+
   waitForExplicitFinish();
-  
+
   let testURL = "http://localhost:8888/browser/" +
     "browser/components/sessionstore/test/browser/browser_461743_sample.html";
-  
+
+  let frameCount = 0;
   let tab = gBrowser.addTab(testURL);
-  info("New tab added");
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    info("New tab loaded");
-    this.removeEventListener("load", arguments.callee, true);
-    executeSoon(function() {
-      let tab2 = gBrowser.duplicateTab(tab);
-      info("Duplicated tab");
-      tab2.linkedBrowser.addEventListener("461743", function(aEvent) {
-        tab2.linkedBrowser.removeEventListener("461743", arguments.callee, true);
-        is(aEvent.data, "done", "XSS injection was attempted");
-        
-        executeSoon(function() {
-          let iframes = tab2.linkedBrowser.contentWindow.frames;
-          let innerHTML = iframes[1].document.body.innerHTML;
-          isnot(innerHTML, Components.utils.reportError.toString(),
-                "chrome access denied!");
-          
-          // clean up
-          gBrowser.removeTab(tab2);
-          gBrowser.removeTab(tab);
-          
-          finish();
-        });
-      }, true, true);
-    });
+    // Wait for all frames to load completely.
+    if (frameCount++ < 2)
+      return;
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+    let tab2 = gBrowser.duplicateTab(tab);
+    tab2.linkedBrowser.addEventListener("461743", function(aEvent) {
+      tab2.linkedBrowser.removeEventListener("461743", arguments.callee, true);
+      is(aEvent.data, "done", "XSS injection was attempted");
+
+      executeSoon(function() {
+        let iframes = tab2.linkedBrowser.contentWindow.frames;
+        let innerHTML = iframes[1].document.body.innerHTML;
+        isnot(innerHTML, Components.utils.reportError.toString(),
+              "chrome access denied!");
+
+        // Clean up.
+        gBrowser.removeTab(tab2);
+        gBrowser.removeTab(tab);
+
+        finish();
+      });
+    }, true, true);
   }, true);
 }
--- a/browser/components/sessionstore/test/browser/browser_461743_sample.html
+++ b/browser/components/sessionstore/test/browser/browser_461743_sample.html
@@ -5,43 +5,51 @@
 
 <body>
 <iframe src="data:text/html,empty"></iframe>
 <iframe></iframe>
 
 <script type="application/javascript">
   var chromeUrl = "chrome://global/content/mozilla.xhtml";
   var exploitUrl = "javascript:try { document.body.innerHTML = Components.utils.reportError; } catch (ex) { }";
-  
-  window.onload = function() {
+
+  var loadCount = 0;
+  frames[0].addEventListener("DOMContentLoaded", handleLoad, false);
+  frames[1].addEventListener("DOMContentLoaded", handleLoad, false);
+  function handleLoad() {
+    if (++loadCount < 2)
+      return;
+    frames[0].removeEventListener("DOMContentLoaded", handleLoad, false);
+    frames[1].removeEventListener("DOMContentLoaded", handleLoad, false);
+
     var flip = 0;
     MutationEvent.prototype.toString = function() {
       return flip++ == 0 ? chromeUrl : exploitUrl;
     };
-    
+
     var href = Components.lookupMethod(frames[1].location, "href");
     var loadChrome = { handleEvent: href };
     var loadExploit = { handleEvent: href };
-    
+
     function delay() {
       var xhr = new XMLHttpRequest();
       xhr.open("GET", location.href, false);
       xhr.send(null);
     }
     function done() {
       var event = document.createEvent("MessageEvent");
       event.initMessageEvent("461743", true, false, "done", location.href, "", window);
       document.dispatchEvent(event);
       frames[0].document.removeEventListener("DOMNodeInserted", loadChrome, true);
       frames[0].document.removeEventListener("DOMNodeInserted", delay, true);
       frames[0].document.removeEventListener("DOMNodeInserted", loadExploit, true);
       frames[0].document.removeEventListener("DOMNodeInserted", done, true);
     }
-    
+
     frames[0].document.addEventListener("DOMNodeInserted", loadChrome, true);
     frames[0].document.addEventListener("DOMNodeInserted", delay, true);
     frames[0].document.addEventListener("DOMNodeInserted", loadExploit, true);
     frames[0].document.addEventListener("DOMNodeInserted", done, true);
-    
+
     frames[0].document.designMode = "on";
   };
 </script>
 </body>
--- a/browser/components/sessionstore/test/browser/browser_463205.js
+++ b/browser/components/sessionstore/test/browser/browser_463205.js
@@ -43,17 +43,17 @@ function test() {
     "browser/components/sessionstore/test/browser/browser_463205_sample.html";
   
   var frameCount = 0;
   let tab = gBrowser.addTab(testURL);
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
     // wait for all frames to load completely
     if (frameCount++ < 3)
       return;
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     
     function typeText(aTextField, aValue) {
       aTextField.value = aValue;
       
       let event = aTextField.ownerDocument.createEvent("UIEvents");
       event.initUIEvent("input", true, true, aTextField.ownerDocument.defaultView, 0);
       aTextField.dispatchEvent(event);
     }
@@ -64,17 +64,17 @@ function test() {
     typeText(win.frames[1].document.getElementById("original"), uniqueValue);
     
     frameCount = 0;
     let tab2 = gBrowser.duplicateTab(tab);
     tab2.linkedBrowser.addEventListener("load", function(aEvent) {
       // wait for all frames to load (and reload!) completely
       if (frameCount++ < 4)
         return;
-      this.removeEventListener("load", arguments.callee, true);
+      tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
 
       let win = tab2.linkedBrowser.contentWindow;
       isnot(win.frames[0].document.getElementById("original").value, uniqueValue,
             "subframes must match URL to get text restored");
       is(win.frames[0].document.getElementById("original").value, "preserve me",
          "subframes must match URL to get text restored");
       is(win.frames[1].document.getElementById("original").value, uniqueValue,
          "text still gets restored for all other subframes");
--- a/browser/components/sessionstore/test/browser/browser_463206.js
+++ b/browser/components/sessionstore/test/browser/browser_463206.js
@@ -43,17 +43,17 @@ function test() {
     "browser/components/sessionstore/test/browser/browser_463206_sample.html";
   
   var frameCount = 0;
   let tab = gBrowser.addTab(testURL);
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
     // wait for all frames to load completely
     if (frameCount++ < 5)
       return;
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     
     function typeText(aTextField, aValue) {
       aTextField.value = aValue;
       
       let event = aTextField.ownerDocument.createEvent("UIEvents");
       event.initUIEvent("input", true, true, aTextField.ownerDocument.defaultView, 0);
       aTextField.dispatchEvent(event);
     }
@@ -64,17 +64,17 @@ function test() {
     typeText(doc.defaultView.frames[0].frames[1].document.getElementById("in1"), new Date());
     
     frameCount = 0;
     let tab2 = gBrowser.duplicateTab(tab);
     tab2.linkedBrowser.addEventListener("load", function(aEvent) {
       // wait for all frames to load completely
       if (frameCount++ < 5)
         return;
-      this.removeEventListener("load", arguments.callee, true);
+      tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
 
       let doc = tab2.linkedBrowser.contentDocument;
       let win = tab2.linkedBrowser.contentWindow;
       isnot(doc.getElementById("out1").value,
             win.frames[1].document.getElementById("out1").value,
             "text isn't reused for frames");
       isnot(doc.getElementsByName("1|#out2")[0].value, "",
             "text containing | and # is correctly restored");
--- a/browser/components/sessionstore/test/browser/browser_464199.js
+++ b/browser/components/sessionstore/test/browser/browser_464199.js
@@ -29,18 +29,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 464199 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
   
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   
   const REMEMBER = Date.now(), FORGET = Math.random();
   let test_state = { windows: [{ "tabs": [{ "entries": [] }], _closedTabs: [
     { state: { entries: [{ url: "http://www.example.net/" }] }, title: FORGET },
@@ -68,19 +81,18 @@ function test() {
                extData: { "setTabValue": "http://example.net:80" } }, title: REMEMBER }
   ] }] };
   let remember_count = 5;
   
   function countByTitle(aClosedTabList, aTitle)
     aClosedTabList.filter(function(aData) aData.title == aTitle).length;
   
   // open a window and add the above closed tab list
-  let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
+  let newWin = open(location, "", "chrome,all");
   newWin.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, false);
     gPrefService.setIntPref("browser.sessionstore.max_tabs_undo",
                             test_state.windows[0]._closedTabs.length);
     ss.setWindowState(newWin, JSON.stringify(test_state), true);
     
     let closedTabs = eval("(" + ss.getClosedTabData(newWin) + ")");
     is(closedTabs.length, test_state.windows[0]._closedTabs.length,
        "Closed tab list has the expected length");
     is(countByTitle(closedTabs, FORGET),
@@ -98,13 +110,14 @@ function test() {
        "The correct amout of tabs was removed");
     is(countByTitle(closedTabs, FORGET), 0,
        "All tabs to be forgotten were indeed removed");
     is(countByTitle(closedTabs, REMEMBER), remember_count,
        "... and tabs to be remembered weren't.");
     
     // clean up
     newWin.close();
+    is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
     if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
       gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
     finish();
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_465223.js
+++ b/browser/components/sessionstore/test/browser/browser_465223.js
@@ -29,32 +29,44 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 465223 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
   
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   
   let uniqueKey1 = "bug 465223.1";
   let uniqueKey2 = "bug 465223.2";
   let uniqueValue1 = "unik" + Date.now();
   let uniqueValue2 = "pi != " + Math.random();
   
   // open a window and set a value on it
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
   newWin.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, false);
     ss.setWindowValue(newWin, uniqueKey1, uniqueValue1);
     
     let newState = { windows: [{ tabs:[{ entries: [] }], extData: {} }] };
     newState.windows[0].extData[uniqueKey2] = uniqueValue2;
     ss.setWindowState(newWin, JSON.stringify(newState), false);
     
     is(newWin.gBrowser.tabContainer.childNodes.length, 2,
        "original tab wasn't overwritten");
@@ -70,11 +82,12 @@ function test() {
        "original tabs were overwritten");
     is(ss.getWindowValue(newWin, uniqueKey1), "",
        "window value was cleared");
     is(ss.getWindowValue(newWin, uniqueKey2), uniqueValue1,
        "window value was correctly overwritten");
     
     // clean up
     newWin.close();
+    is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
     finish();
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_466937.js
+++ b/browser/components/sessionstore/test/browser/browser_466937.js
@@ -40,24 +40,24 @@ function test() {
   waitForExplicitFinish();
   
   let testURL = "http://localhost:8888/browser/" +
     "browser/components/sessionstore/test/browser/browser_466937_sample.html";
   let testPath = "/home/user/regular.file";
   
   let tab = gBrowser.addTab(testURL);
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     let doc = tab.linkedBrowser.contentDocument;
     doc.getElementById("reverse_thief").value = "/home/user/secret2";
     doc.getElementById("bystander").value = testPath;
     
     let tab2 = gBrowser.duplicateTab(tab);
     tab2.linkedBrowser.addEventListener("load", function(aEvent) {
-      this.removeEventListener("load", arguments.callee, true);
+      tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
       doc = tab2.linkedBrowser.contentDocument;
       is(doc.getElementById("thief").value, "",
          "file path wasn't set to text field value");
       is(doc.getElementById("reverse_thief").value, "",
          "text field value wasn't set to full file path");
       is(doc.getElementById("bystander").value, testPath,
          "normal case: file path was correctly preserved");
       
--- a/browser/components/sessionstore/test/browser/browser_476161.js
+++ b/browser/components/sessionstore/test/browser/browser_476161.js
@@ -38,25 +38,25 @@ function test() {
   /** Test for Bug 476161 **/
   
   waitForExplicitFinish();
   
   let testURL = "http://localhost:8888/browser/" +
     "browser/components/sessionstore/test/browser/browser_476161_sample.html";
   let tab = gBrowser.addTab(testURL);
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     let doc = tab.linkedBrowser.contentDocument;
     
     doc.getElementById("modify1").value += Math.random();
     doc.getElementById("modify2").value += " " + Date.now();
     
     let tab2 = gBrowser.duplicateTab(tab);
     tab2.linkedBrowser.addEventListener("load", function(aEvent) {
-      this.removeEventListener("load", arguments.callee, true);
+      tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
       let doc = tab2.linkedBrowser.contentDocument;
       let changed = doc.getElementById("changed").textContent.trim().split();
       
       is(changed.sort().join(" "), "modify1 modify2",
          "input events were only dispatched for modified text fields");
       
       // clean up
       gBrowser.removeTab(tab2);
--- a/browser/components/sessionstore/test/browser/browser_477657.js
+++ b/browser/components/sessionstore/test/browser/browser_477657.js
@@ -29,25 +29,41 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 477657 **/
-  
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
+
+  // Test fails randomly on OS X (bug 482975)
+  if ("nsILocalFileMac" in Ci)
+    return;
+
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
   newWin.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, false);
     let newState = { windows: [{
       tabs: [{ entries: [] }],
       _closedTabs: [{
         state: { entries: [{ url: "about:" }]},
         title: "About:"
       }],
       sizemode: "maximized"
     }] };
@@ -83,14 +99,15 @@ function test() {
         newState.windows[0].sizemode = "normal";
         ss.setWindowState(newWin, JSON.stringify(newState), true);
         
         setTimeout(function() {
           isnot(newWin.windowState, newWin.STATE_MAXIMIZED,
                 "the window was explicitly unmaximized");
           
           newWin.close();
+          is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
           finish();
         }, 0);
       }, 0);
     }, 0);
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_480148.js
+++ b/browser/components/sessionstore/test/browser/browser_480148.js
@@ -29,18 +29,34 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 484108 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
+
+  let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+  waitForExplicitFinish();
 
   // builds the tests state based on a few parameters
   function buildTestState(num, selected) {
     let state = { windows: [ { "tabs": [], "selected": selected } ] };
     while (num--)
       state.windows[0].tabs.push({entries: [{url: "http://example.com/"}]});
     return state;
   }
@@ -60,20 +76,16 @@ function test() {
     for (let i = 0; i < num; i++) {
       if (expected.indexOf(i) == -1) {
         expected.push(i);
       }
     }
     return expected;
   }
 
-  // test setup
-  let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-  waitForExplicitFinish();
-
   // the number of tests we're running
   let numTests = 4;
   let completedTests = 0;
 
   // access the pref service just once
   let tabMinWidth = gPrefService.getIntPref("browser.tabs.tabMinWidth");
 
   function runTest(testNum, totalTabs, selectedTab, shownTabs, order) {
@@ -106,16 +118,17 @@ function test() {
            "Test #" + testNum + ": 'visible' tabs restored first");
 
         // cleanup
         this.window.close();
         // if we're all done, explicitly finish
         if (++completedTests == numTests) {
           this.window.removeEventListener("load", this, false);
           this.window.removeEventListener("SSTabRestoring", this, false);
+          is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
           finish();
         }
       },
 
       handleLoad: function (aEvent) {
         let _this = this;
         executeSoon(function () {
           _this.window.resizeTo(_this.windowWidth, _this.window.outerHeight);
@@ -148,9 +161,9 @@ function test() {
 
   // actually create & run the tests
   runTest(1, 13, 1, 6,  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
   runTest(2, 13, 13, 6, [12, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6]);
   runTest(3, 13, 4, 6,  [3, 4, 5, 6, 7, 8, 0, 1, 2, 9, 10, 11, 12]);
   runTest(4, 13, 11, 6, [10, 7, 8, 9, 11, 12, 0, 1, 2, 3, 4, 5, 6]);
 
   // finish() is run by the last test to finish, so no cleanup down here
-}
\ No newline at end of file
+}
--- a/browser/components/sessionstore/test/browser/browser_480893.js
+++ b/browser/components/sessionstore/test/browser/browser_480893.js
@@ -41,41 +41,41 @@ function test() {
 
   // Test that starting a new session loads a blank page if Firefox is
   // configured to display a blank page at startup (browser.startup.page = 0)
   gPrefService.setIntPref("browser.startup.page", 0);
   let tab = gBrowser.addTab("about:sessionrestore");
   gBrowser.selectedTab = tab;
   let browser = tab.linkedBrowser;
   browser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    browser.removeEventListener("load", arguments.callee, true);
     let doc = browser.contentDocument;
 
     // click on the "Start New Session" button after about:sessionrestore is loaded
     doc.getElementById("errorCancel").click();
     browser.addEventListener("load", function(aEvent) {
-      this.removeEventListener("load", arguments.callee, true);
+      browser.removeEventListener("load", arguments.callee, true);
       let doc = browser.contentDocument;
 
       is(doc.URL, "about:blank", "loaded page is about:blank");
 
       // Test that starting a new session loads the homepage (set to http://localhost:8888)
       // if Firefox is configured to display a homepage at startup (browser.startup.page = 1)
       let homepage = "http://localhost:8888/";
       gPrefService.setCharPref("browser.startup.homepage", homepage);
       gPrefService.setIntPref("browser.startup.page", 1);
       gBrowser.loadURI("about:sessionrestore");
       browser.addEventListener("load", function(aEvent) {
-        this.removeEventListener("load", arguments.callee, true);
+        browser.removeEventListener("load", arguments.callee, true);
         let doc = browser.contentDocument;
 
         // click on the "Start New Session" button after about:sessionrestore is loaded
         doc.getElementById("errorCancel").click();
         browser.addEventListener("load", function(aEvent) {
-          this.removeEventListener("load", arguments.callee, true);
+          browser.removeEventListener("load", arguments.callee, true);
           let doc = browser.contentDocument;
 
           is(doc.URL, homepage, "loaded page is the homepage");
 
           // close tab, restore default values and finish the test
           gBrowser.removeTab(tab);
           // we need this if-statement because if there is no user set value, 
           // clearUserPref throws a uncatched exception and finish is not called
--- a/browser/components/sessionstore/test/browser/browser_485482.js
+++ b/browser/components/sessionstore/test/browser/browser_485482.js
@@ -40,24 +40,24 @@ function test() {
   waitForExplicitFinish();
   
   let uniqueValue = Math.random();
   
   let testURL = "chrome://mochikit/content/browser/" +
     "browser/components/sessionstore/test/browser/browser_485482_sample.html";
   let tab = gBrowser.addTab(testURL);
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     let doc = tab.linkedBrowser.contentDocument;
     doc.querySelector("input[type=text]").value = uniqueValue;
     doc.querySelector("input[type=checkbox]").checked = true;
     
     let tab2 = gBrowser.duplicateTab(tab);
     tab2.linkedBrowser.addEventListener("load", function(aEvent) {
-      this.removeEventListener("load", arguments.callee, true);
+      tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
       doc = tab2.linkedBrowser.contentDocument;
       is(doc.querySelector("input[type=text]").value, uniqueValue,
          "generated XPath expression was valid");
       ok(doc.querySelector("input[type=checkbox]").checked,
          "generated XPath expression was valid");
       
       // clean up
       gBrowser.removeTab(tab2);
--- a/browser/components/sessionstore/test/browser/browser_485563.js
+++ b/browser/components/sessionstore/test/browser/browser_485563.js
@@ -39,17 +39,17 @@ function test() {
   
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   
   let uniqueValue = Math.random() + "\u2028Second line\u2029Second paragraph\u2027";
   
   let tab = gBrowser.addTab();
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     ss.setTabValue(tab, "bug485563", uniqueValue);
     let tabState = eval("(" + ss.getTabState(tab) + ")");
     is(tabState.extData["bug485563"], uniqueValue,
        "unicode line separator wasn't over-encoded");
     ss.deleteTabValue(tab, "bug485563");
     ss.setTabState(tab, tabState.toSource());
     is(ss.getTabValue(tab, "bug485563"), uniqueValue,
        "unicode line separator was correctly preserved");
--- a/browser/components/sessionstore/test/browser/browser_490040.js
+++ b/browser/components/sessionstore/test/browser/browser_490040.js
@@ -30,18 +30,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 490040 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
 
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
   let os = Cc["@mozilla.org/observer-service;1"].
            getService(Ci.nsIObserverService);
   let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
            getService(Ci.nsIWindowWatcher);
 
@@ -149,14 +162,15 @@ function test() {
   function runNextTest() {
     if (states.length) {
       let state = states.shift();
       testWithState(state);
     }
     else {
       if (gPrefService.prefHasUserValue("browser.sessionstore.max_windows_undo"))
         gPrefService.clearUserPref("browser.sessionstore.max_windows_undo");
+      is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
       finish();
     }
   }
   runNextTest();
 }
 
--- a/browser/components/sessionstore/test/browser/browser_491168.js
+++ b/browser/components/sessionstore/test/browser/browser_491168.js
@@ -29,18 +29,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 491168 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
 
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   let ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
 
   waitForExplicitFinish();
 
   const REFERRER1 = "http://www.example.net/?" + Date.now();
@@ -67,16 +80,17 @@ function test() {
       gBrowser.removeTab(tab);
       let newTab = ss.undoCloseTab(window, 0);
       newTab.addEventListener("SSTabRestored", function() {
         newTab.removeEventListener("SSTabRestored", arguments.callee, true);
 
         is(window.content.document.referrer, REFERRER2, "document.referrer is still correct after closing and reopening the tab.");
         gBrowser.removeTab(newTab);
 
+        is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
         finish();
       }, true);
     }, true);
   },true);
 
   let referrerURI = ioService.newURI(REFERRER1, null, null);
   browser.loadURI("http://www.example.net", referrerURI, null);
 }
--- a/browser/components/sessionstore/test/browser/browser_491577.js
+++ b/browser/components/sessionstore/test/browser/browser_491577.js
@@ -30,18 +30,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 491577 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
   
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   
   const REMEMBER = Date.now(), FORGET = Math.random();
   let test_state = {
     windows: [ { tabs: [{ entries: [{ url: "http://example.com/" }] }], selected: 1 } ],
@@ -144,13 +157,14 @@ function test() {
        "The correct amount of windows were removed");
     is(countByTitle(closedWindows, FORGET), 0,
        "All windows specifically forgotten were indeed removed");
     is(countByTitle(closedWindows, REMEMBER), remember_count,
        "... and windows not specifically forgetten weren't.");
 
     // clean up
     newWin.close();
+    is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
     if (gPrefService.prefHasUserValue("browser.sessionstore.max_windows_undo"))
       gPrefService.clearUserPref("browser.sessionstore.max_windows_undo");
     finish();
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_493467.js
+++ b/browser/components/sessionstore/test/browser/browser_493467.js
@@ -29,18 +29,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 493467 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
   
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   
   let tab = gBrowser.addTab();
   tab.linkedBrowser.stop();
   let tabState = JSON.parse(ss.getTabState(tab));
   is(tabState.disallow || "", "", "Everything is allowed per default");
   
@@ -61,9 +74,10 @@ function test() {
   let disallow = tabState.disallow.split(",");
   permissions.forEach(function(aName) {
     ok(disallow.indexOf(aName) > -1, "Saved state of allow" + aName);
   });
   // IF A TEST FAILS, please add the missing permission's name (without the
   // leading "allow") to nsSessionStore.js's CAPABILITIES array. Thanks.
   
   gBrowser.removeTab(tab);
+  is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
 }
--- a/browser/components/sessionstore/test/browser/browser_495495.js
+++ b/browser/components/sessionstore/test/browser/browser_495495.js
@@ -29,18 +29,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 495495 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
   
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
 
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no,toolbar=yes");
   newWin.addEventListener("load", function() {
     newWin.removeEventListener("load", arguments.callee, false);
 
@@ -74,16 +87,19 @@ function test() {
 
               win.close();
               executeSoon(callback);
             }, false);
           }
 
           testState(state1, {readOnly: false, enablehistory: "true"}, function() {
             testState(state2, {readOnly: true, enablehistory: "false"}, function() {
-              executeSoon(finish);
+              executeSoon(function () {
+                is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
+                finish();
+              });
             });
           });
         });
       }, false);
     });
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_514751.js
+++ b/browser/components/sessionstore/test/browser/browser_514751.js
@@ -29,18 +29,31 @@
  * 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 ***** */
 
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
 function test() {
   /** Test for Bug 514751 (Wallpaper) **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
 
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
   let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
            getService(Ci.nsIWindowWatcher);
 
   waitForExplicitFinish();
 
@@ -76,16 +89,17 @@ function test() {
                 theWin.close();
               });
             });
           }, false);
           break;
 
         case "domwindowclosed":
           ww.unregisterNotification(this);
+          is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
           finish();
           break;
       }
     }
   }
   ww.registerNotification(windowObserver);
   ww.openWindow(null,
                 location,
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_522545.js
@@ -0,0 +1,319 @@
+/* ***** 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 sessionstore test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Paul O’Shannessy <paul@oshannessy.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 ***** */
+
+function browserWindowsCount() {
+  let count = 0;
+  let e = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator)
+            .getEnumerator("navigator:browser");
+  while (e.hasMoreElements()) {
+    if (!e.getNext().closed)
+      ++count;
+  }
+  return count;
+}
+
+function test() {
+  /** Test for Bug 522545 **/
+  is(browserWindowsCount(), 1, "Only one browser window should be open initially");
+
+  waitForExplicitFinish();
+
+  let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+           getService(Ci.nsISessionStore);
+  let os = Cc["@mozilla.org/observer-service;1"].
+           getService(Ci.nsIObserverService);
+
+  function waitForBrowserState(aState, aSetStateCallback) {
+    let observer = {
+      observe: function(aSubject, aTopic, aData) {
+        os.removeObserver(this, "sessionstore-browser-state-restored");
+        executeSoon(aSetStateCallback);
+      }
+    };
+    os.addObserver(observer, "sessionstore-browser-state-restored", false);
+    ss.setBrowserState(JSON.stringify(aState));
+  }
+
+  // This tests the following use case:
+  // User opens a new tab which gets focus. The user types something into the
+  // address bar, then crashes or quits.
+  function test_newTabFocused() {
+    let state = {
+      windows: [{
+        tabs: [
+          { entries: [{ url: "about:mozilla" }] },
+          { entries: [], userTypedValue: "example.com", userTypedClear: 0 }
+        ],
+        selected: 2
+      }]
+    };
+
+    waitForBrowserState(state, function() {
+      let browser = gBrowser.selectedBrowser;
+      is(browser.currentURI.spec, "about:blank",
+         "No history entries still sets currentURI to about:blank");
+      is(browser.userTypedValue, "example.com",
+         "userTypedValue was correctly restored");
+      is(browser.userTypedClear, 0,
+         "userTypeClear restored as expected");
+      is(gURLBar.value, "example.com",
+         "Address bar's value correctly restored");
+      // Change tabs to make sure address bar value gets updated
+      gBrowser.selectedTab = gBrowser.tabContainer.getItemAtIndex(0);
+      is(gURLBar.value, "about:mozilla",
+         "Address bar's value correctly updated");
+      runNextTest();
+    });
+  }
+
+  // This tests the following use case:
+  // User opens a new tab which gets focus. The user types something into the
+  // address bar, switches back to the first tab, then crashes or quits.
+  function test_newTabNotFocused() {
+    let state = {
+      windows: [{
+        tabs: [
+          { entries: [{ url: "about:mozilla" }] },
+          { entries: [], userTypedValue: "example.org", userTypedClear: 0 }
+        ],
+        selected: 1
+      }]
+    };
+
+    waitForBrowserState(state, function() {
+      let browser = gBrowser.getBrowserAtIndex(1);
+      is(browser.currentURI.spec, "about:blank",
+         "No history entries still sets currentURI to about:blank");
+      is(browser.userTypedValue, "example.org",
+         "userTypedValue was correctly restored");
+      is(browser.userTypedClear, 0,
+         "userTypeClear restored as expected");
+      is(gURLBar.value, "about:mozilla",
+         "Address bar's value correctly restored");
+      // Change tabs to make sure address bar value gets updated
+      gBrowser.selectedTab = gBrowser.tabContainer.getItemAtIndex(1);
+      is(gURLBar.value, "example.org",
+         "Address bar's value correctly updated");
+      runNextTest();
+    });
+  }
+
+  // This tests the following use case:
+  // User is in a tab with session history, then types something in the
+  // address bar, then crashes or quits.
+  function test_existingSHEnd_noClear() {
+    let state = {
+      windows: [{
+        tabs: [{
+          entries: [{ url: "about:mozilla" }, { url: "about:config" }],
+          index: 2,
+          userTypedValue: "example.com",
+          userTypedClear: 0
+        }]
+      }]
+    };
+
+    waitForBrowserState(state, function() {
+      let browser = gBrowser.selectedBrowser;
+      is(browser.currentURI.spec, "about:config",
+         "browser.currentURI set to current entry in SH");
+      is(browser.userTypedValue, "example.com",
+         "userTypedValue was correctly restored");
+      is(browser.userTypedClear, 0,
+         "userTypeClear restored as expected");
+      is(gURLBar.value, "example.com",
+         "Address bar's value correctly restored to userTypedValue");
+      runNextTest();
+    });
+  }
+
+  // This tests the following use case:
+  // User is in a tab with session history, presses back at some point, then
+  // types something in the address bar, then crashes or quits.
+  function test_existingSHMiddle_noClear() {
+    let state = {
+      windows: [{
+        tabs: [{
+          entries: [{ url: "about:mozilla" }, { url: "about:config" }],
+          index: 1,
+          userTypedValue: "example.org",
+          userTypedClear: 0
+        }]
+      }]
+    };
+
+    waitForBrowserState(state, function() {
+      let browser = gBrowser.selectedBrowser;
+      is(browser.currentURI.spec, "about:mozilla",
+         "browser.currentURI set to current entry in SH");
+      is(browser.userTypedValue, "example.org",
+         "userTypedValue was correctly restored");
+      is(browser.userTypedClear, 0,
+         "userTypeClear restored as expected");
+      is(gURLBar.value, "example.org",
+         "Address bar's value correctly restored to userTypedValue");
+      runNextTest();
+    });
+  }
+
+  // This test simulates lots of tabs opening at once and then quitting/crashing.
+  function test_getBrowserState_lotsOfTabsOpening() {
+    let uris = [];
+    for (let i = 0; i < 25; i++)
+      uris.push("http://example.com/" + i);
+
+    // We're listening for the first non-"about:blank" load event, which should
+    // indicate one of the tabs has loaded and the others haven't. So one should
+    // be in a non-userTypedValue case, while others should still have
+    // userTypedValue and userTypedClear set.
+    gBrowser.addEventListener("load", function(aEvent) {
+      if (gBrowser.currentURI.spec == "about:blank")
+        return;
+      gBrowser.removeEventListener("load", arguments.callee, true);
+
+      let state = JSON.parse(ss.getBrowserState());
+
+      let hasSH = state.windows[0].tabs.some(function(aTab) {
+        return !("userTypedValue" in aTab) && aTab.entries[0].url;
+      });
+      let hasUTV = state.windows[0].tabs.some(function(aTab) {
+        return aTab.userTypedValue && aTab.userTypedClear && !aTab.entries.length;
+      });
+
+      ok(hasSH, "At least one tab has it's entry in SH");
+      ok(hasUTV, "At least one tab has a userTypedValue with userTypedClear with no loaded URL");
+
+      runNextTest();
+
+    }, true);
+    gBrowser.loadTabs(uris);
+  }
+
+  // This simulates setting a userTypedValue and ensures that just typing in the
+  // URL bar doesn't set userTypedClear as well.
+  function test_getBrowserState_userTypedValue() {
+    let state = {
+      windows: [{
+        tabs: [{ entries: [] }]
+      }]
+    };
+
+    waitForBrowserState(state, function() {
+      let browser = gBrowser.selectedBrowser;
+      // Make sure this tab isn't loading and state is clear before we test.
+      is(browser.userTypedValue, null, "userTypedValue is empty to start");
+      is(browser.userTypedClear, 0, "userTypedClear is 0 to start");
+
+      gURLBar.value = "mozilla.org";
+      let event = document.createEvent("Events");
+      event.initEvent("input", true, false);
+      gURLBar.dispatchEvent(event);
+
+      is(browser.userTypedValue, "mozilla.org",
+         "userTypedValue was set when changing gURLBar.value");
+      is(browser.userTypedClear, 0,
+         "userTypedClear was not changed when changing gURLBar.value");
+
+      // Now make sure ss gets these values too
+      let newState = JSON.parse(ss.getBrowserState());
+      is(newState.windows[0].tabs[0].userTypedValue, "mozilla.org",
+         "sessionstore got correct userTypedValue");
+      is(newState.windows[0].tabs[0].userTypedClear, 0,
+         "sessionstore got correct userTypedClear");
+      runNextTest();
+    });
+  }
+
+  // test_getBrowserState_lotsOfTabsOpening tested userTypedClear in a few cases,
+  // but not necessarily any that had legitimate URIs in the state of loading
+  // (eg, "http://example.com"), so this test will cover that case.
+  function test_userTypedClearLoadURI() {
+    let state = {
+      windows: [{
+        tabs: [
+          { entries: [], userTypedValue: "http://example.com", userTypedClear: 2 }
+        ]
+      }]
+    };
+
+    // Set state here and listen for load event because waitForBrowserState
+    // doesn't guarantee all the tabs have loaded, so the test could continue
+    // before we're in a testable state. This is important here because of the
+    // distinction between "http://example.com" and "http://example.com/".
+    ss.setBrowserState(JSON.stringify(state));
+    gBrowser.addEventListener("load", function(aEvent) {
+      if (gBrowser.currentURI.spec == "about:blank")
+        return;
+      gBrowser.removeEventListener("load", arguments.callee, true);
+
+      let browser = gBrowser.selectedBrowser;
+      is(browser.currentURI.spec, "http://example.com/",
+         "userTypedClear=2 caused userTypedValue to be loaded");
+      is(browser.userTypedValue, null,
+         "userTypedValue was null after loading a URI");
+      is(browser.userTypedClear, 0,
+         "userTypeClear reset to 0");
+      is(gURLBar.value, "http://example.com/",
+         "Address bar's value set after loading URI");
+      runNextTest();
+    }, true);
+  }
+
+
+  let tests = [test_newTabFocused, test_newTabNotFocused,
+               test_existingSHEnd_noClear, test_existingSHMiddle_noClear,
+               test_getBrowserState_lotsOfTabsOpening,
+               test_getBrowserState_userTypedValue, test_userTypedClearLoadURI];
+  let originalState = ss.getBrowserState();
+  info(JSON.parse(originalState).windows.length);
+  info(originalState);
+  function runNextTest() {
+    if (tests.length) {
+      tests.shift().call();
+    } else {
+      ss.setBrowserState(originalState);
+      executeSoon(function () {
+        is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
+        finish();
+      });
+    }
+  }
+
+  // Run the tests!
+  runNextTest();
+}
--- a/browser/components/sessionstore/test/browser/browser_526613.js
+++ b/browser/components/sessionstore/test/browser/browser_526613.js
@@ -44,20 +44,30 @@ function test() {
   let os = Cc["@mozilla.org/observer-service;1"].
            getService(Ci.nsIObserverService);
   let wm = Cc["@mozilla.org/appshell/window-mediator;1"].
            getService(Ci.nsIWindowMediator);
   waitForExplicitFinish();
 
   function browserWindowsCount() {
     let count = 0;
-    let e = wm.getXULWindowEnumerator("navigator:browser");
+    let e = wm.getEnumerator("navigator:browser");
     while (e.hasMoreElements()) {
-      ++count;
-      e.getNext();
+      let win = e.getNext();
+      if (!win.closed) {
+        ++count;
+        if (win != window) {
+          try {
+            var tabs = win.gBrowser.mTabs.length;
+          } catch (e) {
+            info(e);
+          }
+          info("secondary window: " + [win.document.readyState, win.content.location, tabs]);
+        }
+      }
     }
 
     return count;
   }
 
   is(browserWindowsCount(), 1, "Only one browser window should be open initially");
 
   // backup old state
@@ -77,24 +87,31 @@ function test() {
     pass: 1,
     observe: function(aSubject, aTopic, aData) {
       is(aTopic, "sessionstore-browser-state-restored",
          "The sessionstore-browser-state-restored notification was observed");
 
       if (this.pass++ == 1) {  
         is(browserWindowsCount(), 2, "Two windows should exist at this point");
 
-        // executeSoon is needed here in order to let the first window be focused
-        // (see above)
-        executeSoon(function() {
-          ss.setBrowserState(oldState);
-        });
+        // let the first window be focused (see above)
+        function pollMostRecentWindow() {
+          if (wm.getMostRecentWindow("navigator:browser") == window) {
+            ss.setBrowserState(oldState);
+          } else {
+            info("waiting for the current window to become active");
+            setTimeout(pollMostRecentWindow, 0);
+          }
+        }
+        window.focus(); //XXX Why is this needed?
+        pollMostRecentWindow();
       }
       else {
         is(browserWindowsCount(), 1, "Only one window should exist after cleanup");
+        ok(!window.closed, "Restoring the old state should have left this window open");
         os.removeObserver(this, "sessionstore-browser-state-restored");
         finish();
       }
     }
   };
   os.addObserver(observer, "sessionstore-browser-state-restored", false);
 
   // set browser to test state
--- a/browser/components/shell/test/browser_420786.js
+++ b/browser/components/shell/test/browser_420786.js
@@ -1,27 +1,14 @@
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-
 const DG_BACKGROUND = "/desktop/gnome/background"
 const DG_IMAGE_KEY = DG_BACKGROUND + "/picture_filename";
 const DG_OPTION_KEY = DG_BACKGROUND + "/picture_options";
 const DG_DRAW_BG_KEY = DG_BACKGROUND + "/draw_background";
 
-var testPage;
-
-function url(spec) {
-  var ios = Cc["@mozilla.org/network/io-service;1"].
-            getService(Ci.nsIIOService);
-  return ios.newURI(spec, null, null);
-}
-
 function onPageLoad() {
-  testPage.events.removeListener("load", onPageLoad);
-
   var bs = Cc["@mozilla.org/intl/stringbundle;1"].
            getService(Ci.nsIStringBundleService);
   var brandName = bs.createBundle("chrome://branding/locale/brand.properties").
                   GetStringFromName("brandShortName");
 
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                getService(Ci.nsIDirectoryServiceProvider);
   var homeDir = dirSvc.getFile("Home", {});
@@ -44,17 +31,17 @@ function onPageLoad() {
               getService(Ci.nsIShellService);
   var gconf = Cc["@mozilla.org/gnome-gconf-service;1"].
               getService(Ci.nsIGConfService);
 
   var prevImageKey = gconf.getString(DG_IMAGE_KEY);
   var prevOptionKey = gconf.getString(DG_OPTION_KEY);
   var prevDrawBgKey = gconf.getBool(DG_DRAW_BG_KEY);
 
-  var image = testPage.document.getElementsByTagName("img")[0];
+  var image = content.document.images[0];
 
   function checkWallpaper(position, expectedGConfPosition) {
     shell.setDesktopBackground(image, position);
     ok(wpFile.exists(), "Wallpaper was written to disk");
     is(gconf.getString(DG_IMAGE_KEY), wpFile.path,
        "Wallpaper file GConf key is correct");
     is(gconf.getString(DG_OPTION_KEY), expectedGConfPosition,
        "Wallpaper position GConf key is correct");
@@ -67,32 +54,29 @@ function onPageLoad() {
 
   // Restore GConf and wallpaper
 
   gconf.setString(DG_IMAGE_KEY, prevImageKey);
   gconf.setString(DG_OPTION_KEY, prevOptionKey);
   gconf.setBool(DG_DRAW_BG_KEY, prevDrawBgKey);
 
   wpFile.remove(false);
-  if (wpFileBackup.exists()) {
-   wpFileBackup.moveTo(null, wpFile.leafName);
-  }
-  testPage.close();
+  if (wpFileBackup.exists())
+    wpFileBackup.moveTo(null, wpFile.leafName);
+
+  gBrowser.removeCurrentTab();
   finish();
 }
 
 function test() {
   var osString = Cc["@mozilla.org/xre/app-info;1"].
                  getService(Ci.nsIXULRuntime).OS;
 
   // This test is Linux specific for now
-  if (osString != "Linux") {
-    finish();
+  if (osString != "Linux")
     return;
-  }
 
-  testPage = Application.activeWindow.open(url("about:blank"));
-  testPage.events.addListener("load", onPageLoad);
-  testPage.load(url("about:logo"));
-  testPage.focus();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", onPageLoad, true);
+  content.location = "about:logo";
 
   waitForExplicitFinish();
 }
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -500,8 +500,13 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 
 ; [FastStart]
 #ifdef WINCE
 #ifdef MOZ_FASTSTART
 @BINPATH@/firefoxfaststart.exe
 @BINPATH@/components/FastStartup.js
 #endif
 #endif
+
+; [OS/2]
+#ifdef XP_OS2
+@BINPATH@/MozSounds.cmd
+#endif
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -580,16 +580,18 @@ res/hiddenWindow.html
 res/ua.css
 res/html.css
 res/quirk.css
 res/forms.css
 res/viewsource.css
 res/mathml.css
 res/loading-image.png
 res/broken-image.png
+res/loading-image.gif
+res/broken-image.gif
 res/html/gopher-audio.gif
 res/html/gopher-binary.gif
 res/html/gopher-find.gif
 res/html/gopher-image.gif
 res/html/gopher-menu.gif
 res/html/gopher-movie.gif
 res/html/gopher-sound.gif
 res/html/gopher-telnet.gif
@@ -633,31 +635,30 @@ components/websrvcs.xpt
 components/widget_mac.xpt
 components/xml-rpc.xpt
 components/xpcom_obsolete.xpt
 updater.app/Contents/MacOS/updater.ini
 init.d/README
 redo-prebinding.sh
 res/viewer.properties
 res/bloatcycle.html
-res/broken-image.gif
-res/loading-image.gif
 components/browsersearch.xpt
 components/nsResetPref.js
 plugins/Default Plugin.plugin/Contents/Info.plist
 plugins/Default Plugin.plugin/Contents/MacOS/Default Plugin
 plugins/Default Plugin.plugin/Contents/PkgInfo
 plugins/Default Plugin.plugin/Contents/Resources/Default Plugin.rsrc
 plugins/Default Plugin.plugin/Contents/Resources/English.lproj/InfoPlist.strings
 ../Plug-Ins/PrintPDE.plugin/Contents/Info.plist
 ../Plug-Ins/PrintPDE.plugin/Contents/MacOS/PrintPDE
 ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/Localizable.strings
 ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/classes.nib
 ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/info.nib
 ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/objects.xib
+../Resources/firefox-bin.rsrc
 res/cursors/CVS/Entries
 res/cursors/CVS/Repository
 res/cursors/CVS/Root
 res/cursors/CVS/Tag
 components/alerts.xpt
 components/appshell.xpt
 components/appstartup.xpt
 components/autocomplete.xpt
@@ -743,16 +744,17 @@ components/necko_dns.xpt
 components/necko_file.xpt
 components/necko_ftp.xpt
 components/necko_http.xpt
 components/necko_res.xpt
 components/necko_socket.xpt
 components/necko_strconv.xpt
 components/necko_viewsource.xpt
 components/necko_wifi.xpt
+components/oji.xpt
 components/parentalcontrols.xpt
 components/pipboot.xpt
 components/pipnss.xpt
 components/pippki.xpt
 components/places.xpt
 components/plugin.xpt
 components/pref.xpt
 components/prefetch.xpt
@@ -799,24 +801,27 @@ 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
 dictionaries/PL.aff
 libjemalloc.so
+icons/mozicon16.xpm
+icons/mozicon50.xpm
 #endif
 #endif
 #ifdef XP_WIN
 #ifdef MOZ_MEMORY
 Microsoft.VC80.CRT.manifest
 msvcm80.dll
 msvcp80.dll
 msvcr80.dll
@@ -833,8 +838,9 @@ js3250.dll
 #endif
 #ifdef XP_WIN
 components/brwsrcmp.dll
 #endif
 #ifndef MOZ_UPDATER
 components/nsUpdateService.js
 components/nsUpdateServiceStub.js
 #endif
+old-homepage-default.properties
--- a/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd
+++ b/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd
@@ -17,18 +17,18 @@
 <!ENTITY helpForIEUsers.label     "For Internet Explorer Users">
 <!ENTITY helpForIEUsers.accesskey "I">
 <!ENTITY openHelp.commandkey      "VK_F1">
 <!ENTITY helpMac.commandkey       "?">
 
 <!ENTITY helpReleaseNotes.label         "Release Notes">
 <!ENTITY helpReleaseNotes.accesskey     "N">
 
-<!ENTITY helpTroubleshooting.label      "Troubleshooting Information">
-<!ENTITY helpTroubleshooting.accesskey  "T">
+<!ENTITY helpTroubleshootingInfo.label      "Troubleshooting Information">
+<!ENTITY helpTroubleshootingInfo.accesskey  "T">
 
 <!ENTITY updateCmd.label                "Check for Updates…">
 
 <!ENTITY preferencesCmdMac.label        "Preferences…">
 <!ENTITY preferencesCmdMac.commandkey   ",">
 
 <!ENTITY servicesMenuMac.label          "Services">
 
--- a/browser/locales/en-US/searchplugins/yahoo.xml
+++ b/browser/locales/en-US/searchplugins/yahoo.xml
@@ -1,13 +1,13 @@
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Yahoo</ShortName>
 <Description>Yahoo Search</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,R0lGODlhEAAQAJECAP8AAAAAAP///wAAACH5BAEAAAIALAAAAAAQABAAAAIplI+py+0NogQuyBDEnEd2kHkfFWUamEzmpZSfmaIHPHrRguUm/fT+UwAAOw==</Image>
+<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbgJqAIoCdgCaAnoAnhKCAKYijgCuLpIAskKeALpSpgC+Yq4AzHy8ANqezgDmvt4A7tLqAPz5+wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKlRFIoABWAKERERE6ADcKMzzu2hOgAAhERK8REWCWBERE36ERMHMEREvo6iEgY6hEn6Pu0mAzqkz/xjMzoDNwpERERDoAMzAKlERIoAAzMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAP//AADAOQAAgBkAAAAPAAAACQAAAAkAAAAIAAAACAAAAAgAAIAYAADAOAAA//8AAP//AAD//wAA</Image>
 <Url type="application/x-suggestions+json" method="GET"
      template="http://ff.search.yahoo.com/gossip?output=fxjson&amp;command={searchTerms}" />
 <Url type="text/html" method="GET" template="http://search.yahoo.com/search">
   <Param name="p" value="{searchTerms}"/>
   <Param name="ei" value="UTF-8"/>
   <MozParam name="fr" condition="pref" pref="yahoo-fr" />
 </Url>
 <SearchForm>http://search.yahoo.com/</SearchForm>
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1263,17 +1263,19 @@ tabpanels {
 /* Tabstrip close button */
 .tabs-closebutton {
   list-style-image: url("moz-icon://stock/gtk-close?size=menu");
   border: none;
   margin-bottom: 1px;
 }
 
 .tabs-closebutton > .toolbarbutton-icon {
-  margin: 0;
+  /* XXX Buttons have padding in widget/ that we don't want here but can't override with good CSS, so we must
+     use evil CSS to give the impression of smaller content */
+  margin: -2px;
 }
 
 /* Tabbrowser arrowscrollbox arrows */
 .tabbrowser-arrowscrollbox > .scrollbutton-up {
   -moz-appearance: tab-scroll-arrow-back;
   margin: 0;
 }
 
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -41,48 +41,29 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 @import url("chrome://global/skin/");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
 
-#urlbar:-moz-lwtheme:not([focused="true"]),
-.searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
-  opacity: .85;
-}
-
-.tabbrowser-tab:-moz-lwtheme[selected="true"] {
-  text-shadow: none;
-}
-
-.tabbrowser-tabs:-moz-lwtheme {
-  -moz-appearance: none;
-  background: none;
-  border-style: none;
-}
-
-.tabbrowser-tab:-moz-lwtheme:not([selected="true"]) {
-  color: inherit;
-}
-
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
 }
 
 #personal-bookmarks {
   min-height: 24px;
 }
 
-#navigator-toolbox:-moz-system-metric(windows-default-theme) {
+#navigator-toolbox:-moz-system-metric(windows-default-theme):not(:-moz-lwtheme) {
   padding-bottom: 1px; /* uxtheme border drawing fix/hack */
 }
 
 #navigator-toolbox[inFullscreen="true"],
 #navigator-toolbox[inFullscreen="true"] > #nav-bar {
   border-top: none;
 }
 
@@ -224,25 +205,16 @@ toolbar[mode="full"] .toolbarbutton-menu
 .toolbarbutton-menubutton-button {
   padding: 5px;
 }
 
 .toolbarbutton-1[checked="true"] {
   padding: 5px !important;
 }
 
-toolbar[iconsize="large"][mode="icons"] .toolbarbutton-1:-moz-system-metric(windows-default-theme),
-.toolbarbutton-menubutton-button:-moz-system-metric(windows-default-theme) {
-  padding: 6px; /* uxtheme border drawing fix/hack */
-}
-
-toolbar[iconsize="large"][mode="icons"] .toolbarbutton-1[checked="true"]:-moz-system-metric(windows-default-theme) {
-  padding: 6px !important; /* uxtheme border drawing fix/hack */
-}
-
 #back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #back-forward-dropmarker:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   -moz-transform: scaleX(-1);
 }
 
 /* ::::: unified back and forward buttons ::::: */
 
@@ -879,16 +851,21 @@ toolbar[iconsize="small"] #fullscreen-bu
 
 /* ::::: nav-bar-inner ::::: */
 
 #urlbar {
   width: 7em;
   min-width: 7em;
 }
 
+#urlbar:-moz-lwtheme:not([focused="true"]),
+.searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
+  opacity: .85;
+}
+
 #urlbar:-moz-system-metric(windows-default-theme) {
   -moz-appearance: none;
   border-width: 1px;
   -moz-border-top-colors: ThreeDShadow;
   -moz-border-bottom-colors: ThreeDShadow;
   -moz-border-right-colors: ThreeDShadow;
   -moz-border-left-colors: ThreeDShadow;
 }
@@ -1154,38 +1131,67 @@ statusbarpanel#statusbar-display {
 }
 
 /* Tabstrip */
 .tabbrowser-tabs {
   -moz-appearance: -moz-win-browsertabbar-toolbox;
   background: -moz-dialog url("chrome://browser/skin/tabbrowser/tabbrowser-tabs-bkgnd.png") repeat-x;
 }
 
+.tabbrowser-tabs:-moz-lwtheme {
+  -moz-appearance: none;
+  background: none;
+  border-style: none;
+}
+
 .tabbrowser-tabs:-moz-system-metric(touch-enabled) {
   min-height: .81cm;
 }
 
 .tabs-container:not([overflow="true"]) {
   -moz-padding-start: 3px;
 }
 
 /* Tabs */
-.tabbrowser-tab {
+.tabbrowser-tab,
+.tabbrowser-arrowscrollbox > .scrollbutton-up,
+.tabbrowser-arrowscrollbox > .scrollbutton-down,
+.tabs-newtab-button,
+.tabs-alltabs-button {
   -moz-appearance: none;
   background: url("chrome://browser/skin/tabbrowser/tab-bkgnd.png") repeat-x;
   margin: 3px 0px 4px;
-  padding: 0px 1px 1px 0px;
   border: 2px solid;
   border-right-width: 1px;
   border-bottom: none;
+  -moz-border-top-colors: ThreeDShadow rgba(255,255,255,.3);
+  -moz-border-left-colors: ThreeDShadow rgba(255,255,255,.3);
+}
+
+.tabbrowser-tab:-moz-lwtheme-brighttext,
+.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-lwtheme-brighttext,
+.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-lwtheme-brighttext,
+.tabs-newtab-button:-moz-lwtheme-brighttext,
+.tabs-alltabs-button:-moz-lwtheme-brighttext {
+  background-color: rgba(0,0,0,.5);
+}
+
+.tabbrowser-tab:-moz-lwtheme-darktext,
+.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-lwtheme-darktext,
+.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-lwtheme-darktext,
+.tabs-newtab-button:-moz-lwtheme-darktext,
+.tabs-alltabs-button:-moz-lwtheme-darktext {
+  background-color: rgba(255,255,255,.5);
+}
+
+.tabbrowser-tab {
+  padding: 0 1px 1px 0;
   -moz-border-radius-topleft: 2px;
   -moz-border-radius-topright: 2px;
-  -moz-border-top-colors: ThreeDShadow rgba(255,255,255,.3);
   -moz-border-right-colors: rgba(0,0,0,.1);
-  -moz-border-left-colors: ThreeDShadow rgba(255,255,255,.3);
 }
 
 .tabbrowser-tab:hover,
 .tabbrowser-tab[selected="true"] {
   border-width: 1px;
   -moz-border-radius-topleft: 4px;
   -moz-border-radius-topright: 4px;
   -moz-border-top-colors: ThreeDShadow;
@@ -1202,16 +1208,24 @@ statusbarpanel#statusbar-display {
 .tabbrowser-tab[selected="true"] {
   margin: 2px 0px 3px;
   padding: 1px;
   background-image: url("chrome://browser/skin/tabbrowser/tab-active-bkgnd.png");
   background-color: -moz-dialog;
   font-weight: bold;
 }
 
+.tabbrowser-tab:-moz-lwtheme[selected="true"] {
+  text-shadow: none;
+}
+
+.tabbrowser-tab:-moz-lwtheme:not([selected="true"]) {
+  color: inherit;
+}
+
 .tabbrowser-tab[busy] > .tab-icon-image {
   list-style-image: url("chrome://browser/skin/tabbrowser/progress.png") !important;
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 .tabbrowser-tab[busy][stalled] > .tab-icon-image {
   list-style-image: url("chrome://browser/skin/tabbrowser/progress-pulsing.png") !important;
 }
 .tabbrowser-tab[busy][progress="1"] > .tab-icon-image {
@@ -1327,27 +1341,19 @@ tabpanels {
   outline: none !important;
 }
 
 /* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down,
 .tabs-newtab-button,
 .tabs-alltabs-button {
-  -moz-appearance: none;
   width: 18px;
-  margin: 3px 0px 4px;
-  padding: 0px;
-  border: 2px solid;
-  border-right-width: 1px;
-  border-bottom: none;
-  -moz-border-top-colors: ThreeDShadow rgba(255,255,255,.3);
+  padding: 0;
   -moz-border-right-colors: ThreeDShadow;
-  -moz-border-left-colors: ThreeDShadow rgba(255,255,255,.3);
-  background: url("chrome://browser/skin/tabbrowser/tab-bkgnd.png") repeat-x;
   -moz-image-region: rect(0, 11px, 14px, 0);
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-system-metric(touch-enabled),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-system-metric(touch-enabled),
 .tabs-alltabs-button:-moz-system-metric(touch-enabled) {
   min-width: .81cm;
 }
@@ -1860,25 +1866,16 @@ toolbarbutton.bookmark-item[dragover="tr
 #nav-bar[mode="full"][currentset$=",urlbar-container"],
 #nav-bar[mode="full"][currentset$=",search-container"],
 #nav-bar[iconsize="large"][mode="icons"]:not([currentset]),
 #nav-bar[iconsize="large"][mode="icons"][currentset$=",urlbar-container"],
 #nav-bar[iconsize="large"][mode="icons"][currentset$=",search-container"] {
   -moz-padding-end: 2px;
 }
 
-#nav-bar[mode="full"]:not([currentset]):-moz-system-metric(windows-default-theme),
-#nav-bar[mode="full"][currentset$=",urlbar-container"]:-moz-system-metric(windows-default-theme),
-#nav-bar[mode="full"][currentset$=",search-container"]:-moz-system-metric(windows-default-theme),
-#nav-bar[iconsize="large"][mode="icons"]:not([currentset]):-moz-system-metric(windows-default-theme),
-#nav-bar[iconsize="large"][mode="icons"][currentset$=",urlbar-container"]:-moz-system-metric(windows-default-theme),
-#nav-bar[iconsize="large"][mode="icons"][currentset$=",search-container"]:-moz-system-metric(windows-default-theme) {
-  -moz-padding-end: 3px;
-}
-
 /* ::::: Keyboard UI Panel ::::: */
 
 .KUI-panel {
   -moz-appearance: none;
   background: rgba(27%,27%,27%,.9) url(KUI-background.png) repeat-x;
   color: white;
   border-style: none;
   -moz-border-radius: 20px;
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -61,16 +61,17 @@ SCRIPT_DIR = os.path.abspath(os.path.rea
 
 __all__ = [
            "UNIXISH",
            "IS_WIN32",
            "IS_MAC",
            "log",
            "runApp",
            "Process",
+           "addExtraCommonOptions",
            "initializeProfile",
            "DIST_BIN",
            "DEFAULT_APP",
            "CERTS_SRC_DIR",
            "environment",
            "IS_TEST_BUILD",
            "IS_DEBUG_BUILD",
            "DEFAULT_TIMEOUT",
@@ -346,16 +347,25 @@ user_pref("camino.use_system_proxy_setti
     part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
     prefs.append(part)
 
   # write the preferences
   prefsFile = open(profileDir + "/" + "user.js", "a")
   prefsFile.write("".join(prefs))
   prefsFile.close()
 
+def addExtraCommonOptions(parser):
+  "Adds command-line options which are common to mochitest and reftest."
+
+  parser.add_option("--setpref",
+                    action = "append", type = "string",
+                    default = [],
+                    dest = "extraPrefs", metavar = "PREF=VALUE",
+                    help = "defines an extra user preference")  
+
 def fillCertificateDB(profileDir, certPath, utilityPath, xrePath):
   pwfilePath = os.path.join(profileDir, ".crtdbpw")
   
   pwfile = open(pwfilePath, "w")
   pwfile.write("\n")
   pwfile.close()
 
   # Create head of the ssltunnel configuration file
@@ -432,47 +442,51 @@ def environment(env = None, xrePath = DI
       ldLibraryPath = ldLibraryPath + ":" + env[envVar]
     env[envVar] = ldLibraryPath
   elif IS_WIN32:
     env["PATH"] = env["PATH"] + ";" + ldLibraryPath
 
   if crashreporter:
     env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
     env['MOZ_CRASHREPORTER'] = '1'
+  else:
+    env['MOZ_CRASHREPORTER_DISABLE'] = '1'
+
   env['GNOME_DISABLE_CRASH_DIALOG'] = "1"
   return env
 
 if IS_WIN32:
-  #XXX: disabled on windows for now, see bug 525370 
-  def readWithTimeout(f, timeout):
-    return (f.readline(), False)
-elif False:
-  #XXX: figure out what's going wrong with this code!
   import ctypes, time, msvcrt
   PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe
   GetLastError = ctypes.windll.kernel32.GetLastError
   def readWithTimeout(f, timeout):
     """Try to read a line of output from the file object |f|.
     |f| must be a  pipe, like the |stdout| member of a subprocess.Popen
     object created with stdout=PIPE. If no output
     is received within |timeout| seconds, return a blank line.
     Returns a tuple (line, did_timeout), where |did_timeout| is True
     if the read timed out, and False otherwise."""
+    if timeout is None:
+      # shortcut to allow callers to pass in "None" for no timeout.
+      return (f.readline(), False)
     x = msvcrt.get_osfhandle(f.fileno())
     l = ctypes.c_long()
-    buf = ctypes.create_string_buffer('', 1024)
     done = time.time() + timeout
     while time.time() < done:
-        if PeekNamedPipe(x, buf, len(buf), None, ctypes.byref(l), None) == 0:
-            err = GetLastError()
-            if err == 38 or err == 109: # ERROR_HANDLE_EOF || ERROR_BROKEN_PIPE
-                return ('', False)
-        if (l > 0 and '\n' in buf.value):
-            return (f.readline(), False)
-        time.sleep(0.1)
+      if PeekNamedPipe(x, None, 0, None, ctypes.byref(l), None) == 0:
+        err = 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:
+        # we're assuming that the output is line-buffered,
+        # which is not unreasonable
+        return (f.readline(), False)
+      time.sleep(0.01)
     return ('', True)
 else:
   def readWithTimeout(f, timeout):
     """Try to read a line of output from the file object |f|. If no output
     is received within |timeout| seconds, return a blank line.
     Returns a tuple (line, did_timeout), where |did_timeout| is True
     if the read timed out, and False otherwise."""
     (r, w, e) = select.select([f], [], [], timeout)
@@ -488,17 +502,17 @@ def triggerBreakpad(proc, utilityPath):
       # SEGV will get picked up by Breakpad's signal handler
       os.kill(proc.pid, signal.SIGSEGV)
       return
     elif IS_WIN32:
       # We should have a "crashinject" program in our utility path
       crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
       if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(proc.pid)]).wait() == 0:
         return
-  #TODO: kill the process such that it triggers Breakpad on OS X
+  #TODO: kill the process such that it triggers Breakpad on OS X (bug 525296)
   log.info("Can't trigger Breakpad, just killing process")
   proc.kill()
 
 ###############
 # RUN THE APP #
 ###############
 
 def runApp(testURL, env, app, profileDir, extraArgs,
--- a/build/pgo/profileserver.py.in
+++ b/build/pgo/profileserver.py.in
@@ -65,14 +65,11 @@ if __name__ == '__main__':
   automation.initializeProfile(PROFILE_DIRECTORY)
   browserEnv = automation.environment()
   browserEnv["XPCOM_DEBUG_BREAK"] = "warn"
 
   url = "http://localhost:%d/index.html" % PORT
   appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
   status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY, {},
                              # the profiling HTML doesn't output anything,
-                             # so let's just set this really high for now.
-                             #FIXME: the POSIX codepath accepts None
-                             # as "no timeout", the Windows codepath
-                             # should too.
-                             timeout = 1800.0)
+                             # so let's just run this without a timeout
+                             timeout = None)
   sys.exit(status)
--- a/build/win32/crashinject.cpp
+++ b/build/win32/crashinject.cpp
@@ -1,128 +1,128 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Crash Injection Utility
- *
- * The Initial Developer of the Original Code is
- * The Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Ted Mielczarek <ted.mielczarek@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
- * Given a PID, this program attempts to inject a DLL into the process
- * with that PID. The DLL it attempts to inject, "crashinjectdll.dll",
- * must exist alongside this exe. The DLL will then crash the process.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <Windows.h>
-
-int main(int argc, char** argv)
-{
-  if (argc != 2) {
-    fprintf(stderr, "Usage: crashinject <PID>\n");
-    return 1;
-  }
-  
-  int pid = atoi(argv[1]);
-  if (pid <= 0) {
-    fprintf(stderr, "Usage: crashinject <PID>\n");
-    return 1;
-  }
-
-  // find our DLL to inject
-  wchar_t filename[_MAX_PATH];
-  if (GetModuleFileNameW(NULL, filename, sizeof(filename) / sizeof(wchar_t)) == 0)
-    return 1;
-
-  wchar_t* slash = wcsrchr(filename, L'\\');
-  if (slash == NULL)
-    return 1;
-
-  slash++;
-  wcscpy(slash, L"crashinjectdll.dll");
-
-  // now find our target process
-  HANDLE targetProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD,
-                                  FALSE,
-                                  pid);
-  if (targetProc == NULL) {
-    fprintf(stderr, "Error %d opening target process\n", GetLastError());
-    return 1;
-  }
-
-  /*
-   * This is sort of insane, but we're implementing a technique described here:
-   * http://www.codeproject.com/KB/threads/winspy.aspx#section_2
-   *
-   * The gist is to use CreateRemoteThread to create a thread in the other
-   * process, but cheat and make the thread function kernel32!LoadLibrary,
-   * so that the only remote data we have to pass to the other process
-   * is the path to the library we want to load. The library we're loading
-   * will then do its dirty work inside the other process.
-   */
-  HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
-  // allocate some memory to hold the path in the remote process
-  void*   pLibRemote = VirtualAllocEx(targetProc, NULL, sizeof(filename),
-                                      MEM_COMMIT, PAGE_READWRITE);
-  if (pLibRemote == NULL) {
-    fprintf(stderr, "Error %d in VirtualAllocEx\n", GetLastError());
-    CloseHandle(targetProc);
-    return 1;
-  }
-
-  if (!WriteProcessMemory(targetProc, pLibRemote, (void*)filename,
-                          sizeof(filename), NULL)) {
-    fprintf(stderr, "Error %d in WriteProcessMemory\n", GetLastError());
-    VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
-    CloseHandle(targetProc);
-    return 1;
-  }
-  // Now create a thread in the target process that will load our DLL
-  HANDLE hThread = CreateRemoteThread(
-                     targetProc, NULL, 0,
-                     (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32,
-                                                            "LoadLibraryW"),
-                     pLibRemote, 0, NULL);
-  if (hThread == NULL) {
-    fprintf(stderr, "Error %d in CreateRemoteThread\n", GetLastError());
-    VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
-    CloseHandle(targetProc);
-    return 1;
-  }
-  WaitForSingleObject(hThread, INFINITE);
-  // Cleanup, not that it's going to matter at this point
-  CloseHandle(hThread);
-  VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
-  CloseHandle(targetProc);
-  
-  return 0;
-}
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Crash Injection Utility
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ted Mielczarek <ted.mielczarek@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Given a PID, this program attempts to inject a DLL into the process
+ * with that PID. The DLL it attempts to inject, "crashinjectdll.dll",
+ * must exist alongside this exe. The DLL will then crash the process.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+int main(int argc, char** argv)
+{
+  if (argc != 2) {
+    fprintf(stderr, "Usage: crashinject <PID>\n");
+    return 1;
+  }
+
+  int pid = atoi(argv[1]);
+  if (pid <= 0) {
+    fprintf(stderr, "Usage: crashinject <PID>\n");
+    return 1;
+  }
+
+  // find our DLL to inject
+  wchar_t filename[_MAX_PATH];
+  if (GetModuleFileNameW(NULL, filename, sizeof(filename) / sizeof(wchar_t)) == 0)
+    return 1;
+
+  wchar_t* slash = wcsrchr(filename, L'\\');
+  if (slash == NULL)
+    return 1;
+
+  slash++;
+  wcscpy(slash, L"crashinjectdll.dll");
+
+  // now find our target process
+  HANDLE targetProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD,
+                                  FALSE,
+                                  pid);
+  if (targetProc == NULL) {
+    fprintf(stderr, "Error %d opening target process\n", GetLastError());
+    return 1;
+  }
+
+  /*
+   * This is sort of insane, but we're implementing a technique described here:
+   * http://www.codeproject.com/KB/threads/winspy.aspx#section_2
+   *
+   * The gist is to use CreateRemoteThread to create a thread in the other
+   * process, but cheat and make the thread function kernel32!LoadLibrary,
+   * so that the only remote data we have to pass to the other process
+   * is the path to the library we want to load. The library we're loading
+   * will then do its dirty work inside the other process.
+   */
+  HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
+  // allocate some memory to hold the path in the remote process
+  void*   pLibRemote = VirtualAllocEx(targetProc, NULL, sizeof(filename),
+                                      MEM_COMMIT, PAGE_READWRITE);
+  if (pLibRemote == NULL) {
+    fprintf(stderr, "Error %d in VirtualAllocEx\n", GetLastError());
+    CloseHandle(targetProc);
+    return 1;
+  }
+
+  if (!WriteProcessMemory(targetProc, pLibRemote, (void*)filename,
+                          sizeof(filename), NULL)) {
+    fprintf(stderr, "Error %d in WriteProcessMemory\n", GetLastError());
+    VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+    CloseHandle(targetProc);
+    return 1;
+  }
+  // Now create a thread in the target process that will load our DLL
+  HANDLE hThread = CreateRemoteThread(
+                     targetProc, NULL, 0,
+                     (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32,
+                                                            "LoadLibraryW"),
+                     pLibRemote, 0, NULL);
+  if (hThread == NULL) {
+    fprintf(stderr, "Error %d in CreateRemoteThread\n", GetLastError());
+    VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+    CloseHandle(targetProc);
+    return 1;
+  }
+  WaitForSingleObject(hThread, INFINITE);
+  // Cleanup, not that it's going to matter at this point
+  CloseHandle(hThread);
+  VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+  CloseHandle(targetProc);
+
+  return 0;
+}
--- a/build/win32/crashinjectdll/Makefile.in
+++ b/build/win32/crashinjectdll/Makefile.in
@@ -1,53 +1,53 @@
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is Mozilla core build scripts.
-#
-# The Initial Developer of the Original Code is
-# The Mozilla Foundation
-#
-# Portions created by the Initial Developer are Copyright (C) 2009
-# the Mozilla Foundation <http://www.mozilla.org/>. All Rights Reserved.
-#
-# Contributor(s): 
-#   Ted Mielczarek <ted.mielczarek@gmail.com>
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-DEPTH = ../../..
-topsrcdir = @top_srcdir@
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-LIBRARY_NAME = crashinjectdll
-DEFFILE = $(srcdir)/crashinjectdll.def
-FORCE_SHARED_LIB = 1
-USE_STATIC_LIBS = 1
-
-CPPSRCS = crashinjectdll.cpp
-
-include $(topsrcdir)/config/rules.mk
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla core build scripts.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation
+#
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Mozilla Foundation <http://www.mozilla.org/>. All Rights Reserved.
+#
+# Contributor(s):
+#   Ted Mielczarek <ted.mielczarek@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME = crashinjectdll
+DEFFILE = $(srcdir)/crashinjectdll.def
+FORCE_SHARED_LIB = 1
+USE_STATIC_LIBS = 1
+
+CPPSRCS = crashinjectdll.cpp
+
+include $(topsrcdir)/config/rules.mk
--- a/build/win32/crashinjectdll/crashinjectdll.cpp
+++ b/build/win32/crashinjectdll/crashinjectdll.cpp
@@ -1,34 +1,34 @@
-#include <stdio.h>
-#include <Windows.h>
-
-// make sure we only ever spawn one thread
-DWORD tid = -1;
-
-DWORD WINAPI CrashingThread(
-  LPVOID lpParameter
-)
-{
-  // not a very friendly DLL
-  volatile int* x = (int *)0x0;
-  *x = 1;
-  return 0;
-}
-
-BOOL WINAPI DllMain(
-  HANDLE hinstDLL, 
-  DWORD dwReason, 
-  LPVOID lpvReserved
-)
-{
-  if (tid == -1)
-    // we have to crash on another thread because LoadLibrary() will
-    // catch memory access errors and return failure to the calling process
-    CreateThread( 
-                 NULL,                   // default security attributes
-                 0,                      // use default stack size  
-                 CrashingThread  ,       // thread function name
-                 NULL,                   // argument to thread function 
-                 0,                      // use default creation flags 
-                 &tid);                  // returns the thread identifier 
-  return TRUE;
-}
+#include <stdio.h>
+#include <windows.h>
+
+// make sure we only ever spawn one thread
+DWORD tid = -1;
+
+DWORD WINAPI CrashingThread(
+  LPVOID lpParameter
+)
+{
+  // not a very friendly DLL
+  volatile int* x = (int *)0x0;
+  *x = 1;
+  return 0;
+}
+
+BOOL WINAPI DllMain(
+  HANDLE hinstDLL,
+  DWORD dwReason,
+  LPVOID lpvReserved
+)
+{
+  if (tid == -1)
+    // we have to crash on another thread because LoadLibrary() will
+    // catch memory access errors and return failure to the calling process
+    CreateThread(
+                 NULL,                   // default security attributes
+                 0,                      // use default stack size
+                 CrashingThread  ,       // thread function name
+                 NULL,                   // argument to thread function
+                 0,                      // use default creation flags
+                 &tid);                  // returns the thread identifier
+  return TRUE;
+}
--- a/build/win32/crashinjectdll/crashinjectdll.def
+++ b/build/win32/crashinjectdll/crashinjectdll.def
@@ -1,3 +1,3 @@
-LIBRARY crashinjectdll
-EXPORTS
-     DllMain
+LIBRARY crashinjectdll
+EXPORTS
+     DllMain
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -627,16 +627,20 @@ MOZ_PLATFORM_HILDON = @MOZ_PLATFORM_HILD
 
 LIBHILDONMIME_CFLAGS	= @LIBHILDONMIME_CFLAGS@
 LIBHILDONMIME_LIBS	= @LIBHILDONMIME_LIBS@
 LIBOSSO_CFLAGS 	= @LIBOSSO_CFLAGS@
 LIBOSSO_LIBS 	= @LIBOSSO_LIBS@
 LIBHILDONFM_CFLAGS	= @LIBHILDONFM_CFLAGS@
 LIBHILDONFM_LIBS	= @LIBHILDONFM_LIBS@
 
+MOZ_ENABLE_LIBCONIC = @MOZ_ENABLE_LIBCONIC@
+LIBCONIC_CFLAGS     = @LIBCONIC_CFLAGS@
+LIBCONIC_LIBS       = @LIBCONIC_LIBS@
+
 MACOS_SDK_DIR	= @MACOS_SDK_DIR@
 NEXT_ROOT	= @NEXT_ROOT@
 GCC_VERSION	= @GCC_VERSION@
 XCODEBUILD_VERSION= @XCODEBUILD_VERSION@
 HAS_XCODE_2_1	= @HAS_XCODE_2_1@
 UNIVERSAL_BINARY= @UNIVERSAL_BINARY@
 HAVE_DTRACE= @HAVE_DTRACE@
 
--- a/config/system-headers
+++ b/config/system-headers
@@ -550,17 +550,16 @@ pango-modules.h
 pango/pangocairo.h
 pango/pangofc-decoder.h
 pango/pangofc-font.h
 pango/pangofc-fontmap.h
 pango/pango-break.h
 pango/pango-fontmap.h
 pango/pango.h
 pango/pangoxft.h
-pango/pangox.h
 pango/pango-utils.h
 pango-types.h
 pascal.h
 Patches.h
 Path.h
 pcfs/pc_dir.h
 Pgenerr.h
 PGenErr.h
--- a/config/utils.py
+++ b/config/utils.py
@@ -71,17 +71,17 @@ def lockFile(lockfile, max_wait = 600):
         # should not occur
         raise
   
     try:
       # the lock file exists, try to stat it to get its age
       # and read its contents to report the owner PID
       f = open(lockfile, "r")
       s = os.stat(lockfile)
-    except OSError, e:
+    except EnvironmentError, e:
       if e.errno != errno.ENOENT:
         sys.exit("%s exists but stat() failed: %s" %
                  (lockfile, e.strerror))
       # we didn't create the lockfile, so it did exist, but it's
       # gone now. Just try again
       continue
   
     # we didn't create the lockfile and it's still there, check
--- a/configure.in
+++ b/configure.in
@@ -1501,16 +1501,35 @@ if test "$GNU_CXX"; then
                            ac_has_wno_invalid_offsetof="yes",
                            ac_has_wno_invalid_offsetof="no")
             CXXFLAGS="$_SAVE_CXXFLAGS"
             AC_LANG_RESTORE
         ])
     if test "$ac_has_wno_invalid_offsetof" = "yes"; then
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-Wno-invalid-offsetof"
     fi
+
+    AC_CACHE_CHECK(whether the compiler supports -Wno-variadic-macros,
+                   ac_has_wno_variadic_macros,
+        [
+            AC_LANG_SAVE
+            AC_LANG_CPLUSPLUS
+            _SAVE_CXXFLAGS="$CXXFLAGS"
+            CXXFLAGS="$CXXFLAGS ${_COMPILER_PREFIX}-Wno-variadic-macros"
+            AC_TRY_COMPILE([],
+                           [return(0);],
+                           ac_has_wno_variadic_macros="yes",
+                           ac_has_wno_variadic_macros="no")
+            CXXFLAGS="$_SAVE_CXXFLAGS"
+            AC_LANG_RESTORE
+        ])
+    if test "$ac_has_wno_variadic_macros" = "yes"; then
+        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-Wno-variadic-macros"
+    fi
+
 else
     _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_MOZILLA_CONFIG_H_ $(ACDEFINES)'
 fi
 
 dnl gcc can come with its own linker so it is better to use the pass-thru calls
 dnl MKSHLIB_FORCE_ALL is used to force the linker to include all object
 dnl files present in an archive. MKSHLIB_UNFORCE_ALL reverts the linker to
 dnl normal behavior.
@@ -4151,22 +4170,26 @@ AC_CACHE_CHECK(for trouble comparing to 
                                 template <class T> int operator!=(const T2*, const T&) { return 0; }],
                                [Foo<int> f; return (0 != f);],
                                ac_cv_trouble_comparing_to_zero=no,
                                ac_cv_trouble_comparing_to_zero=yes)])
 if test "$ac_cv_trouble_comparing_to_zero" = yes ; then
   AC_DEFINE(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
 fi
 
+# try harder, when checking for __thread support, see bug 521750 comment #33 and below
+_SAVE_LDFLAGS=$LDFLAGS
+LDFLAGS="$LDFLAGS $DSO_PIC_CFLAGS $DSO_LDOPTS"
 AC_CACHE_CHECK(for __thread keyword for TLS variables,
                ac_cv_thread_keyword,
                [AC_TRY_LINK([__thread bool tlsIsMainThread = false;],
                             [return tlsIsMainThread;],
                             ac_cv_thread_keyword=yes,
                             ac_cv_thread_keyword=no)])
+LDFLAGS=$_SAVE_LDFLAGS
 if test "$ac_cv_thread_keyword" = yes; then
   AC_DEFINE(HAVE_THREAD_TLS_KEYWORD)
 fi
 
 dnl End of C++ language/feature checks
 AC_LANG_C
 
 dnl ========================================================
@@ -6216,16 +6239,38 @@ dnl = Disable zipwriter
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(zipwriter,
 [  --disable-zipwriter             Disable zipwriter component],
     MOZ_ZIPWRITER=,
     MOZ_ZIPWRITER=1 )
 AC_SUBST(MOZ_ZIPWRITER)
 
 dnl ========================================================
+dnl = Disable libconic
+dnl ========================================================
+MOZ_ENABLE_LIBCONIC=1
+MOZ_ARG_DISABLE_BOOL(libconic,
+[  --disable-libconic              Disable libconic],
+    MOZ_ENABLE_LIBCONIC=,
+    MOZ_ENABLE_LIBCONIC=1 )
+
+if test -n "$MOZ_ENABLE_LIBCONIC"; then
+    PKG_CHECK_MODULES(LIBCONIC, conic,
+                      MOZ_ENABLE_LIBCONIC=1,
+                      MOZ_ENABLE_LIBCONIC=)
+fi
+if test "$MOZ_ENABLE_LIBCONIC"; then
+    AC_DEFINE(MOZ_ENABLE_LIBCONIC)
+fi
+
+AC_SUBST(MOZ_ENABLE_LIBCONIC)
+AC_SUBST(LIBCONIC_CFLAGS)
+AC_SUBST(LIBCONIC_LIBS)
+ 
+dnl ========================================================
 dnl = Hildon and OSSO checks
 dnl ========================================================
 PKG_CHECK_MODULES(LIBHILDONMIME,libhildonmime,
                   MOZ_PLATFORM_HILDON=1,
                   MOZ_PLATFORM_HILDON=)
 if test $MOZ_PLATFORM_HILDON; then
    AC_DEFINE(MOZ_PLATFORM_HILDON)
    X11_COMPOSITED_PLUGINS="yes"
--- a/content/base/public/nsIDOMFile.idl
+++ b/content/base/public/nsIDOMFile.idl
@@ -43,14 +43,14 @@ interface nsIDOMFileError;
 interface nsIDOMFile : nsISupports
 {
   //fileName and fileSize are now deprecated attributes
   readonly attribute DOMString fileName;
   readonly attribute unsigned long long fileSize;
 
   readonly attribute DOMString name;
   readonly attribute unsigned long long size;
-  readonly attribute DOMString mediaType;
+  readonly attribute DOMString type;
 
   DOMString getAsText(in DOMString encoding); // raises(FileException) on retrieval
   DOMString getAsDataURL();             // raises(FileException) on retrieval
   DOMString getAsBinary();              // raises(FileException) on retrieval
 };
--- a/content/base/public/nsIDOMFileReader.idl
+++ b/content/base/public/nsIDOMFileReader.idl
@@ -45,17 +45,17 @@ interface nsIDOMFileError;
 interface nsIDOMFileReader : nsISupports 
 {
   void readAsBinaryString(in nsIDOMFile filedata);
   void readAsText(in nsIDOMFile filedata, [optional] in DOMString encoding);
   void readAsDataURL(in nsIDOMFile file);
 
   void abort();
 
-  const unsigned short INITIAL = 0;
+  const unsigned short EMPTY = 0;
   const unsigned short LOADING = 1;
   const unsigned short DONE = 2;
   readonly attribute unsigned short readyState;
 
   readonly attribute DOMString result;
   readonly attribute nsIDOMFileError error;
 
   // event handler attributes
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1173,24 +1173,26 @@ public:
    * so once can know whether a document is expected to be rendered left-to-right
    * or right-to-left.
    */
   virtual PRBool IsDocumentRightToLeft() { return PR_FALSE; }
 
   enum DocumentTheme {
     Doc_Theme_Uninitialized, // not determined yet
     Doc_Theme_None,
+    Doc_Theme_Neutral,
     Doc_Theme_Dark,
     Doc_Theme_Bright
   };
 
   /**
-   * Returns Doc_Theme_None if there is no lightweight theme specified, Doc_Theme_Dark
-   * for a dark theme and Doc_Theme_Bright for a light theme. This is used to
-   * determine the state of the pseudoclasses :-moz-lwtheme and :-moz-lwtheme-text.
+   * Returns Doc_Theme_None if there is no lightweight theme specified,
+   * Doc_Theme_Dark for a dark theme, Doc_Theme_Bright for a light theme, and
+   * Doc_Theme_Neutral for any other theme. This is used to determine the state
+   * of the pseudoclasses :-moz-lwtheme and :-moz-lwtheme-text.
    */
   virtual int GetDocumentLWTheme() { return Doc_Theme_None; }
 
   /**
    * Gets the document's cached pointer to the first <base> element in this
    * document which has an href attribute.  If the document doesn't contain any
    * <base> elements with an href, returns null.
    */
--- a/content/base/public/nsIScriptElement.h
+++ b/content/base/public/nsIScriptElement.h
@@ -38,34 +38,36 @@
 
 #ifndef nsIScriptElement_h___
 #define nsIScriptElement_h___
 
 #include "nsISupports.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
+#include "nsWeakPtr.h"
+#include "nsIParser.h"
 
-// e68ddc48-4055-4ba9-978d-c49d9cf3189a
 #define NS_ISCRIPTELEMENT_IID \
-{ 0xe68ddc48, 0x4055, 0x4ba9, \
-  { 0x97, 0x8d, 0xc4, 0x9d, 0x9c, 0xf3, 0x18, 0x9a } }
+{ 0xa28c198e, 0x14f0, 0x42b1, \
+{ 0x8f, 0x6b, 0x0e, 0x7f, 0xca, 0xb4, 0xf4, 0xe8 } }
 
 /**
  * Internal interface implemented by script elements
  */
 class nsIScriptElement : public nsIScriptLoaderObserver {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
 
   nsIScriptElement()
     : mLineNumber(0),
       mIsEvaluated(PR_FALSE),
       mMalformed(PR_FALSE),
-      mDoneAddingChildren(PR_TRUE)
+      mDoneAddingChildren(PR_TRUE),
+      mCreatorParser(nsnull)
   {
   }
 
   /**
    * Content type identifying the scripting language. Can be empty, in
    * which case javascript will be assumed.
    */
   virtual void GetScriptType(nsAString& type) = 0;
@@ -117,18 +119,59 @@ public:
   }
 
   void WillCallDoneAddingChildren()
   {
     NS_ASSERTION(mDoneAddingChildren, "unexpected, but not fatal");
     mDoneAddingChildren = PR_FALSE;
   }
 
+  void SetCreatorParser(nsIParser* aParser)
+  {
+    mCreatorParser = getter_AddRefs(NS_GetWeakReference(aParser));
+  }
+
+  /**
+   * Informs the creator parser that the evaluation of this script is starting
+   */
+  void BeginEvaluating()
+  {
+    // Once the async attribute is supported, don't do this if this is an
+    // async script.
+    nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
+    if (parser) {
+      parser->BeginEvaluatingParserInsertedScript();
+    }
+  }
+
+  /**
+   * Informs the creator parser that the evaluation of this script is ending
+   */
+  void EndEvaluating()
+  {
+    // Once the async attribute is supported, don't do this if this is an
+    // async script.
+    nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
+    if (parser) {
+      parser->EndEvaluatingParserInsertedScript();
+    }
+  }
+  
+  /**
+   * Retrieves a pointer to the creator parser if this has one or null if not
+   */
+  already_AddRefed<nsIParser> GetCreatorParser()
+  {
+    nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
+    return parser.forget();
+  }
+
 protected:
   PRUint32 mLineNumber;
   PRPackedBool mIsEvaluated;
   PRPackedBool mMalformed;
   PRPackedBool mDoneAddingChildren;
+  nsWeakPtr    mCreatorParser;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptElement, NS_ISCRIPTELEMENT_IID)
 
 #endif // nsIScriptElement_h___
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -120,35 +120,35 @@ nsDOMFile::GetSize(PRUint64 *aFileSize)
   }
 
   *aFileSize = fileSize;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFile::GetMediaType(nsAString &aMediaType)
+nsDOMFile::GetType(nsAString &aType)
 {
   if (!mContentType.Length()) {
     nsresult rv;
     nsCOMPtr<nsIMIMEService> mimeService =
       do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCAutoString mediaType;
-    rv = mimeService->GetTypeFromFile(mFile, mediaType);
+    nsCAutoString mimeType;
+    rv = mimeService->GetTypeFromFile(mFile, mimeType);
     if (NS_FAILED(rv)) {
-      SetDOMStringToNull(aMediaType);
+      aType.Truncate();
       return NS_OK;
     }
 
-    AppendUTF8toUTF16(mediaType, mContentType);
+    AppendUTF8toUTF16(mimeType, mContentType);
   }
 
-  aMediaType = mContentType;
+  aType = mContentType;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMFile::GetAsText(const nsAString &aCharset, nsAString &aResult)
 {
   aResult.Truncate();
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -149,17 +149,17 @@ nsDOMFileReader::Notify(const char *aCha
   return NS_OK;
 }
 
 //nsDOMFileReader constructors/initializers
 
 nsDOMFileReader::nsDOMFileReader()
   : mFileData(nsnull), mReadCount(0),
     mDataLen(0), mDataFormat(0),
-    mReadyState(nsIDOMFileReader::INITIAL),
+    mReadyState(nsIDOMFileReader::EMPTY),
     mProgressEventWasDelayed(PR_FALSE),
     mTimerIsActive(PR_FALSE),
     mReadTotal(0), mReadTransferred(0),
     mReadComplete(PR_TRUE)
 {
   nsLayoutStatics::AddRef();
 }
 
@@ -314,17 +314,17 @@ nsDOMFileReader::Abort()
   //Clean up memory buffer
   PR_Free(mFileData);
   mFileData = nsnull;
 
   //Dispatch the abort event
   DispatchProgressEvent(NS_LITERAL_STRING(ABORT_STR));
   DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
 
-  mReadyState = nsIDOMFileReader::INITIAL;
+  mReadyState = nsIDOMFileReader::EMPTY;
 
   return NS_OK;
 }
 
 // nsITimerCallback
 NS_IMETHODIMP
 nsDOMFileReader::Notify(nsITimer* aTimer)
 {
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -504,16 +504,25 @@ nsScriptLoader::ProcessScriptElement(nsI
     if (i != nsTArray<PreloadInfo>::NoIndex) {
       request = mPreloads[i].mRequest;
       request->mElement = aElement;
       request->mJSVersion = version;
       request->mDefer = mDeferEnabled && aElement->GetScriptDeferred() &&
         !aElement->GetScriptAsync();
       mPreloads.RemoveElementAt(i);
 
+      if (nsContentUtils::GetBoolPref("content.scriptloader.logloads")) {
+        nsCString spec;
+        request->mURI->GetSpec(spec);
+        printf("Grabbing existing speculative load for %s (%p). async:%d defer:%d\n",
+               spec.get(), request.get(), aElement->GetScriptAsync(),
+               request->mDefer);
+      }
+
+
       rv = CheckContentPolicy(mDocument, aElement, request->mURI, type);
       if (NS_FAILED(rv)) {
         // Note, we're dropping our last ref to request here.
         return rv;
       }
 
       // Can we run the script now?
       // This is true if we're done loading, the script isn't deferred and
@@ -553,28 +562,40 @@ nsScriptLoader::ProcessScriptElement(nsI
   // First check to see if this is an external script
   if (scriptURI) {
     request->mDefer = mDeferEnabled && aElement->GetScriptDeferred() &&
       !aElement->GetScriptAsync();
     request->mURI = scriptURI;
     request->mIsInline = PR_FALSE;
     request->mLoading = PR_TRUE;
 
+    if (nsContentUtils::GetBoolPref("content.scriptloader.logloads")) {
+      nsCString spec;
+      request->mURI->GetSpec(spec);
+      printf("Starting normal load for %s (%p). async:%d defer:%d\n",
+             spec.get(), request.get(), aElement->GetScriptAsync(),
+             request->mDefer);
+    }
+
     rv = StartLoad(request, type);
     if (NS_FAILED(rv)) {
       return rv;
     }
   } else {
     request->mDefer = PR_FALSE;
     request->mLoading = PR_FALSE;
     request->mIsInline = PR_TRUE;
     request->mURI = mDocument->GetDocumentURI();
 
     request->mLineNo = aElement->GetScriptLineNumber();
 
+    if (nsContentUtils::GetBoolPref("content.scriptloader.logloads")) {
+      printf("Creating inline request (%p).\n", request.get());
+    }
+
     // If we've got existing pending requests, add ourselves
     // to this list.
     if (!hadPendingRequests && ReadyToExecuteScripts() &&
         nsContentUtils::IsSafeToRunScript()) {
       return ProcessRequest(request);
     }
   }
 
@@ -604,30 +625,36 @@ nsScriptLoader::ProcessRequest(nsScriptL
 {
   NS_ASSERTION(ReadyToExecuteScripts() && nsContentUtils::IsSafeToRunScript(),
                "Caller forgot to check ReadyToExecuteScripts()");
 
   NS_ENSURE_ARG(aRequest);
   nsAFlatString* script;
   nsAutoString textData;
 
+  if (nsContentUtils::GetBoolPref("content.scriptloader.logloads")) {
+    printf("Running request (%p).\n", aRequest);
+  }
+
   // If there's no script text, we try to get it from the element
   if (aRequest->mIsInline) {
     // XXX This is inefficient - GetText makes multiple
     // copies.
     aRequest->mElement->GetScriptText(textData);
 
     script = &textData;
   }
   else {
     script = &aRequest->mScriptText;
   }
 
   FireScriptAvailable(NS_OK, aRequest);
+  aRequest->mElement->BeginEvaluating();
   nsresult rv = EvaluateScript(aRequest, *script);
+  aRequest->mElement->EndEvaluating();
   FireScriptEvaluated(rv, aRequest);
 
   return rv;
 }
 
 void
 nsScriptLoader::FireScriptAvailable(nsresult aResult,
                                     nsScriptLoadRequest* aRequest)
@@ -952,16 +979,23 @@ nsScriptLoader::OnStreamComplete(nsIStre
                                  nsresult aStatus,
                                  PRUint32 aStringLen,
                                  const PRUint8* aString)
 {
   nsScriptLoadRequest* request = static_cast<nsScriptLoadRequest*>(aContext);
   NS_ASSERTION(request, "null request in stream complete handler");
   NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
 
+  if (nsContentUtils::GetBoolPref("content.scriptloader.logloads")) {
+    nsCString spec;
+    request->mURI->GetSpec(spec);
+    printf("Finished loading %s (%p). status:%d\n", spec.get(), request,
+           aStatus);
+  }
+
   nsresult rv = PrepareLoadedRequest(request, aLoader, aStatus, aStringLen,
                                      aString);
   if (NS_FAILED(rv)) {
     if (mRequests.RemoveObject(request) ||
         mAsyncRequests.RemoveObject(request)) {
       FireScriptAvailable(rv, request);
     } else {
       mPreloads.RemoveElement(request, PreloadRequestComparator());
@@ -1105,16 +1139,24 @@ nsScriptLoader::PreloadURI(nsIURI *aURI,
     return;
   }
 
   request->mURI = aURI;
   request->mIsInline = PR_FALSE;
   request->mLoading = PR_TRUE;
   request->mDefer = PR_FALSE; // This is computed later when we go to execute the
                               // script.
+
+  if (nsContentUtils::GetBoolPref("content.scriptloader.logloads")) {
+    nsCString spec;
+    request->mURI->GetSpec(spec);
+    printf("Starting speculative load for %s (%p).\n", spec.get(),
+           request.get());
+  }
+
   nsresult rv = StartLoad(request, aType);
   if (NS_FAILED(rv)) {
     return;
   }
 
   PreloadInfo *pi = mPreloads.AppendElement();
   pi->mRequest = request;
   pi->mCharset = aCharset;
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -91,16 +91,17 @@
 #include "nsIHTMLDocument.h"
 #include "nsIDOM3Document.h"
 #include "nsIMultiPartChannel.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIStorageStream.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsCommaSeparatedTokenizer.h"
+#include "nsIConsoleService.h"
 
 #define LOAD_STR "load"
 #define ERROR_STR "error"
 #define ABORT_STR "abort"
 #define LOADSTART_STR "loadstart"
 #define PROGRESS_STR "progress"
 #define UPLOADPROGRESS_STR "uploadprogress"
 #define READYSTATE_STR "readystatechange"
@@ -1752,18 +1753,16 @@ nsXMLHttpRequest::OpenRequest(const nsAC
 }
 
 /* void open (in AUTF8String method, in AUTF8String url); */
 NS_IMETHODIMP
 nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url,
                        PRBool async, const nsAString& user,
                        const nsAString& password, PRUint8 optional_argc)
 {
-  nsresult rv = NS_OK;
-
   if (nsContentUtils::GetCurrentJSContext()) {
     // We're (likely) called from JS
 
     // Find out if UniversalBrowserRead privileges are enabled
     if (nsContentUtils::IsCallerTrustedForRead()) {
       mState |= XML_HTTP_REQUEST_XSITEENABLED;
     } else {
       mState &= ~XML_HTTP_REQUEST_XSITEENABLED;
@@ -2233,16 +2232,35 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
     httpChannel->GetRequestMethod(method); // If GET, method name will be uppercase
 
     if (!IsSystemPrincipal(mPrincipal)) {
       nsCOMPtr<nsIURI> codebase;
       mPrincipal->GetURI(getter_AddRefs(codebase));
 
       httpChannel->SetReferrer(codebase);
     }
+
+    // Some extensions override the http protocol handler and provide their own
+    // implementation. The channels returned from that implementation doesn't
+    // seem to always implement the nsIUploadChannel2 interface, presumably
+    // because it's a new interface.
+    // Eventually we should remove this and simply require that http channels
+    // implement the new interface.
+    // See bug 529041
+    nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
+      do_QueryInterface(httpChannel);
+    if (!uploadChannel2) {
+      nsCOMPtr<nsIConsoleService> consoleService =
+        do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+      if (consoleService) {
+        consoleService->LogStringMessage(NS_LITERAL_STRING(
+          "Http channel implementation doesn't support nsIUploadChannel2. An extension has supplied a non-functional http protocol handler. This will break behavior and in future releases not work at all."
+                                                           ).get());
+      }
+    }
   }
 
   mUploadTransferred = 0;
   mUploadTotal = 0;
   // By default we don't have any upload, so mark upload complete.
   mUploadComplete = PR_TRUE;
   mErrorLoad = PR_FALSE;
   mLoadLengthComputable = PR_FALSE;
@@ -2374,19 +2392,16 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = converter->ConvertToInputStream(serial,
                                            getter_AddRefs(postDataStream));
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (postDataStream) {
-      nsCOMPtr<nsIUploadChannel2> uploadChannel(do_QueryInterface(httpChannel));
-      NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
-
       // If no content type header was set by the client, we set it to
       // application/xml.
       nsCAutoString contentType;
       if (NS_FAILED(httpChannel->
                       GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
                                        contentType)) ||
           contentType.IsEmpty()) {
         contentType = defaultContentType;
@@ -2432,17 +2447,35 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
 
       mUploadComplete = PR_FALSE;
       PRUint32 uploadTotal = 0;
       postDataStream->Available(&uploadTotal);
       mUploadTotal = uploadTotal;
 
       // We want to use a newer version of the upload channel that won't
       // ignore the necessary headers for an empty Content-Type.
-      rv = uploadChannel->ExplicitSetUploadStream(postDataStream, contentType, -1, method, PR_FALSE);
+      nsCOMPtr<nsIUploadChannel2> uploadChannel2(do_QueryInterface(httpChannel));
+      // This assertion will fire if buggy extensions are installed
+      NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel");
+      if (uploadChannel2) {
+          uploadChannel2->ExplicitSetUploadStream(postDataStream, contentType,
+                                                 -1, method, PR_FALSE);
+      }
+      else {
+        // http channel doesn't support the new nsIUploadChannel2. Emulate
+        // as best we can using nsIUploadChannel
+        if (contentType.IsEmpty()) {
+          contentType.AssignLiteral("application/octet-stream");
+        }
+        nsCOMPtr<nsIUploadChannel> uploadChannel =
+          do_QueryInterface(httpChannel);
+        uploadChannel->SetUploadStream(postDataStream, contentType, -1);
+        // Reset the method to its original value
+        httpChannel->SetRequestMethod(method);
+      }
     }
   }
 
   // Reset responseBody
   mResponseBody.Truncate();
 
   // Reset responseXML
   mResponseXML = nsnull;
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -257,16 +257,17 @@ include $(topsrcdir)/config/rules.mk
 		file_XHRDocURI.xml \
 		file_XHRDocURI.xml^headers^ \
 		file_XHRDocURI.text \
 		file_XHRDocURI.text^headers^ \
 		test_bug459424.html \
 		bug461735-redirect1.sjs \
 		bug461735-redirect2.sjs \
 		bug461735-post-redirect.js \
+		test_bug513194.html \
 		test_bug461735.html \
 		test_bug380418.html \
 		test_bug465767.html \
 		test_bug380418.html^headers^ \
 		test_bug422403-1.html \
 		file_xhtmlserializer_1.xhtml \
 		file_xhtmlserializer_1_bodyonly.xhtml \
 		file_xhtmlserializer_1_format.xhtml \
@@ -332,10 +333,14 @@ include $(topsrcdir)/config/rules.mk
 
 # Disabled; see bug 492181
 #		test_plugin_freezing.html
 
 # Disabled for now. Mochitest isn't reliable enough for these.
 # test_bug444546.html \
 # bug444546.sjs \
 
+# Disabled due to making the harness time out
+#		test_bug503473.html \
+#		file_bug503473-frame.sjs \
+
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug503473-frame.sjs
@@ -0,0 +1,23 @@
+function handleRequest(request, response) {
+  response.processAsync();
+  response.setStatusLine(request.httpVersion, 200, "OK");
+  response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  response.write(
+    '<!DOCTYPE html>' +
+    '<div></div>' +
+    '<script>' +
+    'function doWrite() {' +
+    '  document.write("<p></p>");' +
+    '  parent.done();' +
+    '  document.close();' +
+    '}' +
+    'setTimeout(doWrite, 1);' +
+    '</script>' 
+  );
+
+  response.bodyOutputStream.flush();
+  // leave the stream open
+}
+
--- a/content/base/test/file_bug503481b_inner.html
+++ b/content/base/test/file_bug503481b_inner.html
@@ -1,14 +1,21 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <!-- Async script that isn't preloaded -->
 <script async src="file_bug503481.sjs?blockOn=R&body=runFirst();"></script>
 <script>
+function enableLogs(b) {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+              .getService(Components.interfaces.nsIPrefBranch);
+  prefs.setBoolPref("content.scriptloader.logloads", b);
+}
+enableLogs(true);
 firstRan = false;
 secondRan = false;
 thirdRan = false;
 forthRan = false;
 fifthRan = false;
 sixthRan = false;
 function runFirst() {
   firstRan = true;
@@ -32,16 +39,17 @@ function runSixth() {
 
 function done() {
   parent.is(firstRan, true, "first should have run by onload");
   parent.is(secondRan, true, "second should have run by onload");
   parent.is(thirdRan, true, "third should have run by onload");
   parent.is(forthRan, true, "forth should have run by onload");
   parent.is(fifthRan, true, "fifth should have run by onload");
   parent.is(sixthRan, true, "sixth should have run by onload");
+  enableLogs(false);
   parent.SimpleTest.finish();
 }
 
 var reqs = [];
 function unblock(s) {
   xhr = new XMLHttpRequest();
   xhr.open("GET", "file_bug503481.sjs?unblock=" + s);
   xhr.send();
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug503473.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=503473
+-->
+<head>
+  <title>Test for Bug 503473</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.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>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=503473">Mozilla Bug 503473</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 503473 **/
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+          .getService(Components.interfaces.nsIPrefBranch);
+var gOriginalHtml5Pref = prefs.getBoolPref("html5.enable");
+prefs.setBoolPref("html5.enable", true);
+
+SimpleTest.waitForExplicitFinish();
+
+function done() {
+  var iframe = document.getElementById("iframe");
+  var divs = iframe.contentWindow.document.getElementsByTagName("div").length;
+  is(divs, 0, "Div wasn't blown away.")
+
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  prefs.setBoolPref("html5.enable", gOriginalHtml5Pref);
+
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+<div id="content" style="display: none">
+  <iframe id='iframe' src="file_bug503473-frame.sjs">
+  </iframe>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug513194.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=513194
+-->
+<head>
+  <title>Test for Bug 513194</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">
+
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+  const Cc = Components.classes;
+  const Ci = Components.interfaces;
+  const Cr = Components.results;
+
+  var consoleService =
+    Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+
+  var consoleListener = {
+    seenError: false,
+
+    observe: function(message) {
+      netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+      if (this.seenError) {
+        ok(false, "Seen too many errors!");
+      }
+      
+      this.seenError = true;
+
+      ok(message.message.indexOf("Unknown property") > -1,
+         "Wrong message");
+    },
+    
+    finish: function() {
+      ok(this.seenError , "Didn't get message.");
+      SimpleTest.finish();
+    },
+
+    QueryInterface: function(iid) {
+      netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+      if (iid.equals(Ci.nsIConsoleListener) ||
+          iid.equals(Ci.nsISupports)) {
+        return this;
+      }
+      throw Cr.NS_NOINTERFACE;
+    }
+  };
+
+  consoleService.reset();
+  consoleService.registerListener(consoleListener);
+  SimpleTest.waitForExplicitFinish();
+
+  document.write("<style>qux { foo: bar; }<\/style>");
+
+  function done() {
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    consoleListener.finish();
+    consoleService.unregisterListener(consoleListener);
+  }
+  setTimeout(done, 1);
+</script>
+</pre>
+</body>
+</html>
+
--- a/content/base/test/test_fileapi.html
+++ b/content/base/test/test_fileapi.html
@@ -22,16 +22,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 var testCounter = 0;
 SimpleTest.waitForExplicitFinish();
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
 // Write a test file > 8192 characters
 
+is(FileReader.EMPTY, 0, "correct EMPTY value");
+is(FileReader.LOADING, 1, "correct LOADING value");
+is(FileReader.DONE, 2, "correct DONE value");
+
 var testData = "asdfblahqwer";
 for (var i = 0; i < 10; i++) {
   testData = testData + testData;
 }
 var testData2 = testData + "a";
 var testData3 = testData + "as";
 
 //Ensure we have different sizes of data for thoroughly testing data URI retrieval
@@ -57,18 +61,20 @@ var utf32File = createFileWithData(utf32
 var file = createFileWithData(testData, "00");
 var domFileData = file.getAsDataURL();
 var domFileBinary = file.getAsBinary();
 
 var domFileBinary2 = utf16File.getAsBinary();
 var domFileBinary3 = utf32File.getAsBinary();
 
 var request1 = new FileReader();
+is(request1.readyState, FileReader.EMPTY, "correct initial readyState");
 request1.onload = handleTextISO1;
 request1.readAsText(file, "iso-8859-1");
+is(request1.readyState, FileReader.LOADING, "correct loading readyState");
 
 var request2 = new FileReader();
 request2.onload = handleTextUTF8;
 request2.readAsText(file);
 
 var request3 = new FileReader();
 request3.onload = handleTextUTF8;
 request3.readAsText(file, "");
@@ -84,18 +90,20 @@ request5.onload = handleTextUTF16;
 request5.readAsText(utf16File, "UTF-16");
 
 var request6 = new FileReader();
 request6.onload = handleTextUTF32;
 request6.readAsText(utf32File, "UTF-32");
 
 //Test binary data accessor
 var request7 = new FileReader();
+is(request7.readyState, FileReader.EMPTY, "correct initial readyState");
 request7.onload = handleDataBinary;
 request7.readAsBinaryString(file);
+is(request7.readyState, FileReader.LOADING, "correct loading readyState");
 
 var request71 = new FileReader();
 request71.onload = handleDataBinary16;
 request71.readAsBinaryString(utf16File);
 
 var request72 = new FileReader();
 request72.onload = handleDataBinary32;
 request72.readAsBinaryString(utf32File);
@@ -167,16 +175,17 @@ function handleCancel(event) {
   var fileAsText = event.target.result;
   var error = event.target.error;
   is(error.code, FileError.ABORT_ERR, "error code set to CANCELED for canceled reads");
   is(fileAsText, null, "file data should be null on canceled reads");
   testHasRun();
 }
 
 function handleTextISO1(event) {
+  is(event.target.readyState, FileReader.DONE, "correct final readyState");
   var fileAsText = event.target.result;
   var error = event.target.error;
   is(error, null, "error code set to null for successful data accesses");
   is(testData.length, fileAsText.length, "iso-1 async length should match testdata");
   is(testData, fileAsText, "iso-1 async string result should match testdata");
   testHasRun();
 }
 
@@ -227,16 +236,17 @@ function handleDataURI1(event) {
 function handleDataURI2(event) {
   var fileAsDataURI = event.target.result;
   is(domFileData2.length, fileAsDataURI.length, "data URI async length should match dom file data2");
   is(domFileData2, fileAsDataURI, "data URI async string result should match dom file data2");
   testHasRun();
 }
 
 function handleDataBinary(event) {
+  is(event.target.readyState, FileReader.DONE, "correct final readyState");
   var fileAsBinary = event.target.result;
   is(domFileBinary.length, fileAsBinary.length, "binary data async length should match dom file binary");
   is(domFileBinary, fileAsBinary, "binary data async string result should match dom file binary");
   testHasRun();
 }
 
 function handleDataBinary16(event) {
   var fileAsBinary = event.target.result;
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -293,64 +293,16 @@ WebGLContext::CreateUnsignedIntArray(nsI
 
 /* readonly attribute nsIDOMHTMLCanvasElement canvas; */
 NS_IMETHODIMP
 WebGLContext::GetCanvas(nsIDOMHTMLCanvasElement **aCanvas)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-/* readonly attribute nsIWebGLBuffer currentArrayBufferBinding; */
-NS_IMETHODIMP
-WebGLContext::GetCurrentArrayBufferBinding(nsIWebGLBuffer **aCurrentArrayBufferBinding)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* readonly attribute nsIWebGLBuffer currentElementArrayBufferBinding; */
-NS_IMETHODIMP
-WebGLContext::GetCurrentElementArrayBufferBinding(nsIWebGLBuffer **aCurrentElementArrayBufferBinding)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* readonly attribute nsIWebGLFramebuffer currentFramebufferBinding; */
-NS_IMETHODIMP
-WebGLContext::GetCurrentFramebufferBinding(nsIWebGLFramebuffer **aCurrentFramebufferBinding)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* readonly attribute nsIWebGLRenderbuffer currentRenderbufferBinding; */
-NS_IMETHODIMP
-WebGLContext::GetCurrentRenderbufferBinding(nsIWebGLRenderbuffer **aCurrentRenderbufferBinding)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* readonly attribute nsIWebGLTexture currentTextureBinding2D; */
-NS_IMETHODIMP
-WebGLContext::GetCurrentTextureBinding2D(nsIWebGLTexture **aCurrentTextureBinding2D)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* readonly attribute nsIWebGLTexture currentTextureBindingCubeMap; */
-NS_IMETHODIMP
-WebGLContext::GetCurrentTextureBindingCubeMap(nsIWebGLTexture **aCurrentTextureBindingCubeMap)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* readonly attribute nsIWebGLProgram currentProgram; */
-NS_IMETHODIMP
-WebGLContext::GetCurrentProgram(nsIWebGLProgram **aCurrentProgram)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
 
 /* void present (); */
 NS_IMETHODIMP
 WebGLContext::Present()
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
@@ -1505,16 +1457,44 @@ WebGLContext::GetBufferParameteri(GLenum
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
+WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    MakeContextCurrent();
+
+    switch (pname) {
+        case LOCAL_GL_BUFFER_SIZE:
+        case LOCAL_GL_BUFFER_USAGE:
+        case LOCAL_GL_BUFFER_ACCESS:
+        case LOCAL_GL_BUFFER_MAPPED:
+        {
+            PRInt32 iv = 0;
+            gl->fGetBufferParameteriv(target, pname, (GLint*) &iv);
+            js.SetRetVal(iv);
+        }
+            break;
+
+        default:
+            return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 WebGLContext::GetFramebufferAttachmentParameteri(GLenum target, GLenum attachment, GLenum pname, GLint *retval)
 {
     NativeJSContext js;
     if (NS_FAILED(js.error))
         return js.error;
 
     MakeContextCurrent();
 
@@ -1542,16 +1522,53 @@ WebGLContext::GetFramebufferAttachmentPa
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
+WebGLContext::GetFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname)
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    MakeContextCurrent();
+
+    switch (attachment) {
+        case LOCAL_GL_COLOR_ATTACHMENT0:
+        case LOCAL_GL_DEPTH_ATTACHMENT:
+        case LOCAL_GL_STENCIL_ATTACHMENT:
+            break;
+        default:
+            return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    switch (pname) {
+        case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+        case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+        case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+        case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+        {
+            PRInt32 iv = 0;
+            gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, (GLint*) &iv);
+            js.SetRetVal(iv);
+        }
+            break;
+
+        default:
+            return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 WebGLContext::GetRenderbufferParameteri(GLenum target, GLenum pname, GLint *retval)
 {
     NativeJSContext js;
     if (NS_FAILED(js.error))
         return js.error;
 
     MakeContextCurrent();
 
@@ -1575,16 +1592,49 @@ WebGLContext::GetRenderbufferParameteri(
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
+WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
+{
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    MakeContextCurrent();
+
+    switch (pname) {
+        case LOCAL_GL_RENDERBUFFER_WIDTH:
+        case LOCAL_GL_RENDERBUFFER_HEIGHT:
+        case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
+        case LOCAL_GL_RENDERBUFFER_RED_SIZE:
+        case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
+        case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
+        case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
+        case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
+        case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
+        {
+            PRInt32 iv = 0;
+            gl->fGetRenderbufferParameteriv(target, pname, (GLint*) &iv);
+            js.SetRetVal(iv);
+        }
+            break;
+
+        default:
+            return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 WebGLContext::CreateBuffer(nsIWebGLBuffer **retval)
 {
     MakeContextCurrent();
 
     GLuint name;
     gl->fGenBuffers(1, &name);
 
     WebGLBuffer *globj = new WebGLBuffer(name);
@@ -1660,16 +1710,55 @@ WebGLContext::GetProgrami(nsIWebGLProgra
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
+WebGLContext::GetProgramParameter(nsIWebGLProgram *prog, PRUint32 pname)
+{
+    if (!prog || static_cast<WebGLProgram*>(prog)->Deleted())
+        return ErrorMessage("%s: program is null or deleted!", __FUNCTION__);
+
+    GLuint program = static_cast<WebGLProgram*>(prog)->GLName();
+
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    MakeContextCurrent();
+
+    switch (pname) {
+        case LOCAL_GL_CURRENT_PROGRAM:
+        case LOCAL_GL_DELETE_STATUS:
+        case LOCAL_GL_LINK_STATUS:
+        case LOCAL_GL_VALIDATE_STATUS:
+        case LOCAL_GL_ATTACHED_SHADERS:
+        case LOCAL_GL_INFO_LOG_LENGTH:
+        case LOCAL_GL_ACTIVE_UNIFORMS:
+        case LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH:
+        case LOCAL_GL_ACTIVE_ATTRIBUTES:
+        case LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+        {
+            PRInt32 iv = 0;
+            gl->fGetProgramiv(program, pname, (GLint*) &iv);
+            js.SetRetVal(iv);
+        }
+            break;
+
+        default:
+            return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 WebGLContext::GetProgramInfoLog(nsIWebGLProgram *prog, nsAString& retval)
 {
     if (!prog || static_cast<WebGLProgram*>(prog)->Deleted())
         return ErrorMessage("%s: program is null or deleted!");
 
     GLuint program = static_cast<WebGLProgram*>(prog)->GLName();
 
     MakeContextCurrent();
@@ -1858,45 +1947,16 @@ WebGLContext::GetTexParameterf(GLenum ta
 
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
-/* nsICanvasArray getTexParameterfv (in GLenum target, in GLenum pname); */
-NS_IMETHODIMP
-WebGLContext::GetTexParameterfv(GLenum target, GLenum pname, nsICanvasArray **retval)
-{
-    NativeJSContext js;
-    if (NS_FAILED(js.error))
-        return js.error;
-
-    MakeContextCurrent();
-
-    switch (pname) {
-        case LOCAL_GL_TEXTURE_MIN_FILTER:
-        case LOCAL_GL_TEXTURE_MAG_FILTER:
-        case LOCAL_GL_TEXTURE_WRAP_S:
-        case LOCAL_GL_TEXTURE_WRAP_T:
-        {
-            float fv = 0;
-            gl->fGetTexParameterfv(target, pname, (GLfloat*) &fv);
-            js.SetRetVal(&fv, 1);
-        }
-            break;
-
-        default:
-            return NS_ERROR_NOT_IMPLEMENTED;
-    }
-
-    return NS_OK;
-}
-
 NS_IMETHODIMP
 WebGLContext::GetTexParameteri(GLenum target, GLenum pname, GLint *retval)
 {
     NativeJSContext js;
     if (NS_FAILED(js.error))
         return js.error;
 
     MakeContextCurrent();
@@ -1915,48 +1975,48 @@ WebGLContext::GetTexParameteri(GLenum ta
 
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
-/* nsICanvasArray getTexParameteriv (in GLenum target, in GLenum pname); */
 NS_IMETHODIMP
-WebGLContext::GetTexParameteriv(GLenum target, GLenum pname, nsICanvasArray **retval)
+WebGLContext::GetTexParameter(GLenum target, GLenum pname)
 {
     NativeJSContext js;
     if (NS_FAILED(js.error))
         return js.error;
 
     MakeContextCurrent();
 
     switch (pname) {
         case LOCAL_GL_TEXTURE_MIN_FILTER:
         case LOCAL_GL_TEXTURE_MAG_FILTER:
         case LOCAL_GL_TEXTURE_WRAP_S:
         case LOCAL_GL_TEXTURE_WRAP_T:
         {
-            PRInt32 iv = 0;
-            gl->fGetTexParameteriv(target, pname, (GLint*) &iv);
-            js.SetRetVal(&iv, 1);
+            float fv = 0;
+            gl->fGetTexParameterfv(target, pname, (GLfloat*) &fv);
+            js.SetRetVal(fv);
         }
             break;
 
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
 /* XXX fix */
+/* any getUniform(in WebGLProgram program, in WebGLUniformLocation location) raises(DOMException); */
 NS_IMETHODIMP
-WebGLContext::GetUniformf(nsIWebGLProgram *prog, GLint location, GLfloat *retval)
+WebGLContext::GetUniform(nsIWebGLProgram *prog, GLint location)
 {
     if (!prog || static_cast<WebGLProgram*>(prog)->Deleted())
         return ErrorMessage("%s: program is null or deleted!", __FUNCTION__);
 
     GLuint program = static_cast<WebGLProgram*>(prog)->GLName();
 
     NativeJSContext js;
     if (NS_FAILED(js.error))
@@ -1993,99 +2053,32 @@ WebGLContext::GetUniformf(nsIWebGLProgra
         gl->fGetUniformiv(program, location, iv);
         js.SetRetVal((PRInt32*)iv, unitSize);
     } else {
         js.SetRetValAsJSVal(JSVAL_NULL);
     }
 
     return NS_OK;
 }
-/* nsICanvasArray getUniformfv (in nsIWebGLProgram program, in GLint location); */
-NS_IMETHODIMP
-WebGLContext::GetUniformfv(nsIWebGLProgram *program, GLint location, nsICanvasArray **retval)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-/* GLint getUniformi (in nsIWebGLProgram program, in GLint location); */
-NS_IMETHODIMP
-WebGLContext::GetUniformi(nsIWebGLProgram *program, GLint location, GLint *retval)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* nsICanvasArray getUniformiv (in nsIWebGLProgram program, in GLint location); */
-NS_IMETHODIMP
-WebGLContext::GetUniformiv(nsIWebGLProgram *program, GLint location, nsICanvasArray **retval)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
 
 NS_IMETHODIMP
 WebGLContext::GetUniformLocation(nsIWebGLProgram *prog, const nsAString& name, GLint *retval)
 {
     if (!prog || static_cast<WebGLProgram*>(prog)->Deleted())
         return ErrorMessage("%s: program is null or deleted!", __FUNCTION__);
 
     GLuint program = static_cast<WebGLProgram*>(prog)->GLName();
 
     MakeContextCurrent();
     *retval = gl->fGetUniformLocation(program, NS_LossyConvertUTF16toASCII(name).get());
     return NS_OK;
 }
 
 NS_IMETHODIMP
-WebGLContext::GetVertexAttribf(GLuint index, GLenum pname, GLfloat *retval)
-{
-    NativeJSContext js;
-    if (NS_FAILED(js.error))
-        return js.error;
-
-    MakeContextCurrent();
-
-    switch (pname) {
-        // int
-        case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
-        case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
-        case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
-        case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
-        case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
-        case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
-        {
-            PRInt32 iv = 0;
-            gl->fGetVertexAttribiv(index, pname, (GLint*) &iv);
-            *retval = (GLfloat) iv;
-        }
-            break;
-
-        case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
-        {
-            GLfloat fv[4] = { 0 };
-            gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, &fv[0]);
-            js.SetRetVal(fv, 4);
-        }
-            break;
-
-        // not supported; doesn't make sense to return a pointer unless we have some kind of buffer object abstraction
-        case LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER:
-        default:
-            return NS_ERROR_NOT_IMPLEMENTED;
-
-    }
-
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-WebGLContext::GetVertexAttribfv(GLuint index, GLenum pname, nsICanvasArray **retval)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-WebGLContext::GetVertexAttribi(GLuint index, GLenum pname, GLint *retval)
+WebGLContext::GetVertexAttrib(GLuint index, GLenum pname)
 {
     NativeJSContext js;
     if (NS_FAILED(js.error))
         return js.error;
 
     MakeContextCurrent();
 
     switch (pname) {
@@ -2116,22 +2109,16 @@ WebGLContext::GetVertexAttribi(GLuint in
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
 
     }
 
     return NS_OK;
 }
 
-NS_IMETHODIMP
-WebGLContext::GetVertexAttribiv(GLuint index, GLenum pname, nsICanvasArray **retval)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
 /* GLuint getVertexAttribOffset (in GLuint index, in GLenum pname); */
 NS_IMETHODIMP
 WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname, GLuint *retval)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
@@ -2739,21 +2726,48 @@ WebGLContext::GetShaderi(nsIWebGLShader 
 
         default:
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
-/* nsICanvasIntArray getShaderiv (in nsIWebGLShader shader, in GLenum pname); */
 NS_IMETHODIMP
-WebGLContext::GetShaderiv(nsIWebGLShader *shader, GLenum pname, nsICanvasIntArray **retval)
+WebGLContext::GetShaderParameter(nsIWebGLShader *shobj, GLenum pname)
 {
-    return NS_ERROR_NOT_IMPLEMENTED;
+    if (!shobj || static_cast<WebGLShader*>(shobj)->Deleted())
+        return ErrorMessage("%s: shader is null or deleted!", __FUNCTION__);
+
+    GLuint shader = static_cast<WebGLShader*>(shobj)->GLName();
+    
+    NativeJSContext js;
+    if (NS_FAILED(js.error))
+        return js.error;
+
+    MakeContextCurrent();
+
+    switch (pname) {
+        case LOCAL_GL_SHADER_TYPE:
+        case LOCAL_GL_DELETE_STATUS:
+        case LOCAL_GL_COMPILE_STATUS:
+        case LOCAL_GL_INFO_LOG_LENGTH:
+        case LOCAL_GL_SHADER_SOURCE_LENGTH:
+        {
+            PRInt32 iv = 0;
+            gl->fGetShaderiv(shader, pname, (GLint*) &iv);
+            js.SetRetVal(iv);
+        }
+            break;
+
+        default:
+            return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetShaderInfoLog(nsIWebGLShader *shobj, nsAString& retval)
 {
     if (!shobj || static_cast<WebGLShader*>(shobj)->Deleted())
         return ErrorMessage("%s: shader is null or deleted!", __FUNCTION__);
 
@@ -2955,19 +2969,17 @@ WebGLContext::TexSubImage2D()
     } else {
         jsuint argTarget, argLevel, argX, argY, argWidth, argHeight, argFormat, argType;
         JSObject *argPixelsObj;
         jsuint argPixelsLen;
         if (!::JS_ConvertArguments(js.ctx, js.argc, js.argv, "uuuuuuuuo",
                                    &argTarget, &argLevel, &argX, &argY,
                                    &argWidth, &argHeight, &argFormat, &argType,
                                    &argPixelsObj) ||
-            !argPixelsObj ||
-            !::JS_IsArrayObject(js.ctx, argPixelsObj) ||
-            !::JS_GetArrayLength(js.ctx, argPixelsObj, &argPixelsLen))
+            !argPixelsObj)
             {
                 return ErrorMessage("texSubImage2D: argument error");
                 return NS_ERROR_DOM_SYNTAX_ERR;
             }
 
         switch (argTarget) {
             case LOCAL_GL_TEXTURE_2D:
             case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
@@ -3038,22 +3050,27 @@ WebGLContext::TexSubImage2D()
             return NS_ERROR_DOM_SYNTAX_ERR;
         }
 
         if ((PRUint32) tmp > argPixelsLen) {
             return ErrorMessage("texSubImage2D: array dimensions too small for width, height and pixel format");
             return NS_ERROR_DOM_SYNTAX_ERR;
         }
 
-        SimpleBuffer sbuffer(bufferType, bufferSize, js.ctx, argPixelsObj, argPixelsLen);
-        if (!sbuffer.Valid())
-            return NS_ERROR_FAILURE;
+        nsCOMPtr<nsICanvasArray> arrayObj;
+        nsresult rv;
+        rv = nsContentUtils::XPConnect()->WrapJS(js.ctx, argPixelsObj, NS_GET_IID(nsISupports), getter_AddRefs(arrayObj));
+        arrayObj = do_QueryInterface(arrayObj, &rv);
+
+        if (NS_FAILED(rv) || !arrayObj) {
+            return ErrorMessage("texSubImage2D: pixels arg is not a WebGL array");
+        }
 
         MakeContextCurrent();
-        gl->fTexSubImage2D (argTarget, argLevel, argX, argY, argWidth, argHeight, argFormat, argType, (void *) sbuffer.data);
+        gl->fTexSubImage2D (argTarget, argLevel, argX, argY, argWidth, argHeight, argFormat, argType, arrayObj->NativePointer());
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D()
 {
     // void texImage2D(in GLenum target, in GLint level, in GLenum internalformat,
@@ -3110,19 +3127,17 @@ WebGLContext::TexImage2D()
 
     } else if (js.argc == 9) {
         JSObject *argPixelsObj;
         jsuint argPixelsLen;
         if (!::JS_ConvertArguments(js.ctx, js.argc, js.argv, "uuuuuuuuo",
                                    &argTarget, &argLevel, &argInternalFormat, &argWidth,
                                    &argHeight, &argBorder, &argFormat, &argType,
                                    &argPixelsObj) ||
-            !argPixelsObj ||
-            !::JS_IsArrayObject(js.ctx, argPixelsObj) ||
-            !::JS_GetArrayLength(js.ctx, argPixelsObj, &argPixelsLen))
+            !argPixelsObj)
             {
                 return ErrorMessage("texImage2D: argument error");
                 return NS_ERROR_DOM_SYNTAX_ERR;
             }
         if (argWidth == 0 || argHeight == 0) {
             return ErrorMessage("texImage2D: width or height is zero");
             return NS_ERROR_DOM_SYNTAX_ERR;
         }
@@ -3220,22 +3235,27 @@ WebGLContext::TexImage2D()
             MakeContextCurrent();
             gl->fTexImage2D (argTarget, argLevel, argInternalFormat, argWidth, argHeight, argBorder, argFormat, argType, NULL);
         } else {
             if ((PRUint32) tmp > argPixelsLen) {
                 return ErrorMessage("texImage2D: array dimensions too small for width, height and pixel format");
                 return NS_ERROR_DOM_SYNTAX_ERR;
             }
 
-            SimpleBuffer sbuffer(bufferType, bufferSize, js.ctx, argPixelsObj, argPixelsLen);
-            if (!sbuffer.Valid())
-            return NS_ERROR_FAILURE;
+            nsCOMPtr<nsICanvasArray> arrayObj;
+            nsresult rv;
+            rv = nsContentUtils::XPConnect()->WrapJS(js.ctx, argPixelsObj, NS_GET_IID(nsISupports), getter_AddRefs(arrayObj));
+            arrayObj = do_QueryInterface(arrayObj, &rv);
+
+            if (NS_FAILED(rv) || !arrayObj) {
+                return ErrorMessage("texImage2D: pixels arg is not a WebGL array");
+            }
 
             MakeContextCurrent();
-            gl->fTexImage2D (argTarget, argLevel, argInternalFormat, argWidth, argHeight, argBorder, argFormat, argType, (void *) sbuffer.data);
+            gl->fTexImage2D (argTarget, argLevel, argInternalFormat, argWidth, argHeight, argBorder, argFormat, argType, arrayObj->NativePointer());
         }
     }
     return NS_OK;
 }
 
 #if 0
 // ImageData getImageData (in float x, in float y, in float width, in float height);
 NS_IMETHODIMP
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -950,16 +950,20 @@ nsCanvasRenderingContext2D::InitializeWi
     mThebes->SetLineWidth(1.0);
     mThebes->SetOperator(gfxContext::OPERATOR_OVER);
     mThebes->SetMiterLimit(10.0);
     mThebes->SetLineCap(gfxContext::LINE_CAP_BUTT);
     mThebes->SetLineJoin(gfxContext::LINE_JOIN_MITER);
 
     mThebes->NewPath();
 
+    // always force a redraw, because if the surface dimensions were reset
+    // then the surface became cleared, and we need to redraw everything.
+    Redraw();
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetIsOpaque(PRBool isOpaque)
 {
     if (isOpaque == mOpaque)
         return NS_OK;
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -369,18 +369,17 @@ nsDOMUIEvent::GetIsChar(PRBool* aIsChar)
     default:
       *aIsChar = PR_FALSE;
       return NS_OK;
   }
 }
 
 NS_METHOD nsDOMUIEvent::GetCompositionReply(nsTextEventReply** aReply)
 {
-  if((mEvent->message == NS_COMPOSITION_START) ||
-     (mEvent->message == NS_COMPOSITION_QUERY))
+  if((mEvent->message == NS_COMPOSITION_START))
   {
     *aReply = &(static_cast<nsCompositionEvent*>(mEvent)->theReply);
     return NS_OK;
   }
   *aReply = nsnull;
   return NS_ERROR_FAILURE;
 }
 
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -206,19 +206,17 @@ static const EventDispatchData sMouseMot
 static const EventDispatchData sContextMenuEvents[] = {
   { NS_CONTEXTMENU, HANDLER(&nsIDOMContextMenuListener::ContextMenu) }
 };
 
 static const EventDispatchData sCompositionEvents[] = {
   { NS_COMPOSITION_START,
     HANDLER(&nsIDOMCompositionListener::HandleStartComposition)  },
   { NS_COMPOSITION_END,
-    HANDLER(&nsIDOMCompositionListener::HandleEndComposition)    },
-  { NS_COMPOSITION_QUERY,
-    HANDLER(&nsIDOMCompositionListener::HandleQueryComposition)  }
+    HANDLER(&nsIDOMCompositionListener::HandleEndComposition)    }
 };
 
 static const EventDispatchData sTextEvents[] = {
   { NS_TEXT_TEXT, HANDLER(&nsIDOMTextListener::HandleText) }
 };
 
 static const EventDispatchData sKeyEvents[] = {
   { NS_KEY_UP,    HANDLER(&nsIDOMKeyListener::KeyUp)    },
--- a/content/events/src/nsIMEStateManager.cpp
+++ b/content/events/src/nsIMEStateManager.cpp
@@ -494,16 +494,19 @@ nsIMEStateManager::OnTextStateFocus(nsPr
   NS_ENSURE_TRUE(shell, NS_ERROR_NOT_AVAILABLE);
   
   nsIViewManager* vm = shell->GetViewManager();
   NS_ENSURE_TRUE(vm, NS_ERROR_NOT_AVAILABLE);
 
   nsCOMPtr<nsIWidget> widget;
   nsresult rv = vm->GetRootWidget(getter_AddRefs(widget));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
+  if (!widget) {
+    return NS_OK; // Sometimes, there are no widgets.
+  }
 
   rv = widget->OnIMEFocusChange(PR_TRUE);
   if (rv == NS_ERROR_NOT_IMPLEMENTED)
     return NS_OK;
   NS_ENSURE_SUCCESS(rv, rv);
 
   // OnIMEFocusChange may cause focus and sTextStateObserver to change
   // In that case return and keep the current sTextStateObserver
--- a/content/html/content/src/nsHTMLOptGroupElement.cpp
+++ b/content/html/content/src/nsHTMLOptGroupElement.cpp
@@ -181,17 +181,16 @@ nsHTMLOptGroupElement::InsertChildAt(nsI
     safeMutation.MutationFailed();
   }
   return rv;
 }
 
 nsresult
 nsHTMLOptGroupElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify, PRBool aMutationEvent)
 {
-  NS_ASSERTION(aMutationEvent, "Someone tried to inhibit mutation events on optgroup child removal.");
   nsSafeOptionListMutation safeMutation(GetSelect(), this, nsnull, aIndex);
   nsresult rv = nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify, aMutationEvent);
   if (NS_FAILED(rv)) {
     safeMutation.MutationFailed();
   }
   return rv;
 }
 
--- a/content/html/content/src/nsHTMLTableCellElement.cpp
+++ b/content/html/content/src/nsHTMLTableCellElement.cpp
@@ -366,17 +366,25 @@ void MapAttributesIntoRule(const nsMappe
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
       if (value && value->Type() == nsAttrValue::eEnum)
         aData->mTextData->mTextAlign.SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
     }
 
     if (aData->mTextData->mWhiteSpace.GetUnit() == eCSSUnit_Null) {
       // nowrap: enum
       if (aAttributes->GetAttr(nsGkAtoms::nowrap)) {
-        aData->mTextData->mWhiteSpace.SetIntValue(NS_STYLE_WHITESPACE_NOWRAP, eCSSUnit_Enumerated);
+        // See if our width is not a nonzero integer width.
+        const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
+        nsCompatibility mode = aData->mPresContext->CompatibilityMode();
+        if (!value || value->Type() != nsAttrValue::eInteger ||
+            value->GetIntegerValue() == 0 ||
+            eCompatibility_NavQuirks != mode) {
+          aData->mTextData->mWhiteSpace.SetIntValue(NS_STYLE_WHITESPACE_NOWRAP, eCSSUnit_Enumerated);
+        }
+        
       }
     }
   }
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
     if (aData->mTextData->mVerticalAlign.GetUnit() == eCSSUnit_Null) {
       // valign: enum
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::valign);
       if (value && value->Type() == nsAttrValue::eEnum)
--- a/content/html/content/test/test_bug523771.html
+++ b/content/html/content/test/test_bug523771.html
@@ -18,19 +18,19 @@ method="POST" enctype="multipart/form-da
   <input id=singleFile name=singleFile type=file>
   <input id=multiFile name=multiFile type=file multiple>
 </form>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var filesToKill = [];
 singleFileInput = document.getElementById('singleFile');
 multiFileInput = document.getElementById('multiFile');
-var input1File = { name: "523771_file1", type: null, body: "file1 contents"};
+var input1File = { name: "523771_file1", type: "", body: "file1 contents"};
 var input2Files =
-  [{ name: "523771_file2", type: null, body: "second file contents" },
+  [{ name: "523771_file2", type: "", body: "second file contents" },
    { name: "523771_file3.txt", type: "text/plain", body: "123456" },
    { name: "523771_file4.html", type: "text/html", body: "<html>content</html>" }
   ];
 
 SimpleTest.waitForExplicitFinish();
 
 function setFileInputs () {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
@@ -81,21 +81,21 @@ is(multiFileInput.files.length, 0, "mult
 setFileInputs();
 
 is(singleFileInput.multiple, false, "single-file input .multiple");
 is(multiFileInput.multiple, true, "multi-file input .multiple");
 is(singleFileInput.value, input1File.name, "single-file input .value");
 is(multiFileInput.value, input2Files[0].name, "multi-file input .value");
 is(singleFileInput.files[0].name, input1File.name, "single-file input .files[n].name");
 is(singleFileInput.files[0].size, input1File.body.length, "single-file input .files[n].size");
-is(singleFileInput.files[0].mediaType, input1File.type, "single-file input .files[n].mediaType");
+is(singleFileInput.files[0].type, input1File.type, "single-file input .files[n].type");
 for(i = 0; i < input2Files.length; ++i) {
   is(multiFileInput.files[i].name, input2Files[i].name, "multi-file input .files[n].name");
   is(multiFileInput.files[i].size, input2Files[i].body.length, "multi-file input .files[n].size");
-  is(multiFileInput.files[i].mediaType, input2Files[i].type, "multi-file input .files[n].mediaType");
+  is(multiFileInput.files[i].type, input2Files[i].type, "multi-file input .files[n].type");
 }
 
 document.getElementById('form').submit();
 iframe = document.getElementById('target_iframe');
 iframe.onload = function() {
   response = JSON.parse(iframe.contentDocument.documentElement.textContent);
  is(response[0].headers["Content-Disposition"],
      "form-data; name=\"singleFile\"; filename=\"" + input1File.name +
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -730,16 +730,17 @@ nsHTMLDocument::StartDocumentLoad(const 
     cachingChan->GetCacheToken(getter_AddRefs(cacheToken));
     if (cacheToken)
       cacheDescriptor = do_QueryInterface(cacheToken);
   }
 
   if (needsParser) {
     if (loadAsHtml5) {
       mParser = nsHtml5Module::NewHtml5Parser();
+      mParser->MarkAsNotScriptCreated();
     } else {
       mParser = do_CreateInstance(kCParserCID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   PRInt32 textType = GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions());
 
@@ -2137,17 +2138,18 @@ nsHTMLDocument::WriteCommon(const nsAStr
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   nsresult rv = NS_OK;
 
   void *key = GenerateParserKey();
   if (mWriteState == eDocumentClosed ||
       (mWriteState == ePendingClose &&
-       !mPendingScripts.Contains(key))) {
+       !mPendingScripts.Contains(key)) ||
+      (mParser && !mParser->IsInsertionPointDefined())) {
     mWriteState = eDocumentClosed;
     mParser->Terminate();
     NS_ASSERTION(!mParser, "mParser should have been null'd out");
   }
 
   if (!mParser) {
     rv = Open();
 
@@ -2930,17 +2932,31 @@ nsHTMLDocument::GenerateParserKey(void)
   if (!mScriptLoader) {
     // If we don't have a script loader, then the parser probably isn't parsing
     // anything anyway, so just return null.
     return nsnull;
   }
 
   // The script loader provides us with the currently executing script element,
   // which is guaranteed to be unique per script.
-  return mScriptLoader->GetCurrentScript();
+  if (nsHtml5Module::sEnabled) {
+    nsIScriptElement* script = mScriptLoader->GetCurrentScript();
+    if (script && mParser && mParser->IsScriptCreated()) {
+      nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
+      if (creatorParser != mParser) {
+        // Make scripts that aren't inserted by the active parser of this document
+        // participate in the context of the script that document.open()ed 
+        // this document.
+        return mParser->GetRootContextKey();
+      }
+    }
+    return script;
+  } else {
+    return mScriptLoader->GetCurrentScript();
+  }
 }
 
 /* attribute DOMString designMode; */
 NS_IMETHODIMP
 nsHTMLDocument::GetDesignMode(nsAString & aDesignMode)
 {
   if (HasFlag(NODE_IS_EDITABLE)) {
     aDesignMode.AssignLiteral("on");
--- a/content/media/Makefile.in
+++ b/content/media/Makefile.in
@@ -29,63 +29,60 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-DEPTH		= ../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
+DEPTH     = ../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-MODULE		= content
-LIBRARY_NAME	= gkconmedia_s
-LIBXUL_LIBRARY 	= 1
-
+MODULE = content
+LIBRARY_NAME = gkconmedia_s
+LIBXUL_LIBRARY = 1
 
-EXPORTS		= \
-		nsMediaDecoder.h \
-		nsMediaStream.h \
-		nsMediaCache.h \
-		$(NULL)
+EXPORTS = \
+  nsMediaDecoder.h \
+  nsMediaStream.h \
+  nsMediaCache.h \
+  $(NULL)
 
-CPPSRCS		= \
-		nsMediaDecoder.cpp \
-		nsMediaCache.cpp \
-		nsMediaStream.cpp \
-		$(NULL)
+CPPSRCS = \
+  nsMediaDecoder.cpp \
+  nsMediaCache.cpp \
+  nsMediaStream.cpp \
+  $(NULL)
 
 ifdef MOZ_SYDNEYAUDIO
-EXPORTS		+= \
-		nsAudioStream.h \
-		$(NULL)
-CPPSRCS		+= \
-		nsAudioStream.cpp \
-		$(NULL)
+EXPORTS += \
+  nsAudioStream.h \
+  $(NULL)
+CPPSRCS += \
+  nsAudioStream.cpp \
+  $(NULL)
 endif
 
-DIRS =
-
 ifdef MOZ_OGG
-DIRS += ogg
+PARALLEL_DIRS += ogg
 endif
 
 ifdef MOZ_WAVE
-DIRS += wave
+PARALLEL_DIRS += wave
 endif
 
 ifdef ENABLE_TESTS
-DIRS += test
+PARALLEL_DIRS += test
 endif
 
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
-INCLUDES	+= \
-		-I$(srcdir)/../base/src \
-		-I$(srcdir)/../html/content/src \
-		$(NULL)
+INCLUDES += \
+  -I$(srcdir)/../base/src \
+  -I$(srcdir)/../html/content/src \
+  $(NULL)
--- a/content/media/nsMediaCache.cpp
+++ b/content/media/nsMediaCache.cpp
@@ -185,26 +185,30 @@ public:
   // Verify invariants, especially block list invariants
   void Verify();
 #else
   void Verify() {}
 #endif
 
   PRMonitor* Monitor() { return mMonitor; }
 
+  /**
+   * An iterator that makes it easy to iterate through all streams that
+   * have a given resource ID and are not closed.
+   */
   class ResourceStreamIterator {
   public:
     ResourceStreamIterator(PRInt64 aResourceID) :
       mResourceID(aResourceID), mNext(0) {}
     nsMediaCacheStream* Next()
     {
       while (mNext < gMediaCache->mStreams.Length()) {
         nsMediaCacheStream* stream = gMediaCache->mStreams[mNext];
         ++mNext;
-        if (stream->GetResourceID() == mResourceID)
+        if (stream->GetResourceID() == mResourceID && !stream->IsClosed())
           return stream;
       }
       return nsnull;
     }
   private:
     PRInt64  mResourceID;
     PRUint32 mNext;
   };
@@ -1191,17 +1195,17 @@ nsMediaCache::Update()
         enableReading = predictedNewDataUse < latestNextUse;
       }
 
       if (enableReading) {
         for (PRUint32 j = 0; j < i; ++j) {
           nsMediaCacheStream* other = mStreams[j];
           if (other->mResourceID == stream->mResourceID &&
               !other->mCacheSuspended &&
-              other->mChannelOffset/BLOCK_SIZE == stream->mChannelOffset/BLOCK_SIZE) {
+              other->mChannelOffset/BLOCK_SIZE == desiredOffset/BLOCK_SIZE) {
             // This block is already going to be read by the other stream.
             // So don't try to read it from this stream as well.
             enableReading = PR_FALSE;
             break;
           }
         }
       }
 
new file mode 100644
--- /dev/null
+++ b/content/smil/crashtests/526875-1.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg">
+  <animate attributeName="fill-opacity" by="-1"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/content/smil/crashtests/526875-2.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg">
+  <animate attributeName="fill-opacity" by="1"/>
+</svg>
--- a/content/smil/crashtests/crashtests.list
+++ b/content/smil/crashtests/crashtests.list
@@ -1,2 +1,4 @@
 load 523188-1.svg
 load 525099-1.svg
+load 526875-1.svg
+load 526875-2.svg
--- a/content/smil/nsSMILCSSProperty.cpp
+++ b/content/smil/nsSMILCSSProperty.cpp
@@ -249,20 +249,20 @@ nsSMILCSSProperty::IsPropertyAnimatable(
     case eCSSProperty_fill_opacity:
     case eCSSProperty_fill_rule:
     // case eCSSProperty_filter:
     case eCSSProperty_flood_color:
     case eCSSProperty_flood_opacity:
     // case eCSSProperty_font_family:
     case eCSSProperty_font_size:
     case eCSSProperty_font_size_adjust:
-    // case eCSSProperty_font_stretch:
+    case eCSSProperty_font_stretch:
     case eCSSProperty_font_style:
     case eCSSProperty_font_variant:
-    // case eCSSProperty_font_weight:
+    case eCSSProperty_font_weight:
     case eCSSProperty_image_rendering:
     case eCSSProperty_letter_spacing:
     case eCSSProperty_lighting_color:
     // case eCSSProperty_marker_end:
     // case eCSSProperty_marker_mid:
     // case eCSSProperty_marker_start:
     // case eCSSProperty_mask:
     case eCSSProperty_opacity:
--- a/content/smil/nsSMILCSSValueType.cpp
+++ b/content/smil/nsSMILCSSValueType.cpp
@@ -177,40 +177,48 @@ nsSMILCSSValueType::Add(nsSMILValue& aDe
   NS_ABORT_IF_FALSE(aValueToAdd.mType == this, "Unexpected source type");
 
   ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
   const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd);
 
   NS_ABORT_IF_FALSE(destWrapper && valueToAddWrapper,
                     "these pointers shouldn't be null");
 
+  const nsStyleAnimation::Value* realValueToAdd = &valueToAddWrapper->mCSSValue;
   if (destWrapper->mPropID == eCSSProperty_UNKNOWN) {
-    NS_ABORT_IF_FALSE(destWrapper->mCSSValue.IsNull(),
-                      "If property ID is unset, then the unit should be, too");
+    NS_ABORT_IF_FALSE(destWrapper->mCSSValue.IsNull() &&
+                      !destWrapper->mPresContext,
+                      "Partially-initialized ValueWrapper");
     // We need to update destWrapper, since it's part of an outparam.
     const nsStyleAnimation::Value* zeroVal =
       GetZeroValueForUnit(valueToAddWrapper->mCSSValue.GetUnit());
     if (!zeroVal) {
       // No zero value for this unit --> doesn't support addition.
       return NS_ERROR_FAILURE;
     }
     destWrapper->mCSSValue = *zeroVal;
     destWrapper->mPropID = valueToAddWrapper->mPropID;
     destWrapper->mPresContext = valueToAddWrapper->mPresContext;
+  } else if (valueToAddWrapper->mPropID == eCSSProperty_UNKNOWN) {
+    NS_ABORT_IF_FALSE(valueToAddWrapper->mCSSValue.IsNull() &&
+                      !valueToAddWrapper->mPresContext,
+                      "Partially-initialized ValueWrapper");
+    realValueToAdd = GetZeroValueForUnit(destWrapper->mCSSValue.GetUnit());
+    if (!realValueToAdd) {
+      // No zero value for this unit --> doesn't support addition.
+      return NS_ERROR_FAILURE;
+    }      
   }
-  NS_ABORT_IF_FALSE(valueToAddWrapper->mPropID != eCSSProperty_UNKNOWN &&
-                    !valueToAddWrapper->mCSSValue.IsNull(),
-                    "Added amount should be a parsed value");
 
   // Special case: font-size-adjust is explicitly non-additive
   if (destWrapper->mPropID == eCSSProperty_font_size_adjust) {
     return NS_ERROR_FAILURE;
   }
-  return nsStyleAnimation::Add(destWrapper->mCSSValue,
-                               valueToAddWrapper->mCSSValue, aCount) ?
+  return nsStyleAnimation::Add(destWrapper->mPropID, destWrapper->mCSSValue,
+                               *realValueToAdd, aCount) ?
     NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
                                     const nsSMILValue& aTo,
                                     double& aDistance) const
 {
@@ -220,31 +228,33 @@ nsSMILCSSValueType::ComputeDistance(cons
 
   const ValueWrapper* fromWrapper = ExtractValueWrapper(aFrom);
   const ValueWrapper* toWrapper = ExtractValueWrapper(aTo);
   NS_ABORT_IF_FALSE(fromWrapper && toWrapper,
                     "These pointers shouldn't be null");
 
   const nsStyleAnimation::Value* fromCSSValue;
   if (fromWrapper->mPropID == eCSSProperty_UNKNOWN) {
-    NS_ABORT_IF_FALSE(fromWrapper->mCSSValue.IsNull(),
-                      "If property ID is unset, then the unit should be, too");
+    NS_ABORT_IF_FALSE(fromWrapper->mCSSValue.IsNull() &&
+                      !fromWrapper->mPresContext,
+                      "Partially-initialized ValueWrapper");
     fromCSSValue = GetZeroValueForUnit(toWrapper->mCSSValue.GetUnit());
     if (!fromCSSValue) {
       // No zero value for this unit --> doesn't support distance-computation.
       return NS_ERROR_FAILURE;
     }
   } else {
     fromCSSValue = &fromWrapper->mCSSValue;
   }
   NS_ABORT_IF_FALSE(toWrapper->mPropID != eCSSProperty_UNKNOWN &&
-                    !toWrapper->mCSSValue.IsNull(),
+                    !toWrapper->mCSSValue.IsNull() && toWrapper->mPresContext,
                     "ComputeDistance endpoint should be a parsed value");
 
-  return nsStyleAnimation::ComputeDistance(*fromCSSValue, toWrapper->mCSSValue,
+  return nsStyleAnimation::ComputeDistance(toWrapper->mPropID,
+                                           *fromCSSValue, toWrapper->mCSSValue,
                                            aDistance) ?
     NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
                                 const nsSMILValue& aEndVal,
                                 double aUnitDistance,
@@ -262,31 +272,33 @@ nsSMILCSSValueType::Interpolate(const ns
   const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal);
   ValueWrapper* resultWrapper = ExtractValueWrapper(aResult);
 
   NS_ABORT_IF_FALSE(startWrapper && endWrapper && resultWrapper,
                     "These pointers shouldn't be null");
 
   const nsStyleAnimation::Value* startCSSValue;
   if (startWrapper->mPropID == eCSSProperty_UNKNOWN) {
-    NS_ABORT_IF_FALSE(startWrapper->mCSSValue.IsNull(),
-                      "If property ID is unset, then the unit should be, too");
+    NS_ABORT_IF_FALSE(startWrapper->mCSSValue.IsNull() &&
+                      !startWrapper->mPresContext,
+                      "Partially-initialized ValueWrapper");
     startCSSValue = GetZeroValueForUnit(endWrapper->mCSSValue.GetUnit());
     if (!startCSSValue) {
       // No zero value for this unit --> doesn't support interpolation.
       return NS_ERROR_FAILURE;
     }
   } else {
     startCSSValue = &startWrapper->mCSSValue;
   }
   NS_ABORT_IF_FALSE(endWrapper->mPropID != eCSSProperty_UNKNOWN &&
-                    !endWrapper->mCSSValue.IsNull(),
+                    !endWrapper->mCSSValue.IsNull() && endWrapper->mPresContext,
                     "Interpolate endpoint should be a parsed value");
 
-  if (nsStyleAnimation::Interpolate(*startCSSValue,
+  if (nsStyleAnimation::Interpolate(endWrapper->mPropID,
+                                    *startCSSValue,
                                     endWrapper->mCSSValue,
                                     aUnitDistance,
                                     resultWrapper->mCSSValue)) {
     resultWrapper->mPropID = endWrapper->mPropID;
     resultWrapper->mPresContext = endWrapper->mPresContext;
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
--- a/content/smil/test/Makefile.in
+++ b/content/smil/test/Makefile.in
@@ -45,16 +45,17 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
 	  db_smilCSSFromBy.js \
 	  db_smilCSSFromTo.js \
 	  db_smilCSSPaced.js \
 	  db_smilCSSPropertyList.js \
 	  smilTestUtils.js \
+	  test_smilCSSFontStretchRelative.xhtml \
 	  test_smilCSSFromBy.xhtml \
 	  test_smilCSSFromTo.xhtml \
 	  test_smilCSSInherit.xhtml \
 	  test_smilCSSPaced.xhtml \
 	  test_smilRestart.xhtml \
 	  test_smilGetStartTime.xhtml \
 	  test_smilGetSimpleDuration.xhtml \
 	  test_smilKeySplines.xhtml \
--- a/content/smil/test/db_smilCSSFromTo.js
+++ b/content/smil/test/db_smilCSSFromTo.js
@@ -265,44 +265,52 @@ var gFromToBundles = [
                              toComp: "40px"}),
   ])),
   new TestcaseBundle(gPropList.font_size_adjust, [
     new AnimTestcaseFromTo("0.9", "0.1", { midComp: "0.5" }),
     new AnimTestcaseFromTo("0.5", "0.6", { midComp: "0.55" }),
     new AnimTestcaseFromTo("none", "0.4"),
   ]),
   new TestcaseBundle(gPropList.font_stretch, [
-    new AnimTestcaseFromTo("normal", "wider"),
-    new AnimTestcaseFromTo("narrower", "ultra-condensed"),
-    new AnimTestcaseFromTo("extra-condensed", "condensed"),
-    new AnimTestcaseFromTo("semi-condensed", "semi-expanded"),
-    new AnimTestcaseFromTo("expanded", "extra-expanded"),
-    new AnimTestcaseFromTo("ultra-expanded", "inherit", { toComp: "normal" }),
-  ], "need support for all properties that get stored in nsFont"),
+    new AnimTestcaseFromTo("normal", "wider", {},
+                           "need support for animating between " +
+                           "relative 'font-stretch' values"),
+    new AnimTestcaseFromTo("narrower", "ultra-condensed", {},
+                           "need support for animating between " +
+                           "relative 'font-stretch' values"),
+    new AnimTestcaseFromTo("ultra-condensed", "condensed",
+                           { midComp: "extra-condensed" }),
+    new AnimTestcaseFromTo("semi-condensed", "semi-expanded",
+                           { midComp: "normal" }),
+    new AnimTestcaseFromTo("expanded", "ultra-expanded",
+                           { midComp: "extra-expanded" }),
+    new AnimTestcaseFromTo("ultra-expanded", "inherit",
+                           { midComp: "expanded", toComp: "normal" }),
+  ]),
   new TestcaseBundle(gPropList.font_style, [
     new AnimTestcaseFromTo("italic", "inherit", { toComp: "normal" }),
     new AnimTestcaseFromTo("normal", "italic"),
     new AnimTestcaseFromTo("italic", "oblique"),
     new AnimTestcaseFromTo("oblique", "normal"),
   ]),
   new TestcaseBundle(gPropList.font_variant, [
     new AnimTestcaseFromTo("inherit", "small-caps", { fromComp: "normal" }),
     new AnimTestcaseFromTo("small-caps", "normal"),
   ]),
   new TestcaseBundle(gPropList.font_weight, [
-    new AnimTestcaseFromTo("100", "900"),
-    new AnimTestcaseFromTo("700", "100",
-                           // Note that '700' ends up as "bold" in computed
-                           // style (not the other way around)
-                           { fromComp: "bold" }),
+    new AnimTestcaseFromTo("100", "900", { midComp: "500" }),
+    new AnimTestcaseFromTo("700", "100", { midComp: "400" }),
     new AnimTestcaseFromTo("inherit", "200",
-                           { fromComp: "400" }),
+                           { fromComp: "400", midComp: "300" }),
     new AnimTestcaseFromTo("normal", "bold",
-                           { fromComp: "400" }),
-  ], "need support for all properties that get stored in nsFont"),
+                           { fromComp: "400", midComp: "500", toComp: "700" }),
+    new AnimTestcaseFromTo("lighter", "bolder", {},
+                           "need support for animating between " +
+                           "relative 'font-weight' values"),
+  ]),
   // NOTE: Mozilla doesn't currently support "glyph-orientation-horizontal" or
   // "glyph-orientation-vertical", but I'm testing them here in case we ever
   // add support for them, because they're explicitly not animatable in the SVG
   // spec.
   new TestcaseBundle(gPropList.glyph_orientation_horizontal,
                      [ new AnimTestcaseFromTo("45deg", "60deg") ]),
   new TestcaseBundle(gPropList.glyph_orientation_vertical,
                      [ new AnimTestcaseFromTo("45deg", "60deg") ]),
new file mode 100644
--- /dev/null
+++ b/content/smil/test/test_smilCSSFontStretchRelative.xhtml
@@ -0,0 +1,109 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test for Animation Behavior on CSS Properties</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="smilTestUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<svg id="svg" xmlns="http://www.w3.org/2000/svg">
+</svg>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+/* This testcase verifies that animated values of "wider" and "narrower" for
+   "font-stretch" have the expected effect, across all possible inherited
+   values of the property.
+   XXXdholbert Currently, we don't support animating relative values of
+   font-stretch, so most of the tests here use todo_is() rather than is().
+*/
+
+SimpleTest.waitForExplicitFinish();
+
+const gPropertyName="font-stretch";
+
+// List of non-relative font-stretch values, from smallest to largest
+const gFontStretchValues = [
+  "ultra-condensed",
+  "extra-condensed",
+  "condensed",
+  "semi-condensed",
+  "normal",
+  "semi-expanded",
+  "expanded",
+  "extra-expanded",
+  "ultra-expanded"
+];
+
+function testFontStretchValue(baseValue, narrowerStep, widerStep)
+{
+  var svg = SMILUtil.getSVGRoot();
+  var gElem = document.createElementNS(SVG_NS, "g");
+  gElem.setAttribute("style", "font-stretch: " + baseValue);
+  svg.appendChild(gElem);
+
+  var textElem = document.createElementNS(SVG_NS, "text");
+  gElem.appendChild(textElem);
+
+  var animElem = document.createElementNS(SVG_NS, "set");
+  animElem.setAttribute("attributeName", gPropertyName);
+  animElem.setAttribute("attributeType", "CSS");
+  animElem.setAttribute("begin", "0s");
+  animElem.setAttribute("dur", "indefinite");
+  textElem.appendChild(animElem);
+
+  // CHECK EFFECT OF 'narrower'
+  // NOTE: Using is() instead of todo_is() for ultra-condensed, since
+  // 'narrower' has no effect on that value.
+  var myIs = (baseValue == "ultra-condensed" ? is : todo_is);
+  animElem.setAttribute("to", "narrower");
+  SMILUtil.getSVGRoot().setCurrentTime(1.0); // Force a resample
+  myIs(SMILUtil.getComputedStyleSimple(textElem, gPropertyName), narrowerStep,
+       "checking effect of 'narrower' on inherited value '" + baseValue + "'");
+
+  // CHECK EFFECT OF 'wider'
+  // NOTE: using is() instead of todo_is() for ultra-expanded, since
+  // 'wider' has no effect on that value.
+  myIs = (baseValue == "ultra-expanded" ? is : todo_is);
+  animElem.setAttribute("to", "wider");
+  SMILUtil.getSVGRoot().setCurrentTime(1.0); // Force a resample
+  myIs(SMILUtil.getComputedStyleSimple(textElem, gPropertyName), widerStep,
+          "checking effect of 'wider' on inherited value '" + baseValue + "'");
+
+  // Removing animation should clear animated effects
+  textElem.removeChild(animElem);
+  svg.removeChild(gElem);
+}
+
+function main()
+{
+  if (!SMILUtil.isSMILEnabled()) {
+    ok(false, "SMIL dosn't seem to be enabled");
+    SimpleTest.finish();
+    return;
+  }
+
+  var valuesList = gFontStretchValues;
+  for (var baseIdx in valuesList) {
+    // 'narrower' and 'wider' are expected to shift us by one slot, but not
+    // past the ends of the list of possible values.
+    var narrowerIdx = Math.max(baseIdx - 1, 0);
+    var widerIdx =    Math.min(baseIdx + 1, valuesList.length - 1);
+
+    testFontStretchValue(valuesList[baseIdx],
+                         valuesList[narrowerIdx], valuesList[widerIdx]);
+  }
+
+  SimpleTest.finish();
+}
+
+window.addEventListener("load", main, false);
+]]>
+</script>
+</pre>
+</body>
+</html>
--- a/content/svg/content/test/bbox-helper.svg
+++ b/content/svg/content/test/bbox-helper.svg
@@ -1,6 +1,9 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg">
   <g transform="scale(0.5)">
     <foreignObject id="f" width="100" height="100"/>
   </g>
+  <text id="b" x="20" y="20">b</text>
+  <text id="a" x="20" y="30">a</text>
+  <text id="y" x="20" y="40">y</text>
 </svg>
--- a/content/svg/content/test/test_bbox.xhtml
+++ b/content/svg/content/test/test_bbox.xhtml
@@ -18,28 +18,37 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 <pre id="test">
 <script class="testbody" type="application/javascript">
 SimpleTest.waitForExplicitFinish();
 
 function run()
 {
   var doc = $("svg").contentDocument;
-  
+
+  function getBBox(id) {
+    return doc.getElementById(id).getBBox();
+  }
   function checkBBox(id, x, y, width, height) {
-    var e = doc.getElementById(id);
-    var bbox = e.getBBox();
+    var bbox = getBBox(id);
     is(bbox.x, x, id + ".getBBox().x");
     is(bbox.y, y, id + ".getBBox().y");
     is(bbox.width, width, id + ".getBBox().width");
     is(bbox.height, height, id + ".getBBox().height");
   }
+  function checkBBoxHeight(id1, id2) {
+    var bbox1 = getBBox(id1);
+    var bbox2 = getBBox(id2);
+    is(bbox1.height, bbox2.height, id1 + ".getBBox().height");
+  }
 
   checkBBox("f", 0, 0, 100, 100);
-
+  checkBBoxHeight("a", "b");
+  checkBBoxHeight("a", "y");
+  
   SimpleTest.finish();
 }
 
 window.addEventListener("load", run, false);
 </script>
 </pre>
 </body>
 </html>
--- a/content/test/unit/head_content.js
+++ b/content/test/unit/head_content.js
@@ -70,18 +70,18 @@ function ParseFile(file) {
     }
     var fileObj = __testsDirectory.clone();
     fileObj.append(file);
     file = fileObj;
   }
 
   do_check_eq(file instanceof nsILocalFile, true);
 
-  fileStr = C["@mozilla.org/network/file-input-stream;1"]
-             .createInstance(nsIFileInputStream);
+  var fileStr = C["@mozilla.org/network/file-input-stream;1"]
+                 .createInstance(nsIFileInputStream);
   // Init for readonly reading
   fileStr.init(file,  0x01, 0400, nsIFileInputStream.CLOSE_ON_EOF);
   return ParseXML(fileStr);
 }
 
 function ParseXML(data) {
   if (typeof(data) == "string") {
     return DOMParser().parseFromString(data, "application/xml");
--- a/content/test/unit/test_range.js
+++ b/content/test/unit/test_range.js
@@ -257,17 +257,17 @@ function getParsedDocument(aPath) {
  * Run the extraction tests.
  */
 function run_extract_test() {
   var filePath = "test_delete_range.xml";
   var doc = getParsedDocument(filePath);
   var tests = doc.getElementsByTagName("test");
 
   // Run our deletion, extraction tests.
-  for (i = 0; i < tests.length; i++) {
+  for (var i = 0; i < tests.length; i++) {
     dump("Configuring for test " + i + "\n");
     var currentTest = tests.item(i);
 
     // Validate the test is properly formatted for what this harness expects.
     var baseSource = currentTest.firstChild;
     do_check_eq(baseSource.nodeName, "source");
     var baseResult = baseSource.nextSibling;
     do_check_eq(baseResult.nodeName, "result");
@@ -310,20 +310,20 @@ function run_extract_test() {
     if (cutFragment) {
       do_check_true(extractFrag.isEqualNode(cutFragment));
     } else {
       do_check_eq(extractFrag.firstChild, null);
     }
     do_check_true(baseFrag.isEqualNode(resultFrag));
 
     dump("Ensure the original nodes weren't extracted - test " + i + "\n\n");
-    walker = doc.createTreeWalker(baseFrag,
-                                  C_i.nsIDOMNodeFilter.SHOW_ALL,
-                                  null,
-                                  false);
+    var walker = doc.createTreeWalker(baseFrag,
+				      C_i.nsIDOMNodeFilter.SHOW_ALL,
+				      null,
+				      false);
     var foundStart = false;
     var foundEnd = false;
     do {
       do_check_true(walker.currentNode instanceof C_i.nsIDOM3Node);
 
       if (walker.currentNode.isSameNode(startContainer)) {
         foundStart = true;
       }
@@ -410,23 +410,23 @@ function run_extract_test() {
  */
 function run_miscellaneous_tests() {
   var filePath = "test_delete_range.xml";
   var doc = getParsedDocument(filePath);
   var tests = doc.getElementsByTagName("test");
 
   // Let's try some invalid inputs to our DOM range and see what happens.
   var currentTest = tests.item(0);
-  baseSource = currentTest.firstChild;
-  baseResult = baseSource.nextSibling;
-  baseExtract = baseResult.nextSibling;
+  var baseSource = currentTest.firstChild;
+  var baseResult = baseSource.nextSibling;
+  var baseExtract = baseResult.nextSibling;
 
-  baseFrag = getFragment(baseSource);
+  var baseFrag = getFragment(baseSource);
 
-  baseRange = getRange(baseSource, baseFrag);
+  var baseRange = getRange(baseSource, baseFrag);
   var startContainer = baseRange.startContainer;
   var endContainer = baseRange.endContainer;
   var startOffset = baseRange.startOffset;
   var endOffset = baseRange.endOffset;
 
   // Text range manipulation.
   if ((endOffset > startOffset) &&
       (startContainer == endContainer) &&
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -603,16 +603,19 @@ ChangeDocumentForDefaultContent(nsISuppo
   }
 
   return PL_DHASH_NEXT;
 }
 
 void
 nsXBLBinding::GenerateAnonymousContent()
 {
+  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
+               "Someone forgot a script blocker");
+
   // Fetch the content element for this binding.
   nsIContent* content =
     mPrototypeBinding->GetImmediateChild(nsGkAtoms::content);
 
   if (!content) {
     // We have no anonymous content.
     if (mNextBinding)
       mNextBinding->GenerateAnonymousContent();
@@ -673,24 +676,19 @@ nsXBLBinding::GenerateAnonymousContent()
              localName != nsGkAtoms::_template)) {
           hasContent = PR_FALSE;
           break;
         }
       }
     }
 
     if (hasContent || hasInsertionPoints) {
-      nsIDocument *document = mBoundElement->GetOwnerDoc();
-      if (!document) {
-        return;
-      }
-
       nsCOMPtr<nsIDOMNode> clonedNode;
       nsCOMArray<nsINode> nodesWithProperties;
-      nsNodeUtils::Clone(content, PR_TRUE, document->NodeInfoManager(),
+      nsNodeUtils::Clone(content, PR_TRUE, doc->NodeInfoManager(),
                          nodesWithProperties, getter_AddRefs(clonedNode));
 
       mContent = do_QueryInterface(clonedNode);
       InstallAnonymousContent(mContent, mBoundElement);
 
       if (hasInsertionPoints) {
         // Now check and see if we have a single insertion point 
         // or multiple insertion points.
@@ -1158,42 +1156,46 @@ nsXBLBinding::ChangeDocument(nsIDocument
           }
         }
       }
 
       // Remove our event handlers
       UnhookEventHandlers();
     }
 
-    // Then do our ancestors.  This reverses the construction order, so that at
-    // all times things are consistent as far as everyone is concerned.
-    if (mNextBinding) {
-      mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
-    }
+    {
+      nsAutoScriptBlocker scriptBlocker;
+
+      // Then do our ancestors.  This reverses the construction order, so that at
+      // all times things are consistent as far as everyone is concerned.
+      if (mNextBinding) {
+        mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
+      }
 
-    // Update the anonymous content.
-    // XXXbz why not only for style bindings?
-    nsIContent *anonymous = mContent;
-    if (anonymous) {
-      // Also kill the default content within all our insertion points.
-      if (mInsertionPointTable)
-        mInsertionPointTable->Enumerate(ChangeDocumentForDefaultContent,
-                                        nsnull);
+      // Update the anonymous content.
+      // XXXbz why not only for style bindings?
+      nsIContent *anonymous = mContent;
+      if (anonymous) {
+        // Also kill the default content within all our insertion points.
+        if (mInsertionPointTable)
+          mInsertionPointTable->Enumerate(ChangeDocumentForDefaultContent,
+                                          nsnull);
 
-      nsXBLBinding::UninstallAnonymousContent(aOldDocument, anonymous);
-    }
+        nsXBLBinding::UninstallAnonymousContent(aOldDocument, anonymous);
+      }
 
-    // Make sure that henceforth we don't claim that mBoundElement's children
-    // have insertion parents in the old document.
-    nsBindingManager* bindingManager = aOldDocument->BindingManager();
-    for (PRUint32 i = mBoundElement->GetChildCount(); i > 0; --i) {
-      NS_ASSERTION(mBoundElement->GetChildAt(i-1),
-                   "Must have child at i for 0 <= i < GetChildCount()!");
-      bindingManager->SetInsertionParent(mBoundElement->GetChildAt(i-1),
-                                         nsnull);
+      // Make sure that henceforth we don't claim that mBoundElement's children
+      // have insertion parents in the old document.
+      nsBindingManager* bindingManager = aOldDocument->BindingManager();
+      for (PRUint32 i = mBoundElement->GetChildCount(); i > 0; --i) {
+        NS_ASSERTION(mBoundElement->GetChildAt(i-1),
+                     "Must have child at i for 0 <= i < GetChildCount()!");
+        bindingManager->SetInsertionParent(mBoundElement->GetChildAt(i-1),
+                                           nsnull);
+      }
     }
   }
 }
 
 PRBool
 nsXBLBinding::InheritsStyle() const
 {
   // XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -337,17 +337,17 @@ nsXBLPrototypeBinding::Init(const nsACSt
   mXBLDocInfoWeak = aInfo;
 
   SetBindingElement(aElement);
   return NS_OK;
 }
 
 PRBool nsXBLPrototypeBinding::CompareBindingURI(nsIURI* aURI) const
 {
-  PRBool equal;
+  PRBool equal = PR_FALSE;
   mBindingURI->Equals(aURI, &equal);
   if (!equal && mAlternateBindingURI) {
     mAlternateBindingURI->Equals(aURI, &equal);
   }
   return equal;
 }
 
 static PRIntn
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -615,33 +615,37 @@ nsXBLService::LoadBindings(nsIContent* a
       binding->RootBinding()->SetBaseBinding(newBinding);
     }
     else {
       // Install the binding on the content node.
       bindingManager->SetBinding(aContent, newBinding);
     }
   }
 
-  // Set the binding's bound element.
-  newBinding->SetBoundElement(aContent);
+  {
+    nsAutoScriptBlocker scriptBlocker;
 
-  // Tell the binding to build the anonymous content.
-  newBinding->GenerateAnonymousContent();
+    // Set the binding's bound element.
+    newBinding->SetBoundElement(aContent);
 
-  // Tell the binding to install event handlers
-  newBinding->InstallEventHandlers();
+    // Tell the binding to build the anonymous content.
+    newBinding->GenerateAnonymousContent();
 
-  // Set up our properties
-  rv = newBinding->InstallImplementation();
-  NS_ENSURE_SUCCESS(rv, rv);
+    // Tell the binding to install event handlers
+    newBinding->InstallEventHandlers();
 
-  // Figure out if we have any scoped sheets.  If so, we do a second resolve.
-  *aResolveStyle = newBinding->HasStyleSheets();
+    // Set up our properties
+    rv = newBinding->InstallImplementation();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Figure out if we have any scoped sheets.  If so, we do a second resolve.
+    *aResolveStyle = newBinding->HasStyleSheets();
   
-  newBinding.swap(*aBinding);
+    newBinding.swap(*aBinding);
+  }
 
   return NS_OK; 
 }
 
 nsresult
 nsXBLService::FlushStyleBindings(nsIContent* aContent)
 {
   nsCOMPtr<nsIDocument> document = aContent->GetOwnerDoc();
--- a/content/xtf/test/unit/xtfComponent.js
+++ b/content/xtf/test/unit/xtfComponent.js
@@ -204,17 +204,17 @@ const fooClassID    = Components.ID("{f3
 const fooClassDesc  = "XTF unit test: Foo element factory";
 const fooContractID = xtfClass + "xtf-tests;foo";
 
 /* </foo:element> */
 
 const Module = {
   // nsIModule
   registerSelf: function registerSelf(compMgr, fileSpec, location, type) {
-    compReg = compMgr.QueryInterface(nsIComponentRegistrar);
+    var compReg = compMgr.QueryInterface(nsIComponentRegistrar);
 
     compReg.registerFactoryLocation(fooClassID,
                                     fooClassDesc,
                                     fooContractID,
                                     fileSpec,
                                     location,
                                     type);
   },
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -4754,16 +4754,17 @@ nsXULDocument::GetDocumentLWTheme()
         mDocLWTheme = Doc_Theme_None; // No lightweight theme by default
 
         nsIContent* content = GetRootContent();
         nsAutoString hasLWTheme;
         if (content &&
             content->GetAttr(kNameSpaceID_None, nsGkAtoms::lwtheme, hasLWTheme) &&
             !(hasLWTheme.IsEmpty()) &&
             hasLWTheme.EqualsLiteral("true")) {
+            mDocLWTheme = Doc_Theme_Neutral;
             nsAutoString lwTheme;
             content->GetAttr(kNameSpaceID_None, nsGkAtoms::lwthemetextcolor, lwTheme);
             if (!(lwTheme.IsEmpty())) {
                 if (lwTheme.EqualsLiteral("dark"))
                     mDocLWTheme = Doc_Theme_Dark;
                 else if (lwTheme.EqualsLiteral("bright"))
                     mDocLWTheme = Doc_Theme_Bright;
             }
--- a/db/Makefile.in
+++ b/db/Makefile.in
@@ -30,27 +30,26 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-DEPTH		= ..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
+DEPTH     = ..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 ifndef NSS_DISABLE_DBM
 ifdef MOZ_MORK
-DIRS		= mdb mork
+PARALLEL_DIRS = mdb mork
 endif
 endif 
 
 ifdef MOZ_MORKREADER
-DIRS		+= morkreader
+PARALLEL_DIRS += morkreader
 endif
 
 include $(topsrcdir)/config/rules.mk
-
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3789,45 +3789,24 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, 
         else
             chanName.AssignLiteral("<no channel>");
 
         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
                ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
                 spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
     }
 #endif
-    // Create an shistory entry for the old load, if we have a channel
-    if (aFailedChannel) {
-        mURIResultedInDocument = PR_TRUE;
-        OnLoadingSite(aFailedChannel, PR_TRUE, PR_FALSE);
-    } else if (aURI) {
-        mURIResultedInDocument = PR_TRUE;
-        OnNewURI(aURI, nsnull, nsnull, mLoadType, PR_TRUE, PR_FALSE);
-    }
-    // Be sure to have a correct mLSHE, it may have been cleared by
-    // EndPageLoad. See bug 302115.
-    if (mSessionHistory && !mLSHE) {
-        PRInt32 idx;
-        mSessionHistory->GetRequestedIndex(&idx);
-        if (idx == -1)
-            mSessionHistory->GetIndex(&idx);
-
-        nsCOMPtr<nsIHistoryEntry> entry;
-        mSessionHistory->GetEntryAtIndex(idx, PR_FALSE,
-                                         getter_AddRefs(entry));
-        mLSHE = do_QueryInterface(entry);
-    }
+    mFailedChannel = aFailedChannel;
+    mFailedURI = aURI;
+    mFailedLoadType = mLoadType;
 
     nsCAutoString url;
     nsCAutoString charset;
     if (aURI)
     {
-        // Set our current URI
-        SetCurrentURI(aURI);
-
         nsresult rv = aURI->GetSpec(url);
         rv |= aURI->GetOriginCharset(charset);
         NS_ENSURE_SUCCESS(rv, rv);
     }
     else if (aURL)
     {
         CopyUTF16toUTF8(aURL, url);
     }
@@ -3946,20 +3925,25 @@ nsDocShell::Reload(PRUint32 aReloadFlags
 }
 
 NS_IMETHODIMP
 nsDocShell::Stop(PRUint32 aStopFlags)
 {
     // Revoke any pending event related to content viewer restoration
     mRestorePresentationEvent.Revoke();
 
-    if (mLoadType == LOAD_ERROR_PAGE && mLSHE) {
-        // Since error page loads never unset mLSHE, do so now
-        SetHistoryEntry(&mOSHE, mLSHE);
-        SetHistoryEntry(&mLSHE, nsnull);
+    if (mLoadType == LOAD_ERROR_PAGE) {
+        if (mLSHE) {
+            // Since error page loads never unset mLSHE, do so now
+            SetHistoryEntry(&mOSHE, mLSHE);
+            SetHistoryEntry(&mLSHE, nsnull);
+        }
+
+        mFailedChannel = nsnull;
+        mFailedURI = nsnull;
     }
 
     if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
         // Stop the document loading
         if (mContentViewer)
             mContentViewer->Stop();
     }
 
@@ -7026,16 +7010,59 @@ nsDocShell::CreateContentViewer(const ch
     // *new* document will fire.
     mFiredUnloadEvent = PR_FALSE;
 
     // we've created a new document so go ahead and call
     // OnLoadingSite(), but don't fire OnLocationChange()
     // notifications before we've called Embed(). See bug 284993.
     mURIResultedInDocument = PR_TRUE;
 
+    if (mLoadType == LOAD_ERROR_PAGE) {
+        // We need to set the SH entry and our current URI here and not
+        // at the moment we load the page. We want the same behavior 
+        // of Stop() as for a normal page load. See bug 514232 for details.
+
+        // Revert mLoadType to load type to state the page load failed,
+        // following function calls need it.
+        mLoadType = mFailedLoadType;
+
+        nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
+        nsCOMPtr<nsIURI> failedURI = mFailedURI;
+        mFailedChannel = nsnull;
+        mFailedURI = nsnull;
+
+        // Create an shistory entry for the old load, if we have a channel
+        if (failedChannel) {
+            mURIResultedInDocument = PR_TRUE;
+            OnLoadingSite(failedChannel, PR_TRUE, PR_FALSE);
+        } else if (failedURI) {
+            mURIResultedInDocument = PR_TRUE;
+            OnNewURI(failedURI, nsnull, nsnull, mLoadType, PR_TRUE, PR_FALSE);
+        }
+
+        // Be sure to have a correct mLSHE, it may have been cleared by
+        // EndPageLoad. See bug 302115.
+        if (mSessionHistory && !mLSHE) {
+            PRInt32 idx;
+            mSessionHistory->GetRequestedIndex(&idx);
+            if (idx == -1)
+                mSessionHistory->GetIndex(&idx);
+
+            nsCOMPtr<nsIHistoryEntry> entry;
+            mSessionHistory->GetEntryAtIndex(idx, PR_FALSE,
+                                             getter_AddRefs(entry));
+            mLSHE = do_QueryInterface(entry);
+        }
+
+        // Set our current URI
+        SetCurrentURI(failedURI);
+
+        mLoadType = LOAD_ERROR_PAGE;
+    }
+
     PRBool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, PR_FALSE);
 
     // let's try resetting the load group if we need to...
     nsCOMPtr<nsILoadGroup> currentLoadGroup;
     NS_ENSURE_SUCCESS(aOpenedChannel->
                       GetLoadGroup(getter_AddRefs(currentLoadGroup)),
                       NS_ERROR_FAILURE);
 
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -692,16 +692,23 @@ protected:
 
     // The URI we're currently loading.  This is only relevant during the
     // firing of a pagehide/unload.  The caller of FirePageHideNotification()
     // is responsible for setting it and unsetting it.  It may be null if the
     // pagehide/unload is happening for some reason other than just loading a
     // new URI.
     nsCOMPtr<nsIURI>           mLoadingURI;
 
+    // Set in LoadErrorPage from the method argument and used later
+    // in CreateContentViewer. We have to delay an shistory entry creation
+    // for which these objects are needed.
+    nsCOMPtr<nsIURI>           mFailedURI;
+    nsCOMPtr<nsIChannel>       mFailedChannel;
+    PRUint32                   mFailedLoadType;
+
     // WEAK REFERENCES BELOW HERE.
     // Note these are intentionally not addrefd.  Doing so will create a cycle.
     // For that reasons don't use nsCOMPtr.
 
     nsIDocShellTreeOwner *     mTreeOwner; // Weak Reference
     nsPIDOMEventTarget *       mChromeEventHandler; //Weak Reference
 
     eCharsetReloadState        mCharsetReloadState;
--- a/docshell/test/Makefile.in
+++ b/docshell/test/Makefile.in
@@ -73,16 +73,19 @@ include $(topsrcdir)/config/rules.mk
 		test_bug475636.html \
 		file_bug475636.sjs \
 		test_bug385434.html \
 		file_bug385434_1.html \
 		file_bug385434_2.html \
 		file_bug385434_3.html \
 		test_bug509055.html \
 		file_bug509055.html \
+		test_bug529119-1.html \
+		test_bug529119-2.html \
+		bug529119-window.html \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 _TEST_FILES += \
 		test_bug511449.html \
 		file_bug511449.html \
 		$(NULL)
 endif
new file mode 100644
--- /dev/null
+++ b/docshell/test/bug529119-window.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test bug 529119, sub-window</title>
+<body onload="window.opener.windowLoaded();">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug529119-1.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test bug 529119</title>
+<script type="text/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>        
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var workingURL = "http://localhost:8888/tests/docshell/test/bug529119-window.html";
+var faultyURL = "http://some-non-existent-domain-27489274c892748217cn2384.com/";
+
+var w = null;
+var phase = 0;
+var gotWrongPageOnTryAgainClick = false;
+
+function pollForPage(expected_title, f, w)
+{
+  // Start with polling after a delay, we might mistakenly take the current page
+  // as an expected one.
+  window.setTimeout(function() {
+    var iterationsLeft = 20;
+    var int = window.setInterval(function() {
+      iterationsLeft--;
+      
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      try {
+        var title = w.document.title;
+      }
+      catch (ex) {
+        alert(ex);
+        return;
+      }
+  
+      if (iterationsLeft == 0 || title.match(expected_title)) {
+        window.clearInterval(int);
+        f(iterationsLeft > 0);
+      }
+    }, 100);
+  }, 1000);
+}
+
+function windowLoaded()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  switch (phase)
+  {
+    case 0:
+      /* 2. We have succeededfully loaded a page, now go to a faulty URL */
+      window.setTimeout(function() {
+        w.location.href = faultyURL;
+      }, 0);
+    
+      phase = 1;
+
+      pollForPage("Problem loading page", function(succeeded) {
+        ok(succeeded, "Waiting for error page succeeded");
+        
+        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+        /* 3. now, while we are on the error page, try to reload it, actually 
+           click the "Try Again" button */
+        w.location.reload();
+
+        pollForPage("Problem loading page", function(succeeded) {
+          ok(succeeded, "Waiting for error page succeeded");
+          
+          netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+          /* 4-finish, check we are still on the error page */
+          is(w.location.href, faultyURL, "Is on an error page");
+          isnot(w.location.href, workingURL, "Is not on the previous page");
+          is(gotWrongPageOnTryAgainClick, false, 
+            "Must not get www.example.com page on reload of an error page");
+          w.close();
+          SimpleTest.finish();
+        }, w);
+      }, w);
+      break;
+      
+    case 1:
+      /* 4-check, we must not get here! */
+      gotWrongPageOnTryAgainClick = true;
+      break;
+  }             
+}
+
+function startTest()
+{
+  /* 1. load a URL that leads to an error page */
+  w = window.open(workingURL);
+}
+
+</script>
+</head>
+<body onload="startTest();">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug529119-2.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test bug 529119</title>
+<script type="text/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>        
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var workingURL = "http://localhost:8888/tests/docshell/test/bug529119-window.html";
+var faultyURL = "http://some-non-existent-domain-27489274c892748217cn2384.com/";
+
+var w = null;
+var phase = 0;
+
+function pollForPage(expected_title, f, w)
+{
+  // Start with polling after a delay, we might mistakenly take the current page
+  // as an expected one.
+  window.setTimeout(function() {
+    var iterationsLeft = 20;
+    var int = window.setInterval(function() {
+      iterationsLeft--;
+      
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      try {
+        var title = w.document.title;
+      }
+      catch (ex) {
+        alert(ex);
+        return;
+      }
+  
+      if (iterationsLeft == 0 || title.match(expected_title)) {
+        window.clearInterval(int);
+        f(iterationsLeft > 0);
+      }
+    }, 100);
+  }, 1000);
+}
+
+function windowLoaded()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  /* 2. We have successfully loaded a page, now go to a faulty URL */
+  // XXX The test fails when we change the location synchronously 
+  window.setTimeout(function() {
+    w.location.href = faultyURL;
+  }, 0);
+
+  pollForPage("Problem loading page", function(succeeded) {
+    ok(succeeded, "Waiting for error page succeeded");
+    
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    /* 3. now, while we are on the error page, navigate back */
+    try {
+      w.back();
+    }
+    catch(ex) {
+      ok(false, "w.back() threw " + ex);
+    }
+
+    pollForPage("Test bug 529119, sub-window", function(succeeded) {
+      ok(succeeded, "Waiting for original page succeeded");
+      
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      /* 4-finish, check we are back at the original page */
+      isnot(w.location.href, faultyURL, "Is on an error page");
+      is(w.location.href, workingURL, "Is not on the previous page");
+      w.close();
+      SimpleTest.finish();
+    }, w);
+  }, w);
+}
+
+function startTest()
+{
+  /* 1. load a URL that leads to an error page */
+  w = window.open(workingURL);
+}
+
+</script>
+</head>
+<body onload="startTest();">
+</body>
+</html>
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8094,36 +8094,42 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
       return;
     }
 
     PRBool isInterval = PR_FALSE;
 
     // If we have a regular interval timer, we re-schedule the
     // timeout, accounting for clock drift.
     if (timeout->mInterval) {
-      // Compute time to next timeout for interval timer. If we're
-      // running pending timeouts because they've been temporarily
-      // disabled (!aTimeout), set the next interval to be relative to
-      // "now", and not to when the timeout that was pending should
-      // have fired.
-      // Also check if the next interval timeout is overdue.  If so,
-      // then restart the interval from now.
+      // Compute time to next timeout for interval timer.
       PRTime nextInterval = (PRTime)timeout->mInterval * PR_USEC_PER_MSEC;
+
+      // Make sure nextInterval is at least DOM_MIN_TIMEOUT_VALUE.
+      // Note: We must cast the rhs expression to PRTime to work
+      // around what looks like a compiler bug on x86_64.
+      if (nextInterval < (PRTime)(DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC)) {
+         nextInterval = DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC;
+      }
+
+      // If we're running pending timeouts because they've been temporarily
+      // disabled (!aTimeout), set the next interval to be relative to "now",
+      // and not to when the timeout that was pending should have fired.  Also
+      // check if the next interval timeout is overdue.  If so, then restart
+      // the interval from now.
       if (!aTimeout || nextInterval + timeout->mWhen <= now)
         nextInterval += now;
       else
         nextInterval += timeout->mWhen;
 
       PRTime delay = nextInterval - PR_Now();
 
-      // Make sure the delay is at least DOM_MIN_TIMEOUT_VALUE.
-      // Note: We must cast the rhs expression to PRTime to work
-      // around what looks like a compiler bug on x86_64.
-      if (delay < (PRTime)(DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC)) {
-        delay = DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC;
+      // And make sure delay is nonnegative; that might happen if the timer
+      // thread is firing our timers somewhat early.
+      if (delay < 0) {
+        delay = 0;
       }
 
       if (timeout->mTimer) {
         timeout->mWhen = nextInterval;
 
         // Reschedule the OS timer. Don't bother returning any error
         // codes if this fails since the callers of this method
         // doesn't care about them nobody who cares about them
@@ -9377,16 +9383,18 @@ nsNavigator::GetPlatform(nsAString& aPla
 #if defined(_WIN64)
     aPlatform.AssignLiteral("Win64");
 #elif defined(WIN32)
     aPlatform.AssignLiteral("Win32");
 #elif defined(XP_MACOSX) && defined(__ppc__)
     aPlatform.AssignLiteral("MacPPC");
 #elif defined(XP_MACOSX) && defined(__i386__)
     aPlatform.AssignLiteral("MacIntel");
+#elif defined(XP_MACOSX) && defined(__x86_64__)
+    aPlatform.AssignLiteral("MacIntel");
 #elif defined(XP_OS2)
     aPlatform.AssignLiteral("OS/2");
 #else
     // XXX Communicator uses compiled-in build-time string defines
     // to indicate the platform it was compiled *for*, not what it is
     // currently running *on* which is what this does.
     nsCAutoString plat;
     rv = service->GetOscpu(plat);
@@ -9908,17 +9916,32 @@ nsNavigator::MozIsLocallyAvailable(const
 
 //*****************************************************************************
 //    nsNavigator::nsIDOMNavigatorGeolocation
 //*****************************************************************************
 
 NS_IMETHODIMP nsNavigator::GetGeolocation(nsIDOMGeoGeolocation **_retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
-
-  if (!mGeolocation && mDocShell) {
-    nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
-    mGeolocation = new nsGeolocation(contentDOMWindow);
-  }
-
-  NS_IF_ADDREF(*_retval = mGeolocation);
-  return NS_OK;
-}
+  *_retval = nsnull;
+
+  if (mGeolocation) {
+    NS_ADDREF(*_retval = mGeolocation);
+    return NS_OK;
+  }
+
+  if (!mDocShell)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
+  if (!contentDOMWindow)
+    return NS_ERROR_FAILURE;
+    
+  mGeolocation = new nsGeolocation();
+  if (!mGeolocation)
+    return NS_ERROR_FAILURE;
+  
+  if (NS_FAILED(mGeolocation->Init(contentDOMWindow)))
+    return NS_ERROR_FAILURE;
+  
+  NS_ADDREF(*_retval = mGeolocation);    
+  return NS_OK; 
+}
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -936,36 +936,58 @@ nsJSContext::DOMOperationCallback(JSCont
       // lets see if CC() did anything, if not, cancel the script.
       mem->IsLowMemory(&lowMemory);
       if (lowMemory) {
 
         if (nsContentUtils::GetBoolPref("dom.prevent_oom_dialog", PR_FALSE)) {
           JS_ClearPendingException(cx);
           return JS_FALSE;
         }
-        
-        nsCOMPtr<nsIPrompt> prompt = GetPromptFromContext(ctx);
-        
-        nsXPIDLString title, msg;
-        rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                "LowMemoryTitle",
-                                                title);
-        
-        rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                 "LowMemoryMessage",
-                                                 msg);
-        
-        //GetStringFromName can return NS_OK and still give NULL string
-        if (NS_FAILED(rv) || !title || !msg) {
-          NS_ERROR("Failed to get localized strings.");
-          JS_ClearPendingException(cx);
-          return JS_FALSE;
+
+        nsCOMPtr<nsIScriptError> errorObject =
+          do_CreateInstance("@mozilla.org/scripterror;1");
+
+        if (errorObject) {
+          nsXPIDLString msg;
+          nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                             "LowMemoryMessage",
+                                             msg);
+
+          JSStackFrame *fp, *iterator = nsnull;
+          fp = ::JS_FrameIterator(cx, &iterator);
+          PRUint32 lineno = 0;
+          nsAutoString sourcefile;
+          if (fp) {
+            JSScript* script = ::JS_GetFrameScript(cx, fp);
+            if (script) {
+              const char* filename = ::JS_GetScriptFilename(cx, script);
+              if (filename) {
+                CopyUTF8toUTF16(nsDependentCString(filename), sourcefile);
+              }
+              jsbytecode* pc = ::JS_GetFramePC(cx, fp);
+              if (pc) {
+                lineno = ::JS_PCToLineNumber(cx, script, pc);
+              }
+            }
+          }
+
+          rv = errorObject->Init(msg.get(),
+                                 sourcefile.get(),
+                                 EmptyString().get(),
+                                 lineno, 0, nsIScriptError::errorFlag,
+                                 "content javascript");
+          if (NS_SUCCEEDED(rv)) {
+            nsCOMPtr<nsIConsoleService> consoleService =
+              do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
+            if (NS_SUCCEEDED(rv)) {
+              consoleService->LogMessage(errorObject);
+            }
+          }
         }
-        
-        prompt->Alert(title, msg);
+
         JS_ClearPendingException(cx);
         return JS_FALSE;
       }
     }
   }
 
   PRTime now = PR_Now();
 
--- a/dom/interfaces/canvas/nsICanvasRenderingContextWebGL.idl
+++ b/dom/interfaces/canvas/nsICanvasRenderingContextWebGL.idl
@@ -665,23 +665,16 @@ interface nsICanvasRenderingContextWebGL
   const unsigned long MAX_RENDERBUFFER_SIZE          = 0x84E8;
 
   const unsigned long INVALID_FRAMEBUFFER_OPERATION  = 0x0506;
 
   //
   //  ATTRIBUTES
   //
   readonly attribute nsIDOMHTMLCanvasElement canvas;
-  readonly attribute nsIWebGLBuffer currentArrayBufferBinding;
-  readonly attribute nsIWebGLBuffer currentElementArrayBufferBinding;
-  readonly attribute nsIWebGLFramebuffer currentFramebufferBinding;
-  readonly attribute nsIWebGLRenderbuffer currentRenderbufferBinding;
-  readonly attribute nsIWebGLTexture currentTextureBinding2D;
-  readonly attribute nsIWebGLTexture currentTextureBindingCubeMap;
-  readonly attribute nsIWebGLProgram currentProgram;
 
   //
   //  METHODS
   //
   void present();
   long sizeInBytes(in GLenum type);
 
   void activeTexture (in GLenum texture);
@@ -775,74 +768,66 @@ interface nsICanvasRenderingContextWebGL
   // Modified
   //GLboolean getBoolean(in GLenum pname);
   // NOTYET nsIWebGLBooleanArray getBooleanv(in GLenum pname);
   //GLfloat getFloat(in GLenum pname);
   //nsIWebGLArray getFloatv(in GLenum pname);
   //GLint getInteger(in GLenum pname);
   //nsIWebGLIntArray getIntegerv(in GLenum pname);
   // js only
-  void getParameter(in GLenum pname);
+  void getParameter (in GLenum pname);
 
   // Modified: void glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
-  GLint getBufferParameteri (in GLenum target, in GLenum pname);
-  //nsIWebGLIntArray glGetBufferParameteriv (in GLenum target, in GLenum pname);
+  GLint getBufferParameteri (in GLenum target, in GLenum pname); // XXX remove
+  void getBufferParameter (in GLenum target, in GLenum pname);
 
   GLenum getError ();
 
   // Modified: void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
-  GLint getFramebufferAttachmentParameteri (in GLenum target, in GLenum attachment, in GLenum pname);
-  //nsIWebGLIntArray glGetFramebufferAttachmentParameteriv (in GLenum target, in GLenum attachment, in GLenum pname);
+  GLint getFramebufferAttachmentParameteri (in GLenum target, in GLenum attachment, in GLenum pname); // XXX remove
+  void getFramebufferAttachmentParameter (in GLenum target, in GLenum attachment, in GLenum pname);
 
   // Modified: void glGetProgramiv (nsIWebGLProgram program, GLenum pname, GLint* params);
-  GLint getProgrami (in nsIWebGLProgram program, in GLenum pname);
-  //nsIWebGLIntArray getProgramiv (in nsIWebGLProgram program, in GLenum pname);
-  //void getProgramParameter (in nsIWebGLProgram program, in GLenum pname);
+  GLint getProgrami (in nsIWebGLProgram program, in GLenum pname); // XXX remove
+  void getProgramParameter (in nsIWebGLProgram program, in GLenum pname);
 
   // Modified: void glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
   DOMString getProgramInfoLog (in nsIWebGLProgram program);
 
   // Modified: void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
   //nsIWebGLIntArray getRenderbufferParameteriv (in GLenum target, in GLenum pname);
-  GLint getRenderbufferParameteri (in GLenum target, in GLenum pname);
+  GLint getRenderbufferParameteri (in GLenum target, in GLenum pname); // XXX remove
+  void getRenderbufferParameter (in GLenum target, in GLenum pname);
 
-  GLint getShaderi (in nsIWebGLShader shader, in GLenum pname);
-  nsICanvasIntArray getShaderiv (in nsIWebGLShader shader, in GLenum pname);
-  // GONE void getShaderParameter (in nsIWebGLShader shader, in GLenum pname);
+  GLint getShaderi (in nsIWebGLShader shader, in GLenum pname); // XXX remove
+  void getShaderParameter (in nsIWebGLShader shader, in GLenum pname);
 
   // Modified: void glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
   DOMString getShaderInfoLog (in nsIWebGLShader shader);
 
   // TBD
   //void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
 
   DOMString getShaderSource (in nsIWebGLShader shader);
   DOMString getString (in GLenum name);
 
-  GLfloat getTexParameterf (in GLenum target, in GLenum pname);
-  nsICanvasArray getTexParameterfv (in GLenum target, in GLenum pname);
-  GLint getTexParameteri (in GLenum target, in GLenum pname);
-  nsICanvasArray getTexParameteriv (in GLenum target, in GLenum pname);
+  GLfloat getTexParameterf (in GLenum target, in GLenum pname);         // XXX remove
+  GLint getTexParameteri (in GLenum target, in GLenum pname);           // XXX remove
+  void getTexParameter (in GLenum target, in GLenum pname);
 
   // FIXME: This is problematic. We don't implicitly know how big the returned data buffer
   // needs to be like in the other glGet* calls. The only way to find out is to iterate 
   // through all the active uniforms with glGetActiveUniform() looking for the corresponding
   // 'location'. This will give us the type and size of the data. Since this is a get call
   // maybe that's ok?
-  GLfloat getUniformf (in nsIWebGLProgram program, in GLint location);
-  nsICanvasArray getUniformfv (in nsIWebGLProgram program, in GLint location);
-  GLint getUniformi (in nsIWebGLProgram program, in GLint location);
-  nsICanvasArray getUniformiv (in nsIWebGLProgram program, in GLint location);
+  void getUniform (in nsIWebGLProgram program, in GLint location);
 
   GLint getUniformLocation (in nsIWebGLProgram program, in DOMString name);
 
-  GLfloat getVertexAttribf (in GLuint index, in GLenum pname);
-  nsICanvasArray getVertexAttribfv (in GLuint index, in GLenum pname);
-  GLint getVertexAttribi (in GLuint index, in GLenum pname);
-  nsICanvasArray getVertexAttribiv (in GLuint index, in GLenum pname);
+  void getVertexAttrib (in GLuint index, in GLenum pname);
 
   // TBD
   // void glGetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer);
   GLuint getVertexAttribOffset(in GLuint index, in GLenum pname);
 
   void hint (in GLenum target, in GLenum mode);
 
   GLboolean isBuffer (in nsIWebGLBuffer buffer);
--- a/dom/interfaces/geolocation/nsIDOMGeoPositionError.idl
+++ b/dom/interfaces/geolocation/nsIDOMGeoPositionError.idl
@@ -32,19 +32,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 
 #include "domstubs.idl"
 
-[scriptable, uuid(1B493214-4E58-4A40-AA4C-1AB70C6DDBEC)]
+[scriptable, uuid(AD9FA4C8-EC71-4B2D-8294-9ADF06DDEC32)]
 interface nsIDOMGeoPositionError : nsISupports
 {
-  const unsigned short UNKNOWN_ERROR = 0;
   const unsigned short PERMISSION_DENIED  = 1;
   const unsigned short POSITION_UNAVAILABLE = 2;
   const unsigned short TIMEOUT = 3;
 
   readonly attribute short code;
-  readonly attribute DOMString message;
 };
--- a/dom/public/coreEvents/nsIDOMCompositionListener.h
+++ b/dom/public/coreEvents/nsIDOMCompositionListener.h
@@ -39,29 +39,28 @@
 #define nsIDOMCompositionListener_h__
 
 #include "nsIDOMEvent.h"
 #include "nsIDOMEventListener.h"
 
 /*
  * Key pressed / released / typed listener interface.
  */
-// {93A5A335-AA51-4d32-977D-3680B7722AD5}
+// {47F158C0-C534-43a1-8415-8B17706E2FBC}
 #define NS_IDOMCOMPOSITIONLISTENER_IID	\
-{ 0x93a5a335, 0xaa51, 0x4d32, \
-{ 0x97, 0x7d, 0x36, 0x80, 0xb7, 0x72, 0x2a, 0xd5 } }
+{ 0x47f158c0, 0xc534, 0x43a1, \
+{ 0x84, 0x15, 0x8b, 0x17, 0x70, 0x6e, 0x2f, 0xbc } }
 
 
 class nsIDOMCompositionListener : public nsIDOMEventListener {
 
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOMCOMPOSITIONLISTENER_IID)
 
   NS_IMETHOD HandleStartComposition(nsIDOMEvent* aCompositionEvent) = 0;
   NS_IMETHOD HandleEndComposition(nsIDOMEvent* aCompositionEvent) = 0;
-  NS_IMETHOD HandleQueryComposition(nsIDOMEvent* aCompositionEvent) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMCompositionListener,
                               NS_IDOMCOMPOSITIONLISTENER_IID)
 
 #endif // nsIDOMCompositionListener_h__
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -106,23 +106,16 @@ nsDOMGeoPositionError::~nsDOMGeoPosition
 NS_IMETHODIMP
 nsDOMGeoPositionError::GetCode(PRInt16 *aCode)
 {
   NS_ENSURE_ARG_POINTER(aCode);
   *aCode = mCode;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMGeoPositionError::GetMessage(nsAString & aMessage)
-{
-  aMessage.Truncate();
-  return NS_OK;
-}
-
 void
 nsDOMGeoPositionError::NotifyCallback(nsIDOMGeoPositionErrorCallback* aCallback)
 {
   if (!aCallback)
     return;
   
   // Ensure that the proper context is on the stack (bug 452762)
   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
@@ -707,42 +700,63 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   PRUint32 i; 
   for (i = 0; i < tmp->mPendingCallbacks.Length(); ++i)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mPendingCallbacks[i], nsIGeolocationRequest)
 
   for (i = 0; i < tmp->mWatchingCallbacks.Length(); ++i)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWatchingCallbacks[i], nsIGeolocationRequest)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-nsGeolocation::nsGeolocation(nsIDOMWindow* aContentDom) 
+nsGeolocation::nsGeolocation() 
 : mUpdateInProgress(PR_FALSE)
 {
-  // Remember the window
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContentDom);
-  if (window)
-    mOwner = do_GetWeakReference(window->GetCurrentInnerWindow());
-
-  // Grab the uri of the document
-  nsCOMPtr<nsIDOMDocument> domdoc;
-  aContentDom->GetDocument(getter_AddRefs(domdoc));
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
-  if (doc)
-    doc->NodePrincipal()->GetURI(getter_AddRefs(mURI));
-
-  mService = nsGeolocationService::GetInstance();
-  if (mService)
-    mService->AddLocator(this);
 }
 
 nsGeolocation::~nsGeolocation()
 {
   if (mService)
     Shutdown();
 }
 
+nsresult
+nsGeolocation::Init(nsIDOMWindow* aContentDom)
+{
+  // Remember the window
+  if (aContentDom) {
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContentDom);
+    if (!window)
+      return NS_ERROR_FAILURE;
+
+    mOwner = do_GetWeakReference(window->GetCurrentInnerWindow());
+    if (!mOwner)
+      return NS_ERROR_FAILURE;
+
+    // Grab the uri of the document
+    nsCOMPtr<nsIDOMDocument> domdoc;
+    aContentDom->GetDocument(getter_AddRefs(domdoc));
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
+    if (!doc)
+      return NS_ERROR_FAILURE;
+
+    doc->NodePrincipal()->GetURI(getter_AddRefs(mURI));
+    
+    if (!mURI)
+      return NS_ERROR_FAILURE;
+  }
+
+  // If no aContentDom was passed into us, we are being used
+  // by chrome/c++ and have no mOwner, no mURI, and no need
+  // to prompt.
+  mService = nsGeolocationService::GetInstance();
+  if (mService)
+    mService->AddLocator(this);
+
+  return NS_OK;
+}
+
 void
 nsGeolocation::Shutdown()
 {
   // Shutdown and release all callbacks
   for (PRUint32 i = 0; i< mPendingCallbacks.Length(); i++)
     mPendingCallbacks[i]->Shutdown();
   mPendingCallbacks.Clear();
 
@@ -786,17 +800,17 @@ nsGeolocation::Update(nsIDOMGeoPosition 
   // function can only be called on the primary thread, we
   // can lock this method with a member var.
 
   if (mUpdateInProgress)
     return;
 
   mUpdateInProgress = PR_TRUE;
 
-  if (!OwnerStillExists())
+  if (!WindowOwnerStillExists())
   {
     Shutdown();
     return;
   }
 
   // notify anyone that has been waiting
   for (PRUint32 i = 0; i< mPendingCallbacks.Length(); i++)
     mPendingCallbacks[i]->SendLocation(aSomewhere);
@@ -814,95 +828,124 @@ nsGeolocation::GetCurrentPosition(nsIDOM
                                   nsIDOMGeoPositionErrorCallback *errorCallback,
                                   nsIDOMGeoPositionOptions *options)
 {
   NS_ENSURE_ARG_POINTER(callback);
 
   if (sGeoEnabled == PR_FALSE)
     return NS_ERROR_NOT_AVAILABLE;
 
-  nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
-  if (prompt == nsnull)
+  if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this, callback, errorCallback, options);
+  if (!request)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  if (NS_FAILED(request->Init()))
+    return NS_ERROR_FAILURE; // this as OKAY.  not sure why we wouldn't throw. xxx dft
+
+  if (mOwner) {
+    nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
+    if (prompt == nsnull)
+      return NS_ERROR_NOT_AVAILABLE;
+
+    prompt->Prompt(request);
+
+    mPendingCallbacks.AppendElement(request);
+
+    return NS_OK;
+  }
+
+  if (!nsContentUtils::IsCallerChrome())
+    return NS_ERROR_FAILURE;
+
+  request->Allow();
+
+  mPendingCallbacks.AppendElement(request);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *callback,
+                             nsIDOMGeoPositionErrorCallback *errorCallback,
+                             nsIDOMGeoPositionOptions *options,
+                             PRInt32 *_retval NS_OUTPARAM)
+{
+
+  NS_ENSURE_ARG_POINTER(callback);
+
+  if (sGeoEnabled == PR_FALSE)
     return NS_ERROR_NOT_AVAILABLE;
 
   if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
     return NS_ERROR_NOT_AVAILABLE;
 
   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this, callback, errorCallback, options);
   if (!request)
     return NS_ERROR_OUT_OF_MEMORY;
 
   if (NS_FAILED(request->Init()))
-    return NS_OK;
-
-  prompt->Prompt(request);
+    return NS_ERROR_FAILURE; // this as OKAY.  not sure why we wouldn't throw. xxx dft
 
-  // What if you have a location provider that only sends a location once, then stops.?  fix.
-  mPendingCallbacks.AppendElement(request);
-  return NS_OK;
-}
+  if (mOwner) {
+    nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
+    if (prompt == nsnull)
+      return NS_ERROR_NOT_AVAILABLE;
 
-NS_IMETHODIMP
-nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *aCallback,
-                             nsIDOMGeoPositionErrorCallback *aErrorCallback,
-                             nsIDOMGeoPositionOptions *aOptions, 
-                             PRInt32 *_retval NS_OUTPARAM)
-{
-  NS_ENSURE_ARG_POINTER(aCallback);
+    prompt->Prompt(request);
 
-  if (sGeoEnabled == PR_FALSE)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
-  if (prompt == nsnull)
-    return NS_ERROR_NOT_AVAILABLE;
+    // need to hand back an index/reference.
+    mWatchingCallbacks.AppendElement(request);
+    *_retval = mWatchingCallbacks.Length() - 1;
 
-  if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
-    return NS_ERROR_NOT_AVAILABLE;
+    return NS_OK;
+  }
 
-  nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this, aCallback, aErrorCallback, aOptions);
-  if (!request)
-    return NS_ERROR_OUT_OF_MEMORY;
+  if (!nsContentUtils::IsCallerChrome())
+    return NS_ERROR_FAILURE;
 
-  if (NS_FAILED(request->Init()))
-    return NS_OK;
-
-  prompt->Prompt(request);
+  request->Allow();
 
   // need to hand back an index/reference.
   mWatchingCallbacks.AppendElement(request);
   *_retval = mWatchingCallbacks.Length() - 1;
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGeolocation::ClearWatch(PRInt32 aWatchId)
 {
   PRUint32 count = mWatchingCallbacks.Length();
   if (aWatchId < 0 || count == 0 || aWatchId > count)
-    return NS_ERROR_FAILURE;
+    return NS_OK;
 
   mWatchingCallbacks[aWatchId]->MarkCleared();
   return NS_OK;
 }
 
 PRBool
-nsGeolocation::OwnerStillExists()
+nsGeolocation::WindowOwnerStillExists()
 {
+  // an owner was never set when nsGeolocation
+  // was created, which means that this object
+  // is being used without a window.
+  if (mOwner == nsnull)
+    return PR_TRUE;
+
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
 
-  if (!window)
-    return PR_FALSE;
-
   if (window)
   {
     PRBool closed = PR_FALSE;
     window->GetClosed(&closed);
     if (closed)
       return PR_FALSE;
+
+    nsPIDOMWindow* outer = window->GetOuterWindow();
+    if (!outer || outer->GetCurrentInnerWindow() != window)
+      return PR_FALSE;
   }
 
-  nsPIDOMWindow* outer = window->GetOuterWindow();
-  if (!outer || outer->GetCurrentInnerWindow() != window)
-    return PR_FALSE;
-
   return PR_TRUE;
 }
--- a/dom/src/geolocation/nsGeolocation.h
+++ b/dom/src/geolocation/nsGeolocation.h
@@ -170,17 +170,19 @@ class nsGeolocation : public nsIDOMGeoGe
 {
 public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIDOMGEOGEOLOCATION
 
   NS_DECL_CYCLE_COLLECTION_CLASS(nsGeolocation)
 
-  nsGeolocation(nsIDOMWindow* contentDom);
+  nsGeolocation();
+
+  nsresult Init(nsIDOMWindow* contentDom=nsnull);
 
   // Called by the geolocation device to notify that a location has changed.
   void Update(nsIDOMGeoPosition* aPosition);
 
   // Returns true if any of the callbacks are repeating
   PRBool HasActiveCallbacks();
 
   // Remove request from all callbacks arrays
@@ -191,17 +193,17 @@ public:
 
   // Getter for the URI that this nsGeolocation was loaded from
   nsIURI* GetURI() { return mURI; }
 
   // Getter for the window that this nsGeolocation is owned by
   nsIWeakReference* GetOwner() { return mOwner; }
 
   // Check to see if the widnow still exists
-  PRBool OwnerStillExists();
+  PRBool WindowOwnerStillExists();
 
 private:
 
   ~nsGeolocation();
 
   // Two callback arrays.  The first |mPendingCallbacks| holds objects for only
   // one callback and then they are released/removed from the array.  The second
   // |mWatchingCallbacks| holds objects until the object is explictly removed or
--- a/dom/src/threads/nsDOMThreadService.cpp
+++ b/dom/src/threads/nsDOMThreadService.cpp
@@ -326,17 +326,17 @@ public:
     ClearQueue();
   }
 
   void PutRunnable(nsIRunnable* aRunnable,
                    PRIntervalTime aTimeoutInterval,
                    PRBool aClearQueue) {
     NS_ASSERTION(aRunnable, "Null pointer!");
 
-    // No need to enter the monitor because we should already be in it.
+    PR_ASSERT_CURRENT_THREAD_IN_MONITOR(gDOMThreadService->mMonitor);
 
     if (NS_LIKELY(!aTimeoutInterval)) {
       NS_ADDREF(aRunnable);
       mRunnables.Push(aRunnable);
     }
     else {
       NS_ASSERTION(!mCloseRunnable, "More than one close runnable?!");
       if (aClearQueue) {
@@ -376,16 +376,21 @@ public:
         NS_ERROR("nsDOMThreadService didn't give us a context! Are we out of memory?");
         return NS_ERROR_FAILURE;
     }
 
     NS_ASSERTION(!JS_GetGlobalObject(cx), "Shouldn't have a global!");
 
     JS_SetContextPrivate(cx, mWorker);
 
+    // Go ahead and trigger the operation callback for this context before we
+    // try to run any JS. That way we'll be sure to cancel or suspend as soon as
+    // possible if the compilation takes too long.
+    JS_TriggerOperationCallback(cx);
+
     PRBool killWorkerWhenDone;
 
     // Tell the worker which context it will be using
     if (mWorker->SetGlobalForContext(cx)) {
       RunQueue(cx, &killWorkerWhenDone);
 
       // Code in XPConnect assumes that the context's global object won't be
       // replaced outside of a request.
@@ -428,18 +433,16 @@ protected:
   void ClearQueue() {
     nsCOMPtr<nsIRunnable> runnable;
     while ((runnable = dont_AddRef((nsIRunnable*)mRunnables.PopFront()))) {
       // Loop until all the runnables are dead.
     }
   }
 
   void RunQueue(JSContext* aCx, PRBool* aCloseRunnableSet) {
-    PRBool operationCallbackTriggered = PR_FALSE;
-
     while (1) {
       nsCOMPtr<nsIRunnable> runnable;
       {
         nsAutoMonitor mon(gDOMThreadService->mMonitor);
 
         runnable = dont_AddRef((nsIRunnable*)mRunnables.PopFront());
 
         if (!runnable && mCloseRunnable) {
@@ -464,25 +467,16 @@ protected:
 #endif
           *aCloseRunnableSet = mKillWorkerWhenDone;
           gDOMThreadService->WorkerComplete(this);
           mon.NotifyAll();
           return;
         }
       }
 
-      if (!operationCallbackTriggered) {
-        // Make sure that our operation callback is set to run before starting.
-        // That way we are sure to suspend this worker if needed.
-        JS_TriggerOperationCallback(aCx);
-
-        // Only need to do this the first time.
-        operationCallbackTriggered = PR_TRUE;
-      }
-
       // Clear out any old cruft hanging around in the regexp statics.
       JS_ClearRegExpStatics(aCx);
 
       runnable->Run();
     }
     NS_NOTREACHED("Shouldn't ever get here!");
   }
 
@@ -501,16 +495,17 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorke
 /*******************************************************************************
  * JS environment function and callbacks
  */
 
 JSBool
 DOMWorkerOperationCallback(JSContext* aCx)
 {
   nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(aCx);
+  NS_ASSERTION(worker, "This must never be null!");
 
   PRBool wasSuspended = PR_FALSE;
   PRBool extraThreadAllowed = PR_FALSE;
   jsrefcount suspendDepth = 0;
 
   for (;;) {
     // Kill execution if we're canceled.
     if (worker->IsCanceled()) {
@@ -822,16 +817,26 @@ void
 nsDOMThreadService::Cleanup()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   // This will either be called at 'xpcom-shutdown' or earlier if the call to
   // Init fails somehow. We can therefore assume that all services will still
   // be available here.
 
+  {
+    nsAutoMonitor mon(mMonitor);
+
+    NS_ASSERTION(!mPools.Count(), "Live workers left!");
+    mPools.Clear();
+
+    NS_ASSERTION(!mSuspendedWorkers.Length(), "Suspended workers left!");
+    mSuspendedWorkers.Clear();
+  }
+
   if (gObserverService) {
     gObserverService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
     NS_RELEASE(gObserverService);
 
     UnregisterPrefCallbacks();
   }
 
   // The thread pool holds a circular reference to this service through its
@@ -848,21 +853,16 @@ nsDOMThreadService::Cleanup()
       JS_GC(safeContext);
     }
     NS_RELEASE(gThreadJSContextStack);
   }
 
   // These must be released after the thread pool is shut down.
   NS_IF_RELEASE(gJSRuntimeService);
   NS_IF_RELEASE(gWorkerSecurityManager);
-
-  nsAutoMonitor mon(mMonitor);
-  NS_ASSERTION(!mPools.Count(), "Live workers left!");
-
-  mPools.Clear();
 }
 
 nsresult
 nsDOMThreadService::Dispatch(nsDOMWorker* aWorker,
                              nsIRunnable* aRunnable,
                              PRIntervalTime aTimeoutInterval,
                              PRBool aClearQueue)
 {
@@ -939,31 +939,47 @@ nsDOMThreadService::SetWorkerTimeout(nsD
   if (mWorkersInProgress.Get(aWorker, getter_AddRefs(workerRunnable))) {
     workerRunnable->SetCloseRunnableTimeout(aTimeoutInterval);
   }
 }
 
 void
 nsDOMThreadService::WorkerComplete(nsDOMWorkerRunnable* aRunnable)
 {
-
-  // No need to be in the monitor here because we should already be in it.
+  PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mMonitor);
 
 #ifdef DEBUG
   nsRefPtr<nsDOMWorker>& debugWorker = aRunnable->mWorker;
 
   nsRefPtr<nsDOMWorkerRunnable> runnable;
   NS_ASSERTION(mWorkersInProgress.Get(debugWorker, getter_AddRefs(runnable)) &&
                runnable == aRunnable,
                "Removing a worker that isn't in our hashtable?!");
 #endif
 
   mWorkersInProgress.Remove(aRunnable->mWorker);
 }
 
+PRBool
+nsDOMThreadService::QueueSuspendedWorker(nsDOMWorkerRunnable* aRunnable)
+{
+  nsAutoMonitor mon(mMonitor);
+
+#ifdef DEBUG
+    {
+      // Make sure that the runnable is in mWorkersInProgress.
+      nsRefPtr<nsDOMWorkerRunnable> current;
+      mWorkersInProgress.Get(aRunnable->mWorker, getter_AddRefs(current));
+      NS_ASSERTION(current == aRunnable, "Something crazy wrong here!");
+    }
+#endif
+
+  return mSuspendedWorkers.AppendElement(aRunnable) ? PR_TRUE : PR_FALSE;
+}
+
 /* static */
 JSContext*
 nsDOMThreadService::CreateJSContext()
 {
   JSRuntime* rt;
   gJSRuntimeService->GetRuntime(&rt);
   NS_ENSURE_TRUE(rt, nsnull);
 
@@ -1027,63 +1043,113 @@ nsDOMThreadService::GetPoolForGlobal(nsI
   }
 
   return pool.forget();
 }
 
 void
 nsDOMThreadService::TriggerOperationCallbackForPool(nsDOMWorkerPool* aPool)
 {
-  nsAutoMonitor mon(mMonitor);
+  PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mMonitor);
 
   // See if we need to trigger the operation callback on any currently running
   // contexts.
   PRUint32 contextCount = mJSContexts.Length();
   for (PRUint32 index = 0; index < contextCount; index++) {
     JSContext*& cx = mJSContexts[index];
     nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(cx);
     if (worker && worker->Pool() == aPool) {
       JS_TriggerOperationCallback(cx);
     }
   }
 }
 
 void
+nsDOMThreadService::RescheduleSuspendedWorkerForPool(nsDOMWorkerPool* aPool)
+{
+  PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mMonitor);
+
+  PRUint32 count = mSuspendedWorkers.Length();
+  if (!count) {
+    // Nothing to do here.
+    return;
+  }
+
+  nsTArray<nsDOMWorkerRunnable*> others(count);
+
+  for (PRUint32 index = 0; index < count; index++) {
+    nsDOMWorkerRunnable* runnable = mSuspendedWorkers[index];
+
+#ifdef DEBUG
+    {
+      // Make sure that the runnable never left mWorkersInProgress.
+      nsRefPtr<nsDOMWorkerRunnable> current;
+      mWorkersInProgress.Get(runnable->mWorker, getter_AddRefs(current));
+      NS_ASSERTION(current == runnable, "Something crazy wrong here!");
+    }
+#endif
+
+    if (runnable->mWorker->Pool() == aPool) {
+#ifdef DEBUG
+      nsresult rv =
+#endif
+      mThreadPool->Dispatch(runnable, NS_DISPATCH_NORMAL);
+      NS_ASSERTION(NS_SUCCEEDED(rv), "This shouldn't ever fail!");
+    }
+    else {
+      others.AppendElement(runnable);
+    }
+  }
+
+  mSuspendedWorkers.SwapElements(others);
+}
+
+void
 nsDOMThreadService::CancelWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject)
 {
   NS_ASSERTION(aGlobalObject, "Null pointer!");
 
   nsRefPtr<nsDOMWorkerPool> pool = GetPoolForGlobal(aGlobalObject, PR_TRUE);
   if (pool) {
     pool->Cancel();
+
+    nsAutoMonitor mon(mMonitor);
+
     TriggerOperationCallbackForPool(pool);
+    RescheduleSuspendedWorkerForPool(pool);
   }
 }
 
 void
 nsDOMThreadService::SuspendWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject)
 {
   NS_ASSERTION(aGlobalObject, "Null pointer!");
 
   nsRefPtr<nsDOMWorkerPool> pool = GetPoolForGlobal(aGlobalObject, PR_FALSE);
   if (pool) {
     pool->Suspend();
+
+    nsAutoMonitor mon(mMonitor);
     TriggerOperationCallbackForPool(pool);
   }
 }
 
 void
 nsDOMThreadService::ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject)
 {
   NS_ASSERTION(aGlobalObject, "Null pointer!");
 
   nsRefPtr<nsDOMWorkerPool> pool = GetPoolForGlobal(aGlobalObject, PR_FALSE);
   if (pool) {
     pool->Resume();
+
+    nsAutoMonitor mon(mMonitor);
+
     TriggerOperationCallbackForPool(pool);
+    RescheduleSuspendedWorkerForPool(pool);
   }
 }
 
 void
 nsDOMThreadService::NoteEmptyPool(nsDOMWorkerPool* aPool)
 {
   NS_ASSERTION(aPool, "Null pointer!");
 
--- a/dom/src/threads/nsDOMThreadService.h
+++ b/dom/src/threads/nsDOMThreadService.h
@@ -135,16 +135,17 @@ private:
 
   static JSContext* CreateJSContext();
 
   already_AddRefed<nsDOMWorkerPool>
     GetPoolForGlobal(nsIScriptGlobalObject* aGlobalObject,
                      PRBool aRemove);
 
   void TriggerOperationCallbackForPool(nsDOMWorkerPool* aPool);
+  void RescheduleSuspendedWorkerForPool(nsDOMWorkerPool* aPool);
 
   void NoteEmptyPool(nsDOMWorkerPool* aPool);
 
   void TimeoutReady(nsDOMWorkerTimeout* aTimeout);
 
   nsresult RegisterWorker(nsDOMWorker* aWorker,
                           nsIScriptGlobalObject* aGlobalObject);
 
@@ -156,16 +157,18 @@ private:
   void RegisterPrefCallbacks();
   void UnregisterPrefCallbacks();
 
   static int PrefCallback(const char* aPrefName,
                           void* aClosure);
 
   static PRUint32 GetWorkerCloseHandlerTimeoutMS();
 
+  PRBool QueueSuspendedWorker(nsDOMWorkerRunnable* aRunnable);
+
   // Our internal thread pool.
   nsCOMPtr<nsIThreadPool> mThreadPool;
 
   // Maps nsIScriptGlobalObject* to nsDOMWorkerPool.
   nsRefPtrHashtable<nsISupportsHashKey, nsDOMWorkerPool> mPools;
 
   // mMonitor protects all access to mWorkersInProgress and
   // mCreationsInProgress.
@@ -173,16 +176,20 @@ private:
 
   // A map from nsDOMWorkerThread to nsDOMWorkerRunnable.
   nsRefPtrHashtable<nsVoidPtrHashKey, nsDOMWorkerRunnable> mWorkersInProgress;
 
   // A list of active JSContexts that we've created. Always protected with
   // mMonitor.
   nsTArray<JSContext*> mJSContexts;
 
+  // A list of worker runnables that were never started because the worker was
+  // suspended. Always protected with mMonitor.
+  nsTArray<nsDOMWorkerRunnable*> mSuspendedWorkers;
+
   nsString mAppName;
   nsString mAppVersion;
   nsString mPlatform;
   nsString mUserAgent;
 
   PRBool mNavigatorStringsLoaded;
 };
 
--- a/dom/src/threads/test/closeOnGC_worker.js
+++ b/dom/src/threads/test/closeOnGC_worker.js
@@ -1,5 +1,7 @@
 onclose = function() {
   var xhr = new XMLHttpRequest();
   xhr.open("POST", "closeOnGC_server.sjs", false);
   xhr.send();
 };
+
+postMessage("ready");
--- a/dom/src/threads/test/test_closeOnGC.html
+++ b/dom/src/threads/test/test_closeOnGC.html
@@ -15,21 +15,23 @@
   function CC() {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
           .getInterface(Components.interfaces.nsIDOMWindowUtils)
           .garbageCollect();
   }
 
   var worker = new Worker("closeOnGC_worker.js");
-  worker = null;
-
-  CC();
+  worker.onmessage = function(event) {
+    is(event.data, "ready");
+    worker = null;
+  }
 
   var interval = setInterval(function() {
+    dump("xxxben interval\n");
     var xhr = new XMLHttpRequest();
     xhr.open("GET", "closeOnGC_server.sjs", false);
     xhr.send();
     if (xhr.responseText != "closed") {
       CC();
       return;
     }
     clearInterval(interval);
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug456151.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=456151
+-->
+<head>
+  <title>Test for Bug 456151</title>
+  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.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=456151">Mozilla Bug 456151</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 456151 **/
+var intercepted = false;
+
+// Set up our new addEventListener
+var proto = HTMLParagraphElement.prototype;
+proto.oldAdd = proto.addEventListener;
+proto.addEventListener = function(ev, list, capt) {
+  intercepted = true;
+  this.oldAdd(ev, list, capt);
+}
+proto.oldRemove = proto.removeEventListener;
+proto.removeEventListener = function(ev, list, capt) {
+  intercepted = true;
+  this.oldRemove(ev, list, capt);
+}
+
+var called = false;
+
+var func = function() { called = true; };
+$("display").addEventListener("click", func, false);
+is(intercepted, true, "Should have interecepted addEventListener call");
+
+sendMouseEvent({type: "click"}, "display");
+is(called, true, "Should have called event listener");
+
+interecepted = false;
+called = false;
+
+$("display").removeEventListener("click", func, false);
+is(intercepted, true, "Should have interecepted removeEventListener call");
+
+sendMouseEvent({type: "click"}, "display");
+is(called, false, "Should have removed event listener");
+
+// And now some simple sanity tests
+var recursion = false;
+var x = document.createElement("span");
+HTMLSpanElement.prototype.addEventListener =
+  function(a, b, c) {
+    return x.addEventListener(a,b,c);
+  }
+try {
+  x.addEventListener("click", function() { called = true; }, false);
+} catch (e) {
+  recursion = e.message.match(/recursion/);
+}
+SimpleTest.isDeeply(recursion, ["recursion"], "Caught infinite recursion");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/tests/mochitest/chrome/Makefile.in
+++ b/dom/tests/mochitest/chrome/Makefile.in
@@ -54,12 +54,13 @@ include $(topsrcdir)/config/rules.mk
 		domstorage_global.js \
 		focus_window2.xul \
 		focus_frameset.html \
 		child_focus_frame.html \
 		test_focus_switchbinding.xul \
 		test_focus.xul \
 		window_focus.xul \
 		test_focused_link_scroll.xul \
+		test_geolocation.xul \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/test_geolocation.xul
@@ -0,0 +1,39 @@
+<?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"?>
+<!--
+  Test for Geolocation in chrome
+  -->
+<window id="sample-window" width="400" height="400"
+        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>      
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+var geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsIDOMGeoGeolocation);
+geolocation.getCurrentPosition(done, error);
+
+function error(error)
+{
+  ok(0, "error occured trying to get geolocation from chrome");
+  SimpleTest.finish();
+  newwindow.close();
+}
+function done(position)
+{
+  ok(position, "geolocation was found from chrome");
+  SimpleTest.finish();
+  newwindow.close();
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+</window>
--- a/dom/tests/mochitest/geolocation/Makefile.in
+++ b/dom/tests/mochitest/geolocation/Makefile.in
@@ -53,16 +53,18 @@ include $(topsrcdir)/config/rules.mk
 		test_manyWindows.html \
 		test_allowCurrent.html \
 		test_allowWatch.html \
 		test_cancelCurrent.html \
 		test_cancelWatch.html \
 		test_clearWatch.html \
 		test_clearWatch_invalid.html \
 		test_timeoutWatch.html \
+		test_windowClose.html \
+		windowTest.html \
 		geolocation_common.js  \
 		geolocation.html \
 		test_optional_api_params.html \
         network_geolocation.sjs \
 		$(NULL)
 
 
 libs:: 	$(_TEST_FILES)
--- a/dom/tests/mochitest/geolocation/test_clearWatch_invalid.html
+++ b/dom/tests/mochitest/geolocation/test_clearWatch_invalid.html
@@ -18,31 +18,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 463039 **/
 
 // there are no watches, so this should always throw
 for (x=-10; x<10; x++) {
-    try {
-        navigator.geolocation.clearWatch(x);
-        ok(0, "clearWatch should throw");
-    } catch (ex) {
-        ok(1, "clearWatch with a bad value did throw");
-    }
+    navigator.geolocation.clearWatch(x);
+    ok(1, "clearWatch should not throw");
 }
 
 // lets try something huge
-try {
-    navigator.geolocation.clearWatch(Number.MAX_VALUE);
-    ok(0, "clearWatch should throw");
-} catch (ex) {
-    ok(1, "clearWatch with a bad value did throw");
-}
-
-
+navigator.geolocation.clearWatch(Number.MAX_VALUE);
+ok(1, "clearWatch should not throw");
     
 </script>
 </pre>
 </body>
 </html>
 
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/geolocation/test_windowClose.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=493615
+-->
+<head>
+  <title>Test for geolocation in chrome </title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="geolocation_common.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=493615">Mozilla Bug 493615</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function done() {
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+window.open("windowTest.html");
+