Merge mozilla-central into electrolysis.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Wed, 03 Feb 2010 13:28:22 -0500
changeset 46636 7270e1c27f5b3535526d8098fec91aa765a06865
parent 46635 c2d2de888c99294c67ee75ad10f7ceb4acb2fe90 (current diff)
parent 37858 e2119ce306c0821645a34fc6b644e0f306ba0708 (diff)
child 46637 482029a3e147a90346dd9e00756adcfa0ec6a648
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone1.9.3a1pre
Merge mozilla-central into electrolysis.
build/automation.py.in
content/base/src/nsGkAtomList.h
content/events/src/Makefile.in
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
dom/plugins/PluginModuleChild.cpp
gfx/src/nsColorNames.cpp
gfx/tests/DumpColors.cpp
js/src/xpconnect/shell/xpcshell.cpp
modules/plugin/base/src/nsPluginHost.cpp
modules/plugin/test/testplugin/nptest.cpp
netwerk/base/src/nsStreamObserverProxy.cpp
netwerk/base/src/nsStreamObserverProxy.h
security/manager/ssl/src/nsSmartCardEvent.cpp
toolkit/mozapps/xpinstall/locale/xpinstallConfirm.properties.txt
xpcom/proxy/public/nsIProxyCreateInstance.idl
xpcom/proxy/public/nsProxyEvent.h
xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s
xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s
--- a/accessible/public/nsIAccessibilityService.idl
+++ b/accessible/public/nsIAccessibilityService.idl
@@ -39,17 +39,17 @@
 #include "nsISupports.idl"
 #include "nsIAccessibleRetrieval.idl"
 
 interface nsIDocument;
 interface nsIFrame;
 interface nsObjectFrame;
 interface nsIContent;
 
-[uuid(e0498def-1552-4763-8c47-6c6cc36c7aa0)]
+[uuid(84a3ab70-8f7e-4610-9cd8-bd69308b76c5)]
 interface nsIAccessibilityService : nsIAccessibleRetrieval
 {
   nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode);
   nsIAccessible createRootAccessible(in nsIPresShell aShell, in nsIDocument aDocument);
 
   nsIAccessible createHTML4ButtonAccessible(in nsIFrame aFrame);
   nsIAccessible createHyperTextAccessible(in nsIFrame aFrame);
   nsIAccessible createHTMLBRAccessible(in nsIFrame aFrame);
@@ -69,29 +69,16 @@ interface nsIAccessibilityService : nsIA
   nsIAccessible createHTMLRadioButtonAccessible(in nsIFrame aFrame);
   nsIAccessible createHTMLSelectOptionAccessible(in nsIDOMNode aNode, in nsIAccessible aAccParent, in nsIWeakReference aPresShell);
   nsIAccessible createHTMLTableAccessible(in nsIFrame aFrame);
   nsIAccessible createHTMLTableCellAccessible(in nsIFrame aFrame);
   nsIAccessible createHTMLTextAccessible(in nsIFrame aFrame);
   nsIAccessible createHTMLTextFieldAccessible(in nsIFrame aFrame);
   nsIAccessible createHTMLCaptionAccessible(in nsIFrame aFrame);
 
-  /**
-   * Return an accessible for the given DOM node.
-   *
-   * @param  aNode       [in] the given node
-   * @param  aPresShell  [in] the pres shell of the node
-   * @param  aWeakShell  [in] the weak shell for the pres shell
-   * @param  aFrameHint  [in] the frame of the given node
-   * @param  aIsHidden   [out] indicates whether the node's frame is hidden
-   */
-  nsIAccessible getAccessible(in nsIDOMNode aNode, in nsIPresShell aPresShell,
-                              in nsIWeakReference aWeakShell,
-                              in nsIFrame aFrameHint, out boolean aIsHidden);
-
   // For gtk+ native window accessible
   nsIAccessible addNativeRootAccessible(in voidPtr aAtkAccessible);
   void removeNativeRootAccessible(in nsIAccessible aRootAccessible);
 
   /**
    * Used to describe sort of changes leading to accessible tree invalidation.
    */
   const unsigned long NODE_APPEND = 0x01;
--- a/accessible/public/nsIAccessibleRetrieval.idl
+++ b/accessible/public/nsIAccessibleRetrieval.idl
@@ -51,17 +51,17 @@ interface nsIDOMDOMStringList;
  * An interface for in-process accessibility clients
  * wishing to get an nsIAccessible or nsIAccessNode for
  * a given DOM node.
  * More documentation at:
  *   http://www.mozilla.org/projects/ui/accessibility
  *
  * @status UNDER_REVIEW
  */
-[scriptable, uuid(244e4c67-a1d3-44f2-9cab-cdaa31b68046)]
+[scriptable, uuid(7eb49afb-6298-4ce6-816f-9615936540f4)]
 interface nsIAccessibleRetrieval : nsISupports
 {
   /**
    * Return an nsIAccessible for a DOM node in pres shell 0.
    * Create a new accessible of the appropriate type if necessary,
    * or use one from the accessibility cache if it already exists.
    * @param aNode The DOM node to get an accessible for.
    * @return The nsIAccessible for the given DOM node.
@@ -88,36 +88,16 @@ interface nsIAccessibleRetrieval : nsISu
    *
    * @param aNode - the DOM node to get relevant content node.
    *
    * @return - the DOM node for parent attached accessible
    */
   nsIDOMNode getRelevantContentNodeFor(in nsIDOMNode aNode);
 
   /**
-   * Return an nsIAccessible for a DOM node in pres shell for this DOM window.
-   * Create a new accessible of the appropriate type if necessary,
-   * or use one from the accessibility cache if it already exists.
-   * @param aNode   The DOM node to get an accessible for.
-   * @param aDOMWin The DOM window containing the node.
-   * @return The nsIAccessible for the given DOM node.
-   */
-  nsIAccessible getAccessibleInWindow(in nsIDOMNode aNode, in nsIDOMWindow aDOMWin);
-
-  /**
-   * Return an nsIAccessible for a DOM node in the given weak shell.
-   * Create a new accessible of the appropriate type if necessary,
-   * or use one from the accessibility cache if it already exists.
-   * @param aNode      The DOM node to get an accessible for.
-   * @param aPresShell The presentation shell which contains layout info for the DOM node.
-   * @return The nsIAccessible for the given DOM node.
-   */
-  nsIAccessible getAccessibleInWeakShell(in nsIDOMNode aNode, in nsIWeakReference aPresShell);
-
-  /**
    * Return an nsIAccessible for a DOM node in the given pres shell.
    * Create a new accessible of the appropriate type if necessary,
    * or use one from the accessibility cache if it already exists.
    * @param aNode      The DOM node to get an accessible for.
    * @param aPresShell The presentation shell which contains layout info for the DOM node.
    * @return The nsIAccessible for the given DOM node.
    */
   nsIAccessible getAccessibleInShell(in nsIDOMNode aNode, in nsIPresShell aPresShell);
--- a/accessible/src/base/nsAccEvent.cpp
+++ b/accessible/src/base/nsAccEvent.cpp
@@ -290,18 +290,17 @@ nsAccReorderEvent::IsUnconditionalEvent(
 
 PRBool
 nsAccReorderEvent::HasAccessibleInReasonSubtree()
 {
   if (!mReasonNode)
     return PR_FALSE;
 
   nsCOMPtr<nsIAccessible> accessible;
-  nsAccessNode::GetAccService()->GetAccessibleFor(mReasonNode,
-                                                  getter_AddRefs(accessible));
+  GetAccService()->GetAccessibleFor(mReasonNode, getter_AddRefs(accessible));
 
   return accessible || nsAccUtils::HasAccessibleChildren(mReasonNode);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccStateChangeEvent
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -167,18 +167,17 @@ nsAccUtils::GetPositionAndSizeForXULSele
   *aPosInSet = indexOf;
 
   for (PRUint32 index = 0; index < itemsCount; index++) {
     nsCOMPtr<nsIDOMXULSelectControlItemElement> currItem;
     control->GetItemAtIndex(index, getter_AddRefs(currItem));
     nsCOMPtr<nsIDOMNode> currNode(do_QueryInterface(currItem));
 
     nsCOMPtr<nsIAccessible> itemAcc;
-    nsAccessNode::GetAccService()->GetAccessibleFor(currNode,
-                                                    getter_AddRefs(itemAcc));
+    GetAccService()->GetAccessibleFor(currNode, getter_AddRefs(itemAcc));
     if (!itemAcc ||
         State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
       (*aSetSize)--;
       if (index < static_cast<PRUint32>(indexOf))
         (*aPosInSet)--;
     }
   }
 
@@ -209,18 +208,17 @@ nsAccUtils::GetPositionAndSizeForXULCont
 
   // Calculate set size and position in the set.
   *aSetSize = 0, *aPosInSet = 0;
   for (PRInt32 index = indexOf; index >= 0; index--) {
     nsCOMPtr<nsIDOMXULElement> item;
     container->GetItemAtIndex(index, getter_AddRefs(item));
 
     nsCOMPtr<nsIAccessible> itemAcc;
-    nsAccessNode::GetAccService()->GetAccessibleFor(item,
-                                                    getter_AddRefs(itemAcc));
+    GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc));
 
     if (itemAcc) {
       PRUint32 itemRole = Role(itemAcc);
       if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
         break; // We reached the beginning of our group.
 
       PRUint32 itemState = State(itemAcc);
       if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE)) {
@@ -231,18 +229,17 @@ nsAccUtils::GetPositionAndSizeForXULCont
   }
 
   for (PRInt32 index = indexOf + 1; index < static_cast<PRInt32>(itemsCount);
        index++) {
     nsCOMPtr<nsIDOMXULElement> item;
     container->GetItemAtIndex(index, getter_AddRefs(item));
     
     nsCOMPtr<nsIAccessible> itemAcc;
-    nsAccessNode::GetAccService()->GetAccessibleFor(item,
-                                                    getter_AddRefs(itemAcc));
+    GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc));
 
     if (itemAcc) {
       PRUint32 itemRole = Role(itemAcc);
       if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
         break; // We reached the end of our group.
 
       PRUint32 itemState = State(itemAcc);
       if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE))
@@ -519,18 +516,17 @@ nsAccUtils::GetSelectableContainer(nsIAc
 
   return accessible.forget();
 }
 
 already_AddRefed<nsIAccessible>
 nsAccUtils::GetMultiSelectableContainer(nsIDOMNode *aNode)
 {
   nsCOMPtr<nsIAccessible> accessible;
-  nsAccessNode::GetAccService()->GetAccessibleFor(aNode,
-                                                  getter_AddRefs(accessible));
+  GetAccService()->GetAccessibleFor(aNode, getter_AddRefs(accessible));
 
   nsCOMPtr<nsIAccessible> container =
     GetSelectableContainer(accessible, State(accessible));
 
   if (State(container) & nsIAccessibleStates::STATE_MULTISELECTABLE)
     return container.forget();
 
   return nsnull;
@@ -568,35 +564,30 @@ nsAccUtils::GetTextAccessibleFromSelecti
     return nsnull;
 
   PRInt32 focusOffset = 0;
   aSelection->GetFocusOffset(&focusOffset);
 
   nsCOMPtr<nsIDOMNode> resultNode =
     nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
 
-  nsIAccessibilityService *accService = nsAccessNode::GetAccService();
-
   // Get text accessible containing the result node.
   while (resultNode) {
     // Make sure to get the correct starting node for selection events inside
     // XBL content trees.
     nsCOMPtr<nsIDOMNode> relevantNode;
-    nsresult rv = accService->
-      GetRelevantContentNodeFor(resultNode, getter_AddRefs(relevantNode));
-    if (NS_FAILED(rv))
-      return nsnull;
-
+    GetAccService()->GetRelevantContentNodeFor(resultNode, 
+                                               getter_AddRefs(relevantNode));
     if (relevantNode)
       resultNode.swap(relevantNode);
 
     nsCOMPtr<nsIContent> content = do_QueryInterface(resultNode);
     if (!content || !content->IsNodeOfType(nsINode::eTEXT)) {
       nsCOMPtr<nsIAccessible> accessible;
-      accService->GetAccessibleFor(resultNode, getter_AddRefs(accessible));
+      GetAccService()->GetAccessibleFor(resultNode, getter_AddRefs(accessible));
       if (accessible) {
         nsIAccessibleText *textAcc = nsnull;
         CallQueryInterface(accessible, &textAcc);
         if (textAcc) {
           if (aNode)
             NS_ADDREF(*aNode = resultNode);
 
           return textAcc;
@@ -951,18 +942,17 @@ nsAccUtils::MustPrune(nsIAccessible *aAc
     role == nsIAccessibleRole::ROLE_PROGRESSBAR ||
     role == nsIAccessibleRole::ROLE_SEPARATOR;
 }
 
 PRBool
 nsAccUtils::IsNodeRelevant(nsIDOMNode *aNode)
 {
   nsCOMPtr<nsIDOMNode> relevantNode;
-  nsAccessNode::GetAccService()->GetRelevantContentNodeFor(aNode,
-                                                           getter_AddRefs(relevantNode));
+  GetAccService()->GetRelevantContentNodeFor(aNode, getter_AddRefs(relevantNode));
   return aNode == relevantNode;
 }
 
 nsresult
 nsAccUtils::GetHeaderCellsFor(nsIAccessibleTable *aTable,
                               nsIAccessibleTableCell *aCell,
                               PRInt32 aRowOrColHeaderCells, nsIArray **aCells)
 {
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -77,22 +77,16 @@ nsIStringBundle *nsAccessNode::gKeyStrin
 nsIDOMNode *nsAccessNode::gLastFocusedNode = 0;
 
 PRBool nsAccessNode::gIsCacheDisabled = PR_FALSE;
 PRBool nsAccessNode::gIsFormFillEnabled = PR_FALSE;
 nsAccessNodeHashtable nsAccessNode::gGlobalDocAccessibleCache;
 
 nsApplicationAccessibleWrap *nsAccessNode::gApplicationAccessible = nsnull;
 
-nsIAccessibilityService*
-nsAccessNode::GetAccService()
-{
-  return nsAccessibilityService::GetAccessibilityService();
-}
-
 /*
  * Class nsAccessNode
  */
  
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible. nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_0(nsAccessNode)
@@ -152,23 +146,20 @@ nsAccessNode::Init()
     // No doc accessible yet for this node's document. 
     // There was probably an accessible event fired before the 
     // current document was ever asked for by the assistive technology.
     // Create a doc accessible so we can cache this node
     nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
     if (presShell) {
       nsCOMPtr<nsIDOMNode> docNode(do_QueryInterface(presShell->GetDocument()));
       if (docNode) {
-        nsIAccessibilityService *accService = GetAccService();
-        if (accService) {
-          nsCOMPtr<nsIAccessible> accessible;
-          accService->GetAccessibleInShell(docNode, presShell,
-                                           getter_AddRefs(accessible));
-          docAccessible = do_QueryInterface(accessible);
-        }
+        nsCOMPtr<nsIAccessible> accessible;
+        GetAccService()->GetAccessibleInShell(docNode, presShell,
+                                              getter_AddRefs(accessible));
+        docAccessible = do_QueryInterface(accessible);
       }
     }
     NS_ASSERTION(docAccessible, "Cannot cache new nsAccessNode");
     if (!docAccessible) {
       return NS_ERROR_FAILURE;
     }
   }
 
@@ -468,26 +459,24 @@ nsAccessNode::ScrollToPoint(PRUint32 aCo
   return NS_OK;
 }
 
 nsresult
 nsAccessNode::MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode)
 {
   *aAccessNode = nsnull;
   
-  nsIAccessibilityService *accService = GetAccService();
-  NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
-
   nsCOMPtr<nsIAccessNode> accessNode;
-  accService->GetCachedAccessNode(aNode, mWeakShell, getter_AddRefs(accessNode));
+  GetAccService()->GetCachedAccessNode(aNode, mWeakShell,
+                                       getter_AddRefs(accessNode));
 
   if (!accessNode) {
     nsCOMPtr<nsIAccessible> accessible;
-    accService->GetAccessibleInWeakShell(aNode, mWeakShell,
-                                         getter_AddRefs(accessible));
+    GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell,
+                                              getter_AddRefs(accessible));
 
     accessNode = do_QueryInterface(accessible);
   }
 
   if (accessNode) {
     NS_ADDREF(*aAccessNode = accessNode);
     return NS_OK;
   }
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -51,17 +51,17 @@
 #include "nsIAccessibleTypes.h"
 #include "nsIAccessNode.h"
 #include "nsIContent.h"
 #include "nsIDOMNode.h"
 #include "nsINameSpaceManager.h"
 #include "nsIStringBundle.h"
 #include "nsWeakReference.h"
 #include "nsInterfaceHashtable.h"
-#include "nsIAccessibilityService.h"
+#include "nsAccessibilityService.h"
 
 class nsIPresShell;
 class nsPresContext;
 class nsIAccessibleDocument;
 class nsIFrame;
 class nsIDOMNodeList;
 class nsRootAccessible;
 class nsApplicationAccessibleWrap;
@@ -140,17 +140,17 @@ class nsAccessNode: public nsIAccessNode
     static already_AddRefed<nsIAccessibleDocument> GetDocAccessibleFor(nsIDocument *aDocument);
     static already_AddRefed<nsIAccessibleDocument> GetDocAccessibleFor(nsIWeakReference *aWeakShell);
     static already_AddRefed<nsIAccessibleDocument> GetDocAccessibleFor(nsIDocShellTreeItem *aContainer, PRBool aCanCreate = PR_FALSE);
     static already_AddRefed<nsIAccessibleDocument> GetDocAccessibleFor(nsIDOMNode *aNode);
 
     already_AddRefed<nsRootAccessible> GetRootAccessible();
 
     static nsIDOMNode *gLastFocusedNode;
-    static nsIAccessibilityService* GetAccService();
+
     already_AddRefed<nsIDOMNode> GetCurrentFocus();
 
     /**
      * Returns true when the accessible is defunct.
      */
     virtual PRBool IsDefunct();
 
     /**
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1168,55 +1168,36 @@ nsAccessibilityService::GetAttachedAcces
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (relevantNode != aNode)
     return NS_OK;
 
   return GetAccessibleFor(aNode, aAccessible);
 }
 
-NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWindow(nsIDOMNode *aNode, 
-                                                            nsIDOMWindow *aWin,
-                                                            nsIAccessible **aAccessible)
-{
-  NS_ENSURE_ARG_POINTER(aAccessible);
-  *aAccessible = nsnull;
-
-  NS_ENSURE_ARG(aNode);
-  NS_ENSURE_ARG(aWin);
-
-  nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(aWin));
-  nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
-  if (!docShell)
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIPresShell> presShell;
-  docShell->GetPresShell(getter_AddRefs(presShell));
-  return GetAccessibleInShell(aNode, presShell, aAccessible);
-}
-
 NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode, 
                                                            nsIPresShell *aPresShell,
                                                            nsIAccessible **aAccessible) 
 {
   NS_ENSURE_ARG_POINTER(aAccessible);
   *aAccessible = nsnull;
 
   NS_ENSURE_ARG(aNode);
   NS_ENSURE_ARG(aPresShell);
 
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell));
   PRBool isHiddenUnused = false;
   return GetAccessible(aNode, aPresShell, weakShell, 
                        nsnull, &isHiddenUnused, aAccessible);
 }
 
-NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode, 
-                                                               nsIWeakReference *aWeakShell,
-                                                               nsIAccessible **aAccessible) 
+nsresult
+nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode, 
+                                                 nsIWeakReference *aWeakShell,
+                                                 nsIAccessible **aAccessible) 
 {
   NS_ENSURE_ARG_POINTER(aAccessible);
   *aAccessible = nsnull;
 
   NS_ENSURE_ARG(aNode);
   NS_ENSURE_ARG(aWeakShell);
 
   nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(aWeakShell));
@@ -1267,22 +1248,23 @@ static PRBool HasRelatedContent(nsIConte
         // ancestor has activedescendant property, this content could be active
       return PR_TRUE;
     }
   }
 
   return PR_FALSE;
 }
 
-NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
-                                                    nsIPresShell *aPresShell,
-                                                    nsIWeakReference *aWeakShell,
-                                                    nsIFrame *aFrameHint,
-                                                    PRBool *aIsHidden,
-                                                    nsIAccessible **aAccessible)
+nsresult
+nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
+                                      nsIPresShell *aPresShell,
+                                      nsIWeakReference *aWeakShell,
+                                      nsIFrame *aFrameHint,
+                                      PRBool *aIsHidden,
+                                      nsIAccessible **aAccessible)
 {
   NS_ENSURE_ARG_POINTER(aAccessible);
   *aAccessible = nsnull;
 
   if (!aPresShell || !aWeakShell || gIsShutdown) {
     return NS_ERROR_FAILURE;
   }
 
@@ -2049,45 +2031,34 @@ nsAccessibilityService::InvalidateSubtre
     docAcc->InvalidateCacheSubtree(aChangeContent, aChangeType);
 
   return NS_OK;
 }
 
 //////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////
 
-nsresult 
-nsAccessibilityService::GetAccessibilityService(nsIAccessibilityService** aResult)
-{
-  NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
-  *aResult = nsnull;
-
-  if (!gAccessibilityService) {
-    gAccessibilityService = new nsAccessibilityService();
-    NS_ENSURE_TRUE(gAccessibilityService, NS_ERROR_OUT_OF_MEMORY);
-
-    gIsShutdown = PR_FALSE;
-  }
-
-  NS_ADDREF(*aResult = gAccessibilityService);
-  return NS_OK;
-}
-
-nsIAccessibilityService*
-nsAccessibilityService::GetAccessibilityService()
-{
-  NS_ASSERTION(!gIsShutdown,
-               "Going to deal with shutdown accessibility service!");
-  return gAccessibilityService;
-}
-
+/**
+ * Return accessibility service; creating one if necessary.
+ */
 nsresult
 NS_GetAccessibilityService(nsIAccessibilityService** aResult)
 {
-  return nsAccessibilityService::GetAccessibilityService(aResult);
+   NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
+   *aResult = nsnull;
+ 
+  if (!nsAccessibilityService::gAccessibilityService) {
+    nsAccessibilityService::gAccessibilityService = new nsAccessibilityService();
+    NS_ENSURE_TRUE(nsAccessibilityService::gAccessibilityService, NS_ERROR_OUT_OF_MEMORY);
+ 
+    nsAccessibilityService::gIsShutdown = PR_FALSE;
+   }
+ 
+  NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
+  return NS_OK;
 }
 
 nsresult
 nsAccessibilityService::GetAccessibleForDeckChildren(nsIDOMNode *aNode, nsIAccessible** aAccessible)
 {
   nsCOMPtr<nsIWeakReference> weakShell;
   GetShellFromNode(aNode, getter_AddRefs(weakShell));
   NS_ENSURE_TRUE(weakShell, NS_ERROR_FAILURE);
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -77,30 +77,44 @@ public:
    * Return presentation shell for the given node.
    *
    * @param aNode - the given DOM node.
    */
   static nsresult GetShellFromNode(nsIDOMNode *aNode,
                                    nsIWeakReference **weakShell);
 
   /**
-   * Return accessibility service (static instance of this class).
-   */
-  static nsresult GetAccessibilityService(nsIAccessibilityService** aResult);
-
-  /**
-   * Return cached accessibility service.
-   */
-  static nsIAccessibilityService* GetAccessibilityService();
-
-  /**
    * Indicates whether accessibility service was shutdown.
    */
   static PRBool gIsShutdown;
 
+  /**
+   * Return an accessible for the given DOM node.
+   *
+   * @param  aNode       [in] the given node
+   * @param  aPresShell  [in] the pres shell of the node
+   * @param  aWeakShell  [in] the weak shell for the pres shell
+   * @param  aFrameHint  [in] the frame of the given node
+   * @param  aIsHidden   [out] indicates whether the node's frame is hidden
+   */
+  nsresult GetAccessible(nsIDOMNode *aNode, nsIPresShell *aPresShell,
+                         nsIWeakReference *aWeakShell, nsIFrame *aFrameHint,
+                         PRBool *aIsHidden, nsIAccessible **aAccessible);
+
+  /**
+   * Return an accessible for a DOM node in the given pres shell.
+   * 
+   * @param aNode       [in] the given node.
+   * @param aPresShell  [in] the presentation shell of the given node.
+   * @param aAccessible [out] the nsIAccessible for the given node.
+   */
+  nsresult GetAccessibleInWeakShell(nsIDOMNode *aNode,
+                                    nsIWeakReference *aPresShell,
+                                    nsIAccessible **aAccessible);
+
 private:
   /**
    * Return presentation shell, DOM node for the given frame.
    *
    * @param aFrame - the given frame
    * @param aShell [out] - presentation shell for DOM node associated with the
    *                 given frame
    * @param aContent [out] - DOM node associated with the given frame
@@ -165,21 +179,35 @@ private:
    *  @param  aWebProgress  [in] the nsIWebProgress object for the load event
    *  @param  aEventType    [in] the type of load event, one of:
    *                          nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START,
    *                          nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE,
    *                          nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED
    */
   void ProcessDocLoadEvent(nsIWebProgress *aWebProgress, PRUint32 aEventType);
 
+  friend nsAccessibilityService* GetAccService();
+
+  friend nsresult  NS_GetAccessibilityService(nsIAccessibilityService** aResult);
+
+  
   NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessibilityService, ProcessDocLoadEvent,
                               nsCOMPtr<nsIWebProgress>, PRUint32)
 };
 
 /**
+ * Return the accessibility service instance. (Handy global function)
+ */
+inline nsAccessibilityService*
+GetAccService()
+{
+  return nsAccessibilityService::gAccessibilityService;
+}
+
+/**
  * Map nsIAccessibleRole constants to strings. Used by
  * nsIAccessibleRetrieval::getStringRole() method.
  */
 static const char kRoleNames[][20] = {
   "nothing",             //ROLE_NOTHING
   "titlebar",            //ROLE_TITLEBAR
   "menubar",             //ROLE_MENUBAR
   "scrollbar",           //ROLE_SCROLLBAR 
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -3091,23 +3091,23 @@ nsAccessible::GetSiblingAtOffset(PRInt32
     *aError = NS_ERROR_UNEXPECTED;
 
   return child;
 }
 
 already_AddRefed<nsIAccessible>
 nsAccessible::GetFirstAvailableAccessible(nsIDOMNode *aStartNode)
 {
-  nsIAccessibilityService *accService = GetAccService();
   nsCOMPtr<nsIAccessible> accessible;
   nsCOMPtr<nsIDOMTreeWalker> walker; 
   nsCOMPtr<nsIDOMNode> currentNode(aStartNode);
 
   while (currentNode) {
-    accService->GetAccessibleInWeakShell(currentNode, mWeakShell, getter_AddRefs(accessible)); // AddRef'd
+    GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell,
+                                              getter_AddRefs(accessible));
     if (accessible)
       return accessible.forget();
 
     if (!walker) {
       // Instantiate walker lazily since we won't need it in 90% of the cases
       // where the first DOM node we're given provides an accessible
       nsCOMPtr<nsIDOMDocument> document;
       currentNode->GetOwnerDocument(getter_AddRefs(document));
--- a/accessible/src/base/nsAccessibleTreeWalker.cpp
+++ b/accessible/src/base/nsAccessibleTreeWalker.cpp
@@ -41,21 +41,21 @@
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessNode.h"
 
 #include "nsIAnonymousContentCreator.h"
 #include "nsIServiceManager.h"
 #include "nsIContent.h"
 #include "nsIDOMXULElement.h"
 #include "nsIPresShell.h"
+#include "nsAccessibilityService.h"
 #include "nsWeakReference.h"
 
 nsAccessibleTreeWalker::nsAccessibleTreeWalker(nsIWeakReference* aPresShell, nsIDOMNode* aNode, PRBool aWalkAnonContent): 
-  mWeakShell(aPresShell), 
-  mAccService(do_GetService("@mozilla.org/accessibilityService;1")),
+  mWeakShell(aPresShell),
   mWalkAnonContent(aWalkAnonContent)
 {
   mState.domNode = aNode;
   mState.prevState = nsnull;
   mState.siblingIndex = eSiblingsUninitialized;
   mState.siblingList = nsnull;
   mState.isHidden = false;
 
@@ -289,22 +289,18 @@ nsAccessibleTreeWalker::WalkFrames()
 }
 
 /**
  * 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));
 
-  mAccService->GetAccessible(mState.domNode, presShell, mWeakShell,
-                             mState.frame.GetFrame(), &mState.isHidden,
-                             getter_AddRefs(mState.accessible));
+  GetAccService()->GetAccessible(mState.domNode, presShell, mWeakShell,
+                                 mState.frame.GetFrame(), &mState.isHidden,
+                                 getter_AddRefs(mState.accessible));
 
   return mState.accessible ? PR_TRUE : PR_FALSE;
 }
 
--- a/accessible/src/base/nsAccessibleTreeWalker.h
+++ b/accessible/src/base/nsAccessibleTreeWalker.h
@@ -43,17 +43,16 @@
  * 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;
@@ -127,13 +126,12 @@ protected:
   void WalkFrames();
 
   /**
    * Change current state so that its node is changed to next node.
    */
   void GetNextDOMNode();
 
   nsCOMPtr<nsIWeakReference> mWeakShell;
-  nsCOMPtr<nsIAccessibilityService> mAccService;
   PRBool mWalkAnonContent;
 };
 
 #endif 
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -2108,34 +2108,32 @@ nsDocAccessible::GetAccessibleInParentCh
                                             PRBool aCanCreate,
                                             nsIAccessible **aAccessible)
 {
   // Find accessible in parent chain of DOM nodes, or return null
   *aAccessible = nsnull;
   nsCOMPtr<nsIDOMNode> currentNode(aNode), parentNode;
   nsCOMPtr<nsIAccessNode> accessNode;
 
-  nsIAccessibilityService *accService = GetAccService();
-  NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
-
   do {
     currentNode->GetParentNode(getter_AddRefs(parentNode));
     currentNode = parentNode;
     if (!currentNode) {
       NS_ADDREF_THIS();
       *aAccessible = this;
       break;
     }
 
     nsCOMPtr<nsIDOMNode> relevantNode;
-    if (NS_SUCCEEDED(accService->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
+    if (NS_SUCCEEDED(GetAccService()->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
       currentNode = relevantNode;
     }
     if (aCanCreate) {
-      accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible);
+      GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell, 
+                                                aAccessible);
     }
     else { // Only return cached accessibles, don't create anything
       nsCOMPtr<nsIAccessNode> accessNode;
       GetCachedAccessNode(currentNode, getter_AddRefs(accessNode)); // AddRefs
       if (accessNode) {
         CallQueryInterface(accessNode, aAccessible); // AddRefs
       }
     }
--- a/accessible/src/base/nsRelUtils.cpp
+++ b/accessible/src/base/nsRelUtils.cpp
@@ -84,21 +84,20 @@ nsRelUtils::AddTarget(PRUint32 aRelation
 nsresult
 nsRelUtils::AddTargetFromContent(PRUint32 aRelationType,
                                  nsIAccessibleRelation **aRelation,
                                  nsIContent *aContent)
 {
   if (!aContent)
     return NS_OK_NO_RELATION_TARGET;
 
-  nsCOMPtr<nsIAccessibilityService> accService = nsAccessNode::GetAccService();
   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
 
   nsCOMPtr<nsIAccessible> accessible;
-  accService->GetAccessibleFor(node, getter_AddRefs(accessible));
+  GetAccService()->GetAccessibleFor(node, getter_AddRefs(accessible));
   return AddTarget(aRelationType, aRelation, accessible);
 }
 
 nsresult
 nsRelUtils::AddTargetFromIDRefAttr(PRUint32 aRelationType,
                                    nsIAccessibleRelation **aRelation,
                                    nsIContent *aContent, nsIAtom *aAttr,
                                    PRBool aMayBeAnon)
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -147,24 +147,24 @@ nsTextEquivUtils::AppendTextEquivFromCon
   }
 
   // If the given content is not visible or isn't accessible then go down
   // through the DOM subtree otherwise go down through accessible subtree and
   // calculate the flat string.
   nsIFrame *frame = aContent->GetPrimaryFrame();
   PRBool isVisible = frame && frame->GetStyleVisibility()->IsVisible();
 
-  nsresult rv;
+  nsresult rv = NS_ERROR_FAILURE;
   PRBool goThroughDOMSubtree = PR_TRUE;
 
   if (isVisible) {
     nsCOMPtr<nsIAccessible> accessible;
-    rv = nsAccessNode::GetAccService()->
-      GetAccessibleInShell(DOMNode, shell, getter_AddRefs(accessible));
-    if (NS_SUCCEEDED(rv) && accessible) {
+    GetAccService()->GetAccessibleInShell(DOMNode, shell,
+                                               getter_AddRefs(accessible));
+    if (accessible) {
       rv = AppendFromAccessible(accessible, aString);
       goThroughDOMSubtree = PR_FALSE;
     }
   }
 
   if (goThroughDOMSubtree)
     rv = AppendFromDOMNode(aContent, aString);
 
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -105,50 +105,51 @@ void nsHTMLSelectableAccessible::iterato
 
   if (mOption)
     mOption->GetSelected(&isSelected);
 
   if (isSelected)
     (*aSelectionCount)++;
 }
 
-void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibilityService *aAccService, 
-                                                                   nsIMutableArray *aSelectedAccessibles, 
-                                                                   nsPresContext *aContext)
+void
+nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles, 
+                                                              nsPresContext *aContext)
 {
   PRBool isSelected = PR_FALSE;
   nsCOMPtr<nsIAccessible> tempAccess;
 
   if (mOption) {
     mOption->GetSelected(&isSelected);
     if (isSelected) {
       nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(mOption));
-      aAccService->GetAccessibleInWeakShell(optionNode, mWeakShell, getter_AddRefs(tempAccess));
+      GetAccService()->GetAccessibleInWeakShell(optionNode, mWeakShell,
+                                                getter_AddRefs(tempAccess));
     }
   }
 
   if (tempAccess)
     aSelectedAccessibles->AppendElement(static_cast<nsISupports*>(tempAccess), PR_FALSE);
 }
 
-PRBool nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex, 
-                                                                     nsIAccessibilityService *aAccService, 
-                                                                     nsPresContext *aContext, 
-                                                                     nsIAccessible **aAccessible)
+PRBool
+nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex,
+                                                              nsPresContext *aContext, 
+                                                              nsIAccessible **aAccessible)
 {
   PRBool isSelected = PR_FALSE;
 
   *aAccessible = nsnull;
 
   if (mOption) {
     mOption->GetSelected(&isSelected);
     if (isSelected) {
       if (mSelCount == aIndex) {
         nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(mOption));
-        aAccService->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible);
+        GetAccService()->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible);
         return PR_TRUE;
       }
       mSelCount++;
     }
   }
 
   return PR_FALSE;
 }
@@ -196,57 +197,49 @@ NS_IMETHODIMP nsHTMLSelectableAccessible
   return rv;
 }
 
 // Interface methods
 NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval)
 {
   *_retval = nsnull;
 
-  nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
-  if (!accService)
-    return NS_ERROR_FAILURE;
-
   nsCOMPtr<nsIMutableArray> selectedAccessibles =
     do_CreateInstance(NS_ARRAY_CONTRACTID);
   NS_ENSURE_STATE(selectedAccessibles);
   
   nsPresContext *context = GetPresContext();
   if (!context)
     return NS_ERROR_FAILURE;
 
   nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
   while (iter.Advance())
-    iter.AddAccessibleIfSelected(accService, selectedAccessibles, context);
+    iter.AddAccessibleIfSelected(selectedAccessibles, context);
 
   PRUint32 uLength = 0;
   selectedAccessibles->GetLength(&uLength); 
   if (uLength != 0) { // length of nsIArray containing selected options
     *_retval = selectedAccessibles;
     NS_ADDREF(*_retval);
   }
   return NS_OK;
 }
 
 // return the nth selected child's nsIAccessible object
 NS_IMETHODIMP nsHTMLSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessible **_retval)
 {
   *_retval = nsnull;
 
-  nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
-  if (!accService)
-    return NS_ERROR_FAILURE;
-
   nsPresContext *context = GetPresContext();
   if (!context)
     return NS_ERROR_FAILURE;
 
   nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
   while (iter.Advance())
-    if (iter.GetAccessibleIfSelected(aIndex, accService, context, _retval))
+    if (iter.GetAccessibleIfSelected(aIndex, context, _retval))
       return NS_OK;
   
   // No matched item found
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
 {
@@ -421,27 +414,27 @@ nsHTMLSelectListAccessible::CacheOptSibl
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectOptionAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 /** Default Constructor */
 nsHTMLSelectOptionAccessible::nsHTMLSelectOptionAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
 nsHyperTextAccessibleWrap(aDOMNode, aShell)
 {
-  nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
   nsCOMPtr<nsIDOMNode> parentNode;
   aDOMNode->GetParentNode(getter_AddRefs(parentNode));
   nsCOMPtr<nsIAccessible> parentAccessible;
   if (parentNode) {
     // If the parent node is a Combobox, then the option's accessible parent
     // is nsHTMLComboboxListAccessible, not the nsHTMLComboboxAccessible that
     // GetParent would normally return. This is because the 
     // nsHTMLComboboxListAccessible is inserted into the accessible hierarchy
     // where there is no DOM node for it.
-    accService->GetAccessibleInWeakShell(parentNode, mWeakShell, getter_AddRefs(parentAccessible));
+    GetAccService()->GetAccessibleInWeakShell(parentNode, mWeakShell, 
+                                              getter_AddRefs(parentAccessible));
     if (parentAccessible) {
       if (nsAccUtils::RoleInternal(parentAccessible) ==
           nsIAccessibleRole::ROLE_COMBOBOX) {
         nsCOMPtr<nsIAccessible> comboAccessible(parentAccessible);
         comboAccessible->GetLastChild(getter_AddRefs(parentAccessible));
       }
     }
   }
@@ -834,24 +827,21 @@ nsIContent* nsHTMLSelectOptionAccessible
 {
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   while (content && content->Tag() != nsAccessibilityAtoms::select) {
     content = content->GetParent();
   }
 
   nsCOMPtr<nsIDOMNode> selectNode(do_QueryInterface(content));
   if (selectNode) {
-    nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
-    if (accService) {
-      nsCOMPtr<nsIAccessible> selAcc;
-      accService->GetAccessibleFor(selectNode, getter_AddRefs(selAcc));
-      if (selAcc) {
-        selAcc->GetState(aState, aExtraState);
-        return content;
-      }
+    nsCOMPtr<nsIAccessible> selAcc;
+    GetAccService()->GetAccessibleFor(selectNode, getter_AddRefs(selAcc));
+    if (selAcc) {
+      selAcc->GetState(aState, aExtraState);
+      return content;
     }
   }
   return nsnull; 
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectOptGroupAccessible
 ////////////////////////////////////////////////////////////////////////////////
@@ -1021,24 +1011,23 @@ NS_IMETHODIMP nsHTMLComboboxAccessible::
 already_AddRefed<nsIAccessible>
 nsHTMLComboboxAccessible::GetFocusedOptionAccessible()
 {
   if (!mWeakShell) {
     return nsnull;  // Shut down
   }
   nsCOMPtr<nsIDOMNode> focusedOptionNode;
   nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mDOMNode, getter_AddRefs(focusedOptionNode));
-  nsIAccessibilityService *accService = GetAccService();
-  if (!focusedOptionNode || !accService) {
+  if (!focusedOptionNode) {
     return nsnull;
   }
 
   nsIAccessible *optionAccessible;
-  accService->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell, 
-                                       &optionAccessible);
+  GetAccService()->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell, 
+                                            &optionAccessible);
   return optionAccessible;
 }
 
 /**
   * MSAA/ATK accessible value != HTML value, especially not in combo boxes.
   * Our accessible value is the text label for of our ( first ) selected child.
   * The easiest way to get this is from the first child which is the readonly textfield.
   */
--- a/accessible/src/html/nsHTMLSelectAccessible.h
+++ b/accessible/src/html/nsHTMLSelectAccessible.h
@@ -40,17 +40,16 @@
 #define __nsHTMLSelectAccessible_h__
 
 #include "nsIAccessibleSelectable.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsHTMLFormControlAccessible.h"
 #include "nsIDOMHTMLOptionsCollection.h"
 #include "nsIDOMHTMLOptionElement.h"
 #include "nsIDOMNode.h"
-#include "nsIAccessibilityService.h"
 #include "nsAccessibleTreeWalker.h"
 
 class nsIMutableArray;
 
 /**
   *  Selects, Listboxes and Comboboxes, are made up of a number of different
   *  widgets, some of which are shared between the two. This file contains
 	*  all of the widgets for both of the Selects, for HTML only.
@@ -99,20 +98,20 @@ protected:
     nsCOMPtr<nsIWeakReference> mWeakShell;
     nsHTMLSelectableAccessible *mParentSelect;
 
   public:
     iterator(nsHTMLSelectableAccessible *aParent, nsIWeakReference *aWeakShell);
 
     void CalcSelectionCount(PRInt32 *aSelectionCount);
     void Select(PRBool aSelect);
-    void AddAccessibleIfSelected(nsIAccessibilityService *aAccService, 
-                                 nsIMutableArray *aSelectedAccessibles, 
+    void AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles, 
                                  nsPresContext *aContext);
-    PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsIAccessibilityService *aAccService, nsPresContext *aContext, nsIAccessible **_retval);
+    PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsPresContext *aContext,
+                                   nsIAccessible **aAccessible);
 
     PRBool Advance();
   };
 
   friend class iterator;
 };
 
 /*
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -34,17 +34,16 @@
  * 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 "nsAccessNodeWrap.h"
 #include "ISimpleDOMNode_i.c"
 #include "nsAccessibilityAtoms.h"
-#include "nsIAccessibilityService.h"
 #include "nsIAccessible.h"
 #include "nsAttrName.h"
 #include "nsIDocument.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMViewCSS.h"
 #include "nsIFrame.h"
@@ -406,23 +405,20 @@ ISimpleDOMNode* nsAccessNodeWrap::MakeAc
     // Get the document via QueryInterface, since there is no content node
     doc = do_QueryInterface(node);
     content = do_QueryInterface(node);
   }
 
   if (!doc)
     return NULL;
 
-  nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
-  if (!accService)
-    return NULL;
-
   ISimpleDOMNode *iNode = NULL;
   nsCOMPtr<nsIAccessible> nsAcc;
-  accService->GetAccessibleInWeakShell(node, mWeakShell, getter_AddRefs(nsAcc));
+  GetAccService()->GetAccessibleInWeakShell(node, mWeakShell, 
+                                            getter_AddRefs(nsAcc));
   if (nsAcc) {
     nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(nsAcc));
     NS_ASSERTION(accessNode, "nsIAccessible impl does not inherit from nsIAccessNode");
     IAccessible *msaaAccessible;
     nsAcc->GetNativeInterface((void**)&msaaAccessible); // addrefs
     msaaAccessible->QueryInterface(IID_ISimpleDOMNode, (void**)&iNode); // addrefs
     msaaAccessible->Release(); // Release IAccessible
   }
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -120,17 +120,16 @@ nsXFormsAccessible::CacheSelectChildren(
     return;
 
   PRUint32 length = 0;
   children->GetLength(&length);
 
   nsCOMPtr<nsIAccessible> accessible;
   nsRefPtr<nsAccessible> acc;
 
-  PRUint32 childLength = 0;
   for (PRUint32 index = 0; index < length; index++) {
     nsCOMPtr<nsIDOMNode> child;
     children->Item(index, getter_AddRefs(child));
     if (!child)
       continue;
 
     accService->GetAttachedAccessibleFor(child, getter_AddRefs(accessible));
     if (!accessible)
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -115,47 +115,44 @@ nsresult nsXULSelectableAccessible::Chan
 // Interface methods
 NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildren)
 {
   *aChildren = nsnull;
   if (!mSelectControl) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
-  NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
-
   nsCOMPtr<nsIMutableArray> selectedAccessibles =
     do_CreateInstance(NS_ARRAY_CONTRACTID);
   NS_ENSURE_STATE(selectedAccessibles);
 
   // For XUL multi-select control
   nsCOMPtr<nsIDOMXULMultiSelectControlElement> xulMultiSelect =
     do_QueryInterface(mSelectControl);
   nsCOMPtr<nsIAccessible> selectedAccessible;
   if (xulMultiSelect) {
     PRInt32 length = 0;
     xulMultiSelect->GetSelectedCount(&length);
     for (PRInt32 index = 0; index < length; index++) {
       nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
       xulMultiSelect->GetSelectedItem(index, getter_AddRefs(selectedItem));
       nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
-      accService->GetAccessibleInWeakShell(selectedNode, mWeakShell,
-                                           getter_AddRefs(selectedAccessible));
+      GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell,
+                                            getter_AddRefs(selectedAccessible));
       if (selectedAccessible)
         selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
     }
   }
   else {  // Single select?
     nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
     mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
     nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
     if(selectedNode) {
-      accService->GetAccessibleInWeakShell(selectedNode, mWeakShell,
-                                           getter_AddRefs(selectedAccessible));
+      GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell,
+                                            getter_AddRefs(selectedAccessible));
       if (selectedAccessible)
         selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
     }
   }
 
   PRUint32 uLength = 0;
   selectedAccessibles->GetLength(&uLength);
   if (uLength != 0) { // length of nsIArray containing selected options
@@ -178,23 +175,21 @@ NS_IMETHODIMP nsXULSelectableAccessible:
     do_QueryInterface(mSelectControl);
   if (xulMultiSelect)
     xulMultiSelect->GetSelectedItem(aIndex, getter_AddRefs(selectedItem));
 
   if (aIndex == 0)
     mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
 
   if (selectedItem) {
-    nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
-    if (accService) {
-      accService->GetAccessibleInWeakShell(selectedItem, mWeakShell, aAccessible);
-      if (*aAccessible) {
-        NS_ADDREF(*aAccessible);
-        return NS_OK;
-      }
+    GetAccService()->GetAccessibleInWeakShell(selectedItem, mWeakShell,
+                                              aAccessible);
+    if (*aAccessible) {
+      NS_ADDREF(*aAccessible);
+      return NS_OK;
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsXULSelectableAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
 {
@@ -349,18 +344,18 @@ nsXULMenuitemAccessible::GetStateInterna
         nsAccessible* grandParentAcc = parentAcc->GetParent();
         NS_ENSURE_TRUE(grandParentAcc, NS_ERROR_FAILURE);
         NS_ASSERTION(nsAccUtils::Role(grandParentAcc) == nsIAccessibleRole::ROLE_COMBOBOX,
                      "grandparent of combobox listitem is not combobox");
         PRUint32 grandParentState, grandParentExtState;
         grandParentAcc->GetState(&grandParentState, &grandParentExtState);
         *aState &= ~(nsIAccessibleStates::STATE_OFFSCREEN |
                      nsIAccessibleStates::STATE_INVISIBLE);
-        *aState |= grandParentState & nsIAccessibleStates::STATE_OFFSCREEN |
-                   grandParentState & nsIAccessibleStates::STATE_INVISIBLE;
+        *aState |= (grandParentState & nsIAccessibleStates::STATE_OFFSCREEN) |
+                   (grandParentState & nsIAccessibleStates::STATE_INVISIBLE);
         if (aExtraState) {
           *aExtraState |=
             grandParentExtState & nsIAccessibleStates::EXT_STATE_OPAQUE;
         }
       } // isCollapsed
     } // isSelected
   } // ROLE_COMBOBOX_OPTION
 
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -35,14 +35,18 @@
 .tabs-container[overflow="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
   visibility: collapse;
 }
 
 .tabs-newtab-button > .toolbarbutton-text {
   display: none;
 }
 
+tabpanels {
+  background-color: white;
+}
+
 %ifdef MOZ_WIDGET_GTK2
 /* Favicons override the "images-in-menus" metric in xul.css */
 .alltabs-item > .menu-iconic-left {
   visibility: inherit;
 }
 %endif
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -1329,17 +1329,25 @@ SessionStoreService.prototype = {
           scriptableStream.readByteArray(scriptableStream.available());
         // We can stop doing base64 encoding once our serialization into JSON
         // is guaranteed to handle all chars in strings, including embedded
         // nulls.
         entry.owner_b64 = btoa(String.fromCharCode.apply(null, ownerBytes));
       }
       catch (ex) { debug(ex); }
     }
-    
+
+    if (aEntry.docIdentifier) {
+      entry.docIdentifier = aEntry.docIdentifier;
+    }
+
+    if (aEntry.stateData) {
+      entry.stateData = aEntry.stateData;
+    }
+
     if (!(aEntry instanceof Ci.nsISHContainer)) {
       return entry;
     }
     
     if (aEntry.childCount > 0) {
       entry.children = [];
       for (var i = 0; i < aEntry.childCount; i++) {
         var child = aEntry.GetChildAt(i);
@@ -2033,33 +2041,36 @@ SessionStoreService.prototype = {
 
     if (!this._isWindowLoaded(aWindow)) {
       // from now on, the data will come from the actual window
       delete this._statesToRestore[aWindow.__SS_restoreID];
       delete aWindow.__SS_restoreID;
       delete this._windows[aWindow.__SSi]._restoring;
     }
     
-    // helper hash for ensuring unique frame IDs
+    // helper hashes for ensuring unique frame IDs and unique document
+    // identifiers.
     var idMap = { used: {} };
-    this.restoreHistory(aWindow, aTabs, aTabData, idMap);
+    var docIdentMap = {};
+    this.restoreHistory(aWindow, aTabs, aTabData, idMap, docIdentMap);
   },
 
   /**
    * Restory history for a window
    * @param aWindow
    *        Window reference
    * @param aTabs
    *        Array of tab references
    * @param aTabData
    *        Array of tab data
    * @param aIdMap
    *        Hash for ensuring unique frame IDs
    */
-  restoreHistory: function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap) {
+  restoreHistory:
+    function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap) {
     var _this = this;
     while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) {
       aTabs.shift(); // this tab got removed before being completely restored
       aTabData.shift();
     }
     if (aTabs.length == 0) {
       return; // no more tabs to restore
     }
@@ -2085,17 +2096,18 @@ SessionStoreService.prototype = {
     }
     else
       delete tab.__SS_extdata;
     
     for (var i = 0; i < tabData.entries.length; i++) {
       //XXXzpao Wallpaper patch for bug 514751
       if (!tabData.entries[i].url)
         continue;
-      history.addEntry(this._deserializeHistoryEntry(tabData.entries[i], aIdMap), true);
+      history.addEntry(this._deserializeHistoryEntry(tabData.entries[i],
+                                                     aIdMap, aDocIdentMap), true);
     }
     
     // make sure to reset the capabilities and attributes, in case this tab gets reused
     var disallow = (tabData.disallow)?tabData.disallow.split(","):[];
     CAPABILITIES.forEach(function(aCapability) {
       browser.docShell["allow" + aCapability] = disallow.indexOf(aCapability) == -1;
     });
     Array.filter(tab.attributes, function(aAttr) {
@@ -2147,28 +2159,32 @@ SessionStoreService.prototype = {
     // 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);
+    aWindow.setTimeout(function(){
+      _this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap);
+    }, 0);
   },
 
   /**
    * expands serialized history data into a session-history-entry instance
    * @param aEntry
    *        Object containing serialized history data for a URL
    * @param aIdMap
    *        Hash for ensuring unique frame IDs
    * @returns nsISHEntry
    */
-  _deserializeHistoryEntry: function sss_deserializeHistoryEntry(aEntry, aIdMap) {
+  _deserializeHistoryEntry:
+    function sss_deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
+
     var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
                   createInstance(Ci.nsISHEntry);
 
     shEntry.setURI(IOSvc.newURI(aEntry.url, null, null));
     shEntry.setTitle(aEntry.title || aEntry.url);
     if (aEntry.subframe)
       shEntry.setIsSubFrame(aEntry.subframe || false);
     shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
@@ -2190,17 +2206,21 @@ SessionStoreService.prototype = {
       var id = aIdMap[aEntry.ID] || 0;
       if (!id) {
         for (id = Date.now(); id in aIdMap.used; id++);
         aIdMap[aEntry.ID] = id;
         aIdMap.used[id] = true;
       }
       shEntry.ID = id;
     }
-    
+
+    if (aEntry.stateData) {
+      shEntry.stateData = aEntry.stateData;
+    }
+
     if (aEntry.scroll) {
       var scrollPos = (aEntry.scroll || "0,0").split(",");
       scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
       shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
     }
 
     var postdata;
     if (aEntry.postdata_b64) {  // Firefox 3
@@ -2211,16 +2231,38 @@ SessionStoreService.prototype = {
 
     if (postdata) {
       var stream = Cc["@mozilla.org/io/string-input-stream;1"].
                    createInstance(Ci.nsIStringInputStream);
       stream.setData(postdata, postdata.length);
       shEntry.postData = stream;
     }
 
+    if (aEntry.docIdentifier) {
+      // Get a new document identifier for this entry to ensure that history
+      // entries after a session restore are considered to have different
+      // documents from the history entries before the session restore.
+      // Document identifiers are 64-bit ints, so JS will loose precision and
+      // start assigning all entries the same doc identifier if these ever get
+      // large enough.
+      //
+      // It's a potential security issue if document identifiers aren't
+      // globally unique, but shEntry.setUniqueDocIdentifier() below guarantees
+      // that we won't re-use a doc identifier within a given instance of the
+      // application.
+      let ident = aDocIdentMap[aEntry.docIdentifier];
+      if (!ident) {
+        shEntry.setUniqueDocIdentifier();
+        aDocIdentMap[aEntry.docIdentifier] = shEntry.docIdentifier;
+      }
+      else {
+        shEntry.docIdentifier = ident;
+      }
+    }
+
     if (aEntry.owner_b64) {  // Firefox 3
       var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
                        createInstance(Ci.nsIStringInputStream);
       var binaryData = atob(aEntry.owner_b64);
       ownerInput.setData(binaryData, binaryData.length);
       var binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
                          createInstance(Ci.nsIObjectInputStream);
       binaryStream.setInputStream(ownerInput);
@@ -2232,17 +2274,18 @@ SessionStoreService.prototype = {
       shEntry.owner = SecuritySvc.getCodebasePrincipal(uriObj);
     }
     
     if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
       for (var i = 0; i < aEntry.children.length; i++) {
         //XXXzpao Wallpaper patch for bug 514751
         if (!aEntry.children[i].url)
           continue;
-        shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap), i);
+        shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap,
+                                                       aDocIdentMap), i);
       }
     }
     
     return shEntry;
   },
 
   /**
    * restores all sessionStorage "super cookies"
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -103,16 +103,17 @@ include $(topsrcdir)/config/rules.mk
 	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_500328.js \
 	browser_506482.js \
 	browser_514751.js \
 	browser_522545.js \
 	browser_524745.js \
 	browser_528776.js \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_500328.js
@@ -0,0 +1,135 @@
+/* ***** 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
+ *  Justin Lebar <justin.lebar@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function checkState(tab) {
+  // Go back and then forward, and make sure that the state objects received
+  // from the popState event are as we expect them to be.
+  //
+  // We also add a node to the document's body when after going back and make
+  // sure it's still there after we go forward -- this is to test that the two
+  // history entries correspond to the same document.
+
+  let popStateCount = 0;
+
+  tab.linkedBrowser.addEventListener("popstate", function(aEvent) {
+    let contentWindow = tab.linkedBrowser.contentWindow;
+    if (popStateCount == 0) {
+      popStateCount++;
+      ok(aEvent.state, "Event should have a state property.");
+      is(JSON.stringify(aEvent.state), JSON.stringify({obj1:1}),
+         "first popstate object.");
+
+      // Add a node with id "new-elem" to the document.
+      let doc = contentWindow.document;
+      ok(!doc.getElementById("new-elem"),
+         "doc shouldn't contain new-elem before we add it.");
+      let elem = doc.createElement("div");
+      elem.id = "new-elem";
+      doc.body.appendChild(elem);
+
+      contentWindow.history.forward();
+    }
+    else if (popStateCount == 1) {
+      popStateCount++;
+      is(JSON.stringify(aEvent.state), JSON.stringify({obj3:3}),
+         "second popstate object.");
+
+      // Make sure that the new-elem node is present in the document.  If it's
+      // not, then this history entry has a different doc identifier than the
+      // previous entry, which is bad.
+      let doc = contentWindow.document;
+      let newElem = doc.getElementById("new-elem");
+      ok(newElem, "doc should contain new-elem.");
+      newElem.parentNode.removeChild(newElem);
+      ok(!doc.getElementById("new-elem"), "new-elem should be removed.");
+
+      // Clean up after ourselves and finish the test.
+      tab.linkedBrowser.removeEventListener("popstate", arguments.callee, false);
+      gBrowser.removeTab(tab);
+      finish();
+    }
+  }, true);
+
+  tab.linkedBrowser.contentWindow.history.back();
+}
+
+function test() {
+  // Tests session restore functionality of history.pushState and
+  // history.replaceState().  (Bug 500328)
+
+  let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+  waitForExplicitFinish();
+
+  // We open a new blank window, let it load, and then load in
+  // http://example.com.  We need to load the blank window first, otherwise the
+  // docshell gets confused and doesn't have a current history entry.
+  let tab = gBrowser.addTab("about:blank");
+  let tabBrowser = tab.linkedBrowser;
+
+  tabBrowser.addEventListener("load", function(aEvent) {
+    tabBrowser.removeEventListener("load", arguments.callee, true);
+
+    tabBrowser.loadURI("http://example.com", null, null);
+
+    tabBrowser.addEventListener("load", function(aEvent) {
+      tabBrowser.removeEventListener("load", arguments.callee, true);
+
+      // After these push/replaceState calls, the window should have three
+      // history entries:
+      //   testURL (state object: null)      <-- oldest
+      //   testURL (state object: {obj1:1})
+      //   page2   (state object: {obj3:3})  <-- newest
+      let contentWindow = tab.linkedBrowser.contentWindow;
+      let history = contentWindow.history;
+      history.pushState({obj1:1}, "title-obj1");
+      history.pushState({obj2:2}, "title-obj2", "page2");
+      history.replaceState({obj3:3}, "title-obj3");
+
+      let state = ss.getTabState(tab);
+
+      // In order to make sure that setWindowState actually modifies the
+      // window's state, we modify the state here.  checkState will fail if
+      // this change isn't overwritten by setWindowState.
+      history.replaceState({should_be_overwritten:true}, "title-overwritten");
+
+      // Restore the state and make sure it looks right, after giving the event
+      // loop a chance to flush.
+      ss.setTabState(tab, state, true);
+      executeSoon(function() { checkState(tab); });
+
+    }, true);
+  }, true);
+}
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1106,21 +1106,16 @@ statusbarpanel#statusbar-display {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
 }
 
 #navigator-throbber,
 #wrapper-navigator-throbber > #navigator-throbber {
   list-style-image: url("chrome://global/skin/icons/notloading_16.png");
 }
 
-
-tabpanels {
-  -moz-appearance: none;
-}
-
 /* Tabs */
 .tabbrowser-tab {
   border: none !important;
   padding: 0px;
   margin-bottom: 1px;
 }
 
 .tabbrowser-tab[selected="true"] {
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -394,32 +394,30 @@ menubutton:not([disabled="true"]):hover:
 
 #back-button {
   -moz-image-region: rect(0px, 36px, 23px, 0px);
 }
 #back-button[disabled="true"] {
   -moz-image-region: rect(23px, 36px, 46px, 0px);
 }
 #back-button:hover:active:not([disabled]),
-#back-button[buttondown="true"]:not([disabled]),
 #back-button[open="true"] {
   -moz-image-region: rect(46px, 36px, 69px, 0px);
 }
 
 /* ----- DEFAULT FORWARD BUTTON, STAND-ALONE ----- */	
 
 #forward-button {
   -moz-image-region: rect(0px, 72px, 23px, 36px);
 }
 
 #forward-button[disabled="true"] {
   -moz-image-region: rect(23px, 72px, 46px, 36px);
 }
 #forward-button:hover:active:not([disabled]),
-#forward-button[buttondown="true"]:not([disabled]),
 #forward-button[open="true"] {
   -moz-image-region: rect(46px, 72px, 69px, 36px);
 }
 
 /* ----- DEFAULT BACK/FORWARD BUTTONS ----- */
 
 toolbar[mode="icons"] #unified-back-forward-button > #back-button {
   -moz-image-region: rect(0px, 535px, 33px, 504px);
@@ -1586,20 +1584,16 @@ tabbrowser > tabbox {
   display: -moz-box;
   width: 3px;
 }
 
 .tabbrowser-tabs[overflow="true"] .tabs-left {
   display: none;
 }
 
-tabbrowser > tabbox > tabpanels {
-  -moz-appearance: none !important;
-}
-
 /**
  * Tab Drag and Drop
  */
 
 .tab-drop-indicator-bar {
   height: 10px;
   margin-top: -10px;
   position: relative;
@@ -1777,20 +1771,16 @@ tabbrowser > tabbox > tabpanels {
   list-style-image: url("chrome://global/skin/icons/closetab.png");
   border: none;
 }
 
 .tabs-closebutton:hover:active {
   list-style-image: url("chrome://global/skin/icons/closetab-active.png");
 }
 
-tabpanels.plain {
-	background-color: #fff !important;
-}
-
 /* Bookmarks toolbar */
 .toolbar-drop-indicator {
   list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
 }
 
 /* Bookmark drag and drop styles */
 
 .bookmark-item[dragover-into="true"] {
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1172,20 +1172,16 @@ statusbarpanel#statusbar-display {
 .tabs-bottom {
   height: 4px;
   margin: 0px;
   background: -moz-dialog url("chrome://browser/skin/tabbrowser/tabstrip-bottom.png") repeat;
   border-top: 1px solid threedshadow;
   border-bottom: 1px solid threedshadow;
 }
 
-tabpanels {
-  -moz-appearance: none;
-}
-
 /* tabbrowser-tab focus ring */
 .tabbrowser-tab > .tab-text {
   border: 1px dotted transparent;
 }
 
 .tabbrowser-tab:focus > .tab-text {
   border: 1px dotted -moz-DialogText;
 }
--- a/caps/idl/nsIScriptSecurityManager.idl
+++ b/caps/idl/nsIScriptSecurityManager.idl
@@ -36,38 +36,30 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "nsIPrincipal.idl"
 #include "nsIXPCSecurityManager.idl"
 interface nsIURI;
 interface nsIChannel;
 
-[scriptable, uuid(c0dbfd5e-b7ae-4c18-8674-82492f35d715)]
+[scriptable, uuid(50eda256-4dd2-4c7c-baed-96983910af9f)]
 interface nsIScriptSecurityManager : nsIXPCSecurityManager
 {
     ///////////////// Security Checks //////////////////
     /**
      * Checks whether the running script is allowed to access aProperty.
      */
     [noscript] void checkPropertyAccess(in JSContextPtr aJSContext,
                                         in JSObjectPtr aJSObject,
                                         in string aClassName,
                                         in JSVal aProperty,
                                         in PRUint32 aAction);
 
     /**
-     * Checks whether the running script is allowed to connect to aTargetURI
-     */
-    [noscript] void checkConnect(in JSContextPtr aJSContext,
-                                 in nsIURI aTargetURI,
-                                 in string aClassName,
-                                 in string aProperty);
-
-    /**
      * Check that the script currently running in context "cx" can load "uri".
      *
      * Will return error code NS_ERROR_DOM_BAD_URI if the load request 
      * should be denied.
      *
      * @param cx the JSContext of the script causing the load
      * @param uri the URI that is being loaded
      */
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -405,18 +405,17 @@ public:
     static PRUint32 SecurityHashURI(nsIURI* aURI);
 
     static nsresult 
     ReportError(JSContext* cx, const nsAString& messageTag,
                 nsIURI* aSource, nsIURI* aTarget);
 
     static nsresult
     CheckSameOriginPrincipal(nsIPrincipal* aSubject,
-                             nsIPrincipal* aObject,
-                             PRBool aIsCheckConnect);
+                             nsIPrincipal* aObject);
     static PRUint32
     HashPrincipalByOrigin(nsIPrincipal* aPrincipal);
 
     static PRBool
     GetStrictFileOriginPolicy()
     {
         return sStrictFileOriginPolicy;
     }
@@ -453,18 +452,17 @@ private:
                             nsISupports* aObj, nsIURI* aTargetURI,
                             nsIClassInfo* aClassInfo,
                             const char* aClassName, jsval aProperty,
                             void** aCachedClassPolicy);
 
     nsresult
     CheckSameOriginDOMProp(nsIPrincipal* aSubject, 
                            nsIPrincipal* aObject,
-                           PRUint32 aAction,
-                           PRBool aIsCheckConnect);
+                           PRUint32 aAction);
 
     nsresult
     LookupPolicy(nsIPrincipal* principal,
                  ClassInfoData& aClassData, jsval aProperty,
                  PRUint32 aAction,
                  ClassPolicy** aCachedClassPolicy,
                  SecurityLevel* result);
 
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -358,18 +358,17 @@ nsPrincipal::Equals(nsIPrincipal *aOther
       }
 
       // Fall through to the codebase comparison.
     }
 
     // Codebases are equal if they have the same origin.
     *aResult =
       NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this,
-                                                                     aOther,
-                                                                     PR_FALSE));
+                                                                     aOther));
     return NS_OK;
   }
 
   *aResult = PR_TRUE;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -559,44 +559,16 @@ nsScriptSecurityManager::CheckPropertyAc
                                              PRUint32 aAction)
 {
     return CheckPropertyAccessImpl(aAction, nsnull, cx, aJSObject,
                                    nsnull, nsnull, nsnull,
                                    aClassName, aProperty, nsnull);
 }
 
 NS_IMETHODIMP
-nsScriptSecurityManager::CheckConnect(JSContext* cx,
-                                      nsIURI* aTargetURI,
-                                      const char* aClassName,
-                                      const char* aPropertyName)
-{
-    // Get a context if necessary
-    if (!cx)
-    {
-        cx = GetCurrentJSContext();
-        if (!cx)
-            return NS_OK; // No JS context, so allow the load
-    }
-
-    nsresult rv = CheckLoadURIFromScript(cx, aTargetURI);
-    if (NS_FAILED(rv)) return rv;
-
-    JSAutoRequest ar(cx);
-
-    JSString* propertyName = ::JS_InternString(cx, aPropertyName);
-    if (!propertyName)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    return CheckPropertyAccessImpl(nsIXPCSecurityManager::ACCESS_CALL_METHOD, nsnull,
-                                   cx, nsnull, nsnull, aTargetURI,
-                                   nsnull, aClassName, STRING_TO_JSVAL(propertyName), nsnull);
-}
-
-NS_IMETHODIMP
 nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
                                          nsIURI* aTargetURI)
 {
     nsresult rv;
 
     // Get a context if necessary
     if (!cx)
     {
@@ -745,17 +717,17 @@ nsScriptSecurityManager::CheckPropertyAc
                 }
                 else
                 {
                     NS_ERROR("CheckPropertyAccessImpl called without a target object or URL");
                     return NS_ERROR_FAILURE;
                 }
                 if(NS_SUCCEEDED(rv))
                     rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
-                                                aAction, aTargetURI != nsnull);
+                                                aAction);
                 break;
             }
         default:
 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
                 printf("ERROR ");
 #endif
             NS_ERROR("Bad Security Level Value");
             return NS_ERROR_FAILURE;
@@ -938,83 +910,65 @@ nsScriptSecurityManager::CheckPropertyAc
     }
 
     return rv;
 }
 
 /* static */
 nsresult
 nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
-                                                  nsIPrincipal* aObject,
-                                                  PRBool aIsCheckConnect)
+                                                  nsIPrincipal* aObject)
 {
     /*
     ** Get origin of subject and object and compare.
     */
     if (aSubject == aObject)
         return NS_OK;
 
-    // These booleans are only used when !aIsCheckConnect.  Default
-    // them to false, and change if that turns out wrong.
+    // Default to false, and change if that turns out wrong.
     PRBool subjectSetDomain = PR_FALSE;
     PRBool objectSetDomain = PR_FALSE;
     
     nsCOMPtr<nsIURI> subjectURI;
     nsCOMPtr<nsIURI> objectURI;
 
-    if (aIsCheckConnect)
-    {
-        // Don't use domain for CheckConnect calls, since that's called for
-        // data-only load checks like XMLHTTPRequest (bug 290100).
+    aSubject->GetDomain(getter_AddRefs(subjectURI));
+    if (!subjectURI) {
         aSubject->GetURI(getter_AddRefs(subjectURI));
-        aObject->GetURI(getter_AddRefs(objectURI));
+    } else {
+        subjectSetDomain = PR_TRUE;
     }
-    else
-    {
-        aSubject->GetDomain(getter_AddRefs(subjectURI));
-        if (!subjectURI) {
-            aSubject->GetURI(getter_AddRefs(subjectURI));
-        } else {
-            subjectSetDomain = PR_TRUE;
-        }
-
-        aObject->GetDomain(getter_AddRefs(objectURI));
-        if (!objectURI) {
-            aObject->GetURI(getter_AddRefs(objectURI));
-        } else {
-            objectSetDomain = PR_TRUE;
-        }
+
+    aObject->GetDomain(getter_AddRefs(objectURI));
+    if (!objectURI) {
+        aObject->GetURI(getter_AddRefs(objectURI));
+    } else {
+        objectSetDomain = PR_TRUE;
     }
 
     if (SecurityCompareURIs(subjectURI, objectURI))
     {   // If either the subject or the object has changed its principal by
         // explicitly setting document.domain then the other must also have
         // done so in order to be considered the same origin. This prevents
         // DNS spoofing based on document.domain (154930)
 
-        // But this restriction does not apply to CheckConnect calls, since
-        // that's called for data-only load checks like XMLHTTPRequest where
-        // we ignore domain (bug 290100).
-        if (aIsCheckConnect)
-            return NS_OK;
-
         // If both or neither explicitly set their domain, allow the access
         if (subjectSetDomain == objectSetDomain)
             return NS_OK;
     }
 
     /*
     ** Access tests failed, so now report error.
     */
     return NS_ERROR_DOM_PROP_ACCESS_DENIED;
 }
 
 // It's important that
 //
-//   CheckSameOriginPrincipal(A, B, PR_FALSE) == NS_OK
+//   CheckSameOriginPrincipal(A, B) == NS_OK
 //
 // imply
 //
 //   HashPrincipalByOrigin(A) == HashPrincipalByOrigin(B)
 //
 // if principals A and B could ever be used as keys in a hashtable.
 // Violation of this invariant leads to spurious failures of hashtable
 // lookups.  See bug 454850.
@@ -1027,31 +981,23 @@ nsScriptSecurityManager::HashPrincipalBy
     if (!uri)
         aPrincipal->GetURI(getter_AddRefs(uri));
     return SecurityHashURI(uri);
 }
 
 nsresult
 nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
                                                 nsIPrincipal* aObject,
-                                                PRUint32 aAction,
-                                                PRBool aIsCheckConnect)
+                                                PRUint32 aAction)
 {
     nsresult rv;
-    if (aIsCheckConnect) {
-        // Don't do equality compares, just do a same-origin compare,
-        // since the object principal isn't a real principal, just a
-        // GetCodebasePrincipal() on whatever URI we started with.
-        rv = CheckSameOriginPrincipal(aSubject, aObject, aIsCheckConnect);
-    } else {
-        PRBool subsumes;
-        rv = aSubject->Subsumes(aObject, &subsumes);
-        if (NS_SUCCEEDED(rv) && !subsumes) {
-            rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
-        }
+    PRBool subsumes;
+    rv = aSubject->Subsumes(aObject, &subsumes);
+    if (NS_SUCCEEDED(rv) && !subsumes) {
+        rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
     }
     
     if (NS_SUCCEEDED(rv))
         return NS_OK;
 
     /*
     * Content can't ever touch chrome (we check for UniversalXPConnect later)
     */
--- a/content/base/public/nsIDOMFile.idl
+++ b/content/base/public/nsIDOMFile.idl
@@ -34,23 +34,24 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIDOMFileError;
 
-[scriptable, uuid(0845E8AE-56BD-4F0E-962A-3B3E92638A0B)]
+[scriptable, uuid(16753172-6890-4e6a-8c10-a7ff30c5ef22)]
 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 DOMString mozFullPath;
   readonly attribute unsigned long long size;
   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/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -101,18 +101,18 @@ class nsBindingManager;
 class nsIDOMNodeList;
 class mozAutoSubtreeModified;
 struct JSObject;
 class nsFrameLoader;
 class nsIBoxObject;
 
 // IID for the nsIDocument interface
 #define NS_IDOCUMENT_IID      \
-  { 0xb04d9176, 0xf087, 0x4d3c, \
-    { 0x87, 0x11, 0x13, 0x9d, 0x19, 0x95, 0x43, 0x55 } }
+{ 0x6b2f1996, 0x95d4, 0x48db, \
+  {0xaf, 0xd1, 0xfd, 0xaa, 0x75, 0x4c, 0x79, 0x92 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 //----------------------------------------------------------------------
 
 // Document interface.  This is implemented by all document objects in
 // Gecko.
@@ -1221,16 +1221,38 @@ public:
     Doc_Theme_Uninitialized, // not determined yet
     Doc_Theme_None,
     Doc_Theme_Neutral,
     Doc_Theme_Dark,
     Doc_Theme_Bright
   };
 
   /**
+   * Returns the document's pending state object (serialized to JSON), or the
+   * empty string if one doesn't exist.
+   *
+   * This field serves as a waiting place for the history entry's state object:
+   * We set the field's value to the history entry's state object early on in
+   * the load, then after we fire onload we deserialize the field's value and
+   * fire a popstate event containing the resulting object.
+   */
+  nsAString& GetPendingStateObject()
+  {
+    return mPendingStateObject;
+  }
+
+  /**
+   * Set the document's pending state object (as serialized to JSON).
+   */
+  void SetPendingStateObject(nsAString &obj)
+  {
+    mPendingStateObject.Assign(obj);
+  }
+
+  /**
    * 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; }
 
   /**
@@ -1383,16 +1405,18 @@ protected:
   PRUint32            mSubtreeModifiedDepth;
 
   // If we're an external resource document, this will be non-null and will
   // point to our "display document": the one that all resource lookups should
   // go to.
   nsCOMPtr<nsIDocument> mDisplayDocument;
 
   PRUint32 mEventsSuppressed;
+
+  nsString mPendingStateObject;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
 /**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -402,16 +402,17 @@ nsContentUtils::InitializeEventTable() {
     { &nsGkAtoms::onblur,                        { NS_BLUR_CONTENT, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onoffline,                     { NS_OFFLINE, EventNameType_HTMLXUL }},
     { &nsGkAtoms::ononline,                      { NS_ONLINE, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onsubmit,                      { NS_FORM_SUBMIT, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onreset,                       { NS_FORM_RESET, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onchange,                      { NS_FORM_CHANGE, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onselect,                      { NS_FORM_SELECTED, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onload,                        { NS_LOAD, EventNameType_All }},
+    { &nsGkAtoms::onpopstate,                    { NS_POPSTATE, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onunload,                      { NS_PAGE_UNLOAD,
                                                  (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
     { &nsGkAtoms::onhashchange,                  { NS_HASHCHANGE, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onbeforeunload,                { NS_BEFORE_PAGE_UNLOAD, EventNameType_HTMLXUL }},
     { &nsGkAtoms::onabort,                       { NS_IMAGE_ABORT,
                                                  (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
     { &nsGkAtoms::onerror,                       { NS_LOAD_ERROR,
                                                  (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -104,16 +104,26 @@ nsDOMFile::GetFileSize(PRUint64 *aFileSi
 
 NS_IMETHODIMP
 nsDOMFile::GetName(nsAString &aFileName)
 {
   return mFile->GetLeafName(aFileName);
 }
 
 NS_IMETHODIMP
+nsDOMFile::GetMozFullPath(nsAString &aFileName)
+{
+  if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
+    return mFile->GetPath(aFileName);
+  }
+  aFileName.Truncate();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMFile::GetSize(PRUint64 *aFileSize)
 {
   PRInt64 fileSize;
   nsresult rv = mFile->GetFileSize(&fileSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (fileSize < 0) {
     return NS_ERROR_FAILURE;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -41,16 +41,21 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * Base class for all our document implementations.
  */
 
+#ifdef MOZ_LOGGING
+// so we can get logging even in release builds
+#define FORCE_PR_LOG 1
+#endif
+#include "prlog.h"
 #include "plstr.h"
 #include "prprf.h"
 
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsDocument.h"
 #include "nsUnicharUtils.h"
 #include "nsIPrivateDOMEvent.h"
@@ -179,23 +184,16 @@ static NS_DEFINE_CID(kDOMEventGroupCID, 
 #include "nsSMILAnimationController.h"
 #include "imgIContainer.h"
 #include "nsSVGUtils.h"
 #endif // MOZ_SMIL
 
 // FOR CSP (autogenerated by xpidl)
 #include "nsIContentSecurityPolicy.h"
 
-
-#ifdef MOZ_LOGGING
-// so we can get logging even in release builds
-#define FORCE_PR_LOG 1
-#endif
-#include "prlog.h"
-
 /* Keeps track of whether or not CSP is enabled */
 static PRBool gCSPEnabled = PR_TRUE;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gDocumentLeakPRLog;
 static PRLogModuleInfo* gCspPRLog;
 #endif
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -645,16 +645,17 @@ GK_ATOM(onfocus, "onfocus")
 GK_ATOM(onget, "onget")
 GK_ATOM(onhashchange, "onhashchange")
 GK_ATOM(oninput, "oninput")
 GK_ATOM(onkeydown, "onkeydown")
 GK_ATOM(onkeypress, "onkeypress")
 GK_ATOM(onkeyup, "onkeyup")
 GK_ATOM(onLoad, "onLoad")
 GK_ATOM(onload, "onload")
+GK_ATOM(onpopstate, "onpopstate")
 GK_ATOM(only, "only")               // this one is not an event
 GK_ATOM(onmousedown, "onmousedown")
 GK_ATOM(onmousemove, "onmousemove")
 GK_ATOM(onmouseout, "onmouseout")
 GK_ATOM(onmouseover, "onmouseover")
 GK_ATOM(onmouseup, "onmouseup")
 GK_ATOM(onMozAfterPaint, "onMozAfterPaint")
 GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -2397,19 +2397,23 @@ WebGLContext::ValidateGL()
         LogMessage("GL_MAX_VERTEX_ATTRIBS is 0!");
         return PR_FALSE;
     }
 
     mAttribBuffers.SetLength(val);
 
     //fprintf(stderr, "GL_MAX_VERTEX_ATTRIBS: %d\n", val);
 
-    gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_UNITS, &val);
+    // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
+    // even though the hardware supports much more.  The
+    // GL_MAX_{COMBINED_}TEXTURE_IMAGE_UNITS value is the accurate
+    // value.  For GLES2, GL_MAX_TEXTURE_UNITS is still correc.t
+    gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &val);
     if (val == 0) {
-        LogMessage("GL_MAX_TEXTURE_UNITS is 0!");
+        LogMessage("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is 0!");
         return PR_FALSE;
     }
 
     mBound2DTextures.SetLength(val);
     mBoundCubeMapTextures.SetLength(val);
 
     //fprintf(stderr, "GL_MAX_TEXTURE_UNITS: %d\n", val);
 
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -77,16 +77,17 @@ CPPSRCS		= \
 		nsEventListenerService.cpp \
 		nsDOMProgressEvent.cpp \
 		nsDOMDataTransfer.cpp \
 		nsDOMNotifyPaintEvent.cpp \
 		nsDOMSimpleGestureEvent.cpp \
 		nsDOMEventTargetHelper.cpp \
 		nsDOMScrollAreaEvent.cpp \
 		nsDOMTransitionEvent.cpp \
+		nsDOMPopStateEvent.cpp \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -54,22 +54,23 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "prmem.h"
 #include "nsGkAtoms.h"
 #include "nsMutationEvent.h"
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
+#include "nsDOMPopStateEvent.h"
 
 static const char* const sEventNames[] = {
   "mousedown", "mouseup", "click", "dblclick", "mouseover",
   "mouseout", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
-  "focus", "blur", "load", "beforeunload", "unload", "hashchange", "abort", "error",
-  "submit", "reset", "change", "select", "input" ,"text",
+  "focus", "blur", "load", "popstate", "beforeunload", "unload", "hashchange",
+  "abort", "error", "submit", "reset", "change", "select", "input", "text",
   "compositionstart", "compositionend", "popupshowing", "popupshown",
   "popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate",
   "dragenter", "dragover", "dragexit", "dragdrop", "draggesture",
   "drag", "dragend", "dragstart", "dragleave", "drop", "resize",
   "scroll", "overflow", "underflow", "overflowchanged",
   "DOMSubtreeModified", "DOMNodeInserted", "DOMNodeRemoved", 
   "DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument",
   "DOMAttrModified", "DOMCharacterDataModified",
@@ -1323,16 +1324,18 @@ const char* nsDOMEvent::GetEventName(PRU
   case NS_FOCUS_CONTENT:
     return sEventNames[eDOMEvents_focus];
   case NS_BLUR_CONTENT:
     return sEventNames[eDOMEvents_blur];
   case NS_XUL_CLOSE:
     return sEventNames[eDOMEvents_close];
   case NS_LOAD:
     return sEventNames[eDOMEvents_load];
+  case NS_POPSTATE:
+    return sEventNames[eDOMEvents_popstate];
   case NS_BEFORE_PAGE_UNLOAD:
     return sEventNames[eDOMEvents_beforeunload];
   case NS_PAGE_UNLOAD:
     return sEventNames[eDOMEvents_unload];
   case NS_HASHCHANGE:
     return sEventNames[eDOMEvents_hashchange];
   case NS_IMAGE_ABORT:
     return sEventNames[eDOMEvents_abort];
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -53,32 +53,33 @@
 class nsIContent;
  
 class nsDOMEvent : public nsIDOMEvent,
                    public nsIDOMNSEvent,
                    public nsIPrivateDOMEvent
 {
 public:
 
-  // Note: this enum must be kept in sync with mEventNames in nsDOMEvent.cpp
+  // Note: this enum must be kept in sync with sEventNames in nsDOMEvent.cpp
   enum nsDOMEvents {
     eDOMEvents_mousedown=0,
     eDOMEvents_mouseup,
     eDOMEvents_click,
     eDOMEvents_dblclick,
     eDOMEvents_mouseover,
     eDOMEvents_mouseout,
     eDOMEvents_mousemove,
     eDOMEvents_contextmenu,
     eDOMEvents_keydown,
     eDOMEvents_keyup,
     eDOMEvents_keypress,
     eDOMEvents_focus,
     eDOMEvents_blur,
     eDOMEvents_load,
+    eDOMEvents_popstate,
     eDOMEvents_beforeunload,
     eDOMEvents_unload,
     eDOMEvents_hashchange,
     eDOMEvents_abort,
     eDOMEvents_error,
     eDOMEvents_submit,
     eDOMEvents_reset,
     eDOMEvents_change,
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMPopStateEvent.cpp
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * 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 ***** */
+
+#include "nsDOMPopStateEvent.h"
+#include "nsCycleCollectionParticipant.h"
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMPopStateEvent)
+
+NS_IMPL_ADDREF_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mState)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mState)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMPopStateEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMPopStateEvent)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(PopStateEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+nsDOMPopStateEvent::~nsDOMPopStateEvent()
+{
+}
+
+NS_IMETHODIMP
+nsDOMPopStateEvent::GetState(nsIVariant **aState)
+{
+  NS_PRECONDITION(aState, "null state arg");
+  NS_IF_ADDREF(*aState = mState);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMPopStateEvent::InitPopStateEvent(const nsAString &aTypeArg,
+                                      PRBool aCanBubbleArg,
+                                      PRBool aCancelableArg,
+                                      nsIVariant *aStateArg)
+{
+  nsresult rv = nsDOMEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mState = aStateArg;
+  return NS_OK;
+}
+
+nsresult NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult,
+                                nsPresContext* aPresContext,
+                                nsEvent* aEvent)
+{
+  nsDOMPopStateEvent* event =
+    new nsDOMPopStateEvent(aPresContext, aEvent);
+
+  if (!event) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return CallQueryInterface(event, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMPopStateEvent.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * 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 ***** */
+
+#ifndef nsDOMPopStateEvent_h__
+#define nsDOMPopStateEvent_h__
+
+class nsEvent;
+
+#include "nsIDOMPopStateEvent.h"
+#include "nsDOMEvent.h"
+#include "nsIVariant.h"
+#include "nsCycleCollectionParticipant.h"
+
+class nsDOMPopStateEvent : public nsDOMEvent,
+                           public nsIDOMPopStateEvent
+{
+public:
+  nsDOMPopStateEvent(nsPresContext* aPresContext, nsEvent* aEvent)
+    : nsDOMEvent(aPresContext, aEvent)  // state
+  {
+  }
+
+  virtual ~nsDOMPopStateEvent();
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
+
+  NS_DECL_NSIDOMPOPSTATEEVENT
+
+  NS_FORWARD_TO_NSDOMEVENT
+
+protected:
+  nsCOMPtr<nsIVariant> mState;
+};
+
+nsresult NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult,
+                                nsPresContext* aPresContext,
+                                nsEvent* aEvent);
+
+#endif // nsDOMPopStateEvent_h__
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -43,16 +43,17 @@
 #include "nsEventListenerManager.h"
 #include "nsContentUtils.h"
 #include "nsDOMError.h"
 #include "nsMutationEvent.h"
 #include NEW_H
 #include "nsFixedSizeAllocator.h"
 #include "nsINode.h"
 #include "nsPIDOMWindow.h"
+#include "nsDOMPopStateEvent.h"
 
 #define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH  (1 << 0)
 #define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
 #define NS_TARGET_CHAIN_MAY_HAVE_MANAGER        (1 << 2)
 
 // nsEventTargetChainItem represents a single item in the event target chain.
 class nsEventTargetChainItem
 {
@@ -791,11 +792,13 @@ nsEventDispatcher::CreateEvent(nsPresCon
   if (aEventType.LowerCaseEqualsLiteral("pagetransition"))
     return NS_NewDOMPageTransitionEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("scrollareaevent"))
     return NS_NewDOMScrollAreaEvent(aDOMEvent, aPresContext, nsnull);
   // FIXME: Should get spec to say what the right string is here!  This
   // is probably wrong!
   if (aEventType.LowerCaseEqualsLiteral("transitionevent"))
     return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext, nsnull);
+  if (aEventType.LowerCaseEqualsLiteral("popstateevent"))
+    return NS_NewDOMPopStateEvent(aDOMEvent, aPresContext, nsnull);
 
   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 }
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -687,19 +687,40 @@ nsHTMLDocument::StartDocumentLoad(const 
       (!aCommand || nsCRT::strcmp(aCommand, "view-source") != 0)) {
     // We're parsing XHTML as XML, remember that.
 
     mIsRegularHTML = PR_FALSE;
     mCompatMode = eCompatibility_FullStandards;
     loadAsHtml5 = PR_FALSE;
   }
   
-  if (!(contentType.EqualsLiteral("text/html") && aCommand && !nsCRT::strcmp(aCommand, "view"))) {
+  if (loadAsHtml5 && 
+      !(contentType.EqualsLiteral("text/html") && 
+        aCommand && 
+        !nsCRT::strcmp(aCommand, "view"))) {
     loadAsHtml5 = PR_FALSE;
   }
+  
+  // TODO: Proper about:blank treatment is bug 543435
+  if (loadAsHtml5) {
+    // mDocumentURI hasn't been set, yet, so get the URI from the channel
+    nsCOMPtr<nsIURI> uri;
+    aChannel->GetOriginalURI(getter_AddRefs(uri));
+    // Adapted from nsDocShell:
+    // GetSpec can be expensive for some URIs, so check the scheme first.
+    PRBool isAbout = PR_FALSE;
+    if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
+      nsCAutoString str;
+      uri->GetSpec(str);
+      if (str.EqualsLiteral("about:blank")) {
+        loadAsHtml5 = PR_FALSE;    
+      }
+    }
+  }
+  
 #ifdef DEBUG
   else {
     NS_ASSERTION(mIsRegularHTML,
                  "Hey, someone forgot to reset mIsRegularHTML!!!");
   }
 #endif
 
   CSSLoader()->SetCompatibilityMode(mCompatMode);
--- a/content/smil/SMILBoolType.h
+++ b/content/smil/SMILBoolType.h
@@ -39,30 +39,37 @@
 
 #include "nsISMILType.h"
 
 namespace mozilla {
 
 class SMILBoolType : public nsISMILType
 {
 public:
+  // Singleton for nsSMILValue objects to hold onto.
+  static SMILBoolType sSingleton;
+
+protected:
+  // nsISMILType Methods
+  // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
                                nsSMILValue& aResult) const;
 
-  static SMILBoolType sSingleton;
-
 private:
-  SMILBoolType() {}
+  // Private constructor & destructor: prevent instances beyond my singleton,
+  // and prevent others from deleting my singleton.
+  SMILBoolType()  {}
+  ~SMILBoolType() {}
 };
 
 } // namespace mozilla
 
 #endif // MOZILLA_SMILBOOLTYPE_H_
--- a/content/smil/SMILEnumType.h
+++ b/content/smil/SMILEnumType.h
@@ -39,30 +39,37 @@
 
 #include "nsISMILType.h"
 
 namespace mozilla {
 
 class SMILEnumType : public nsISMILType
 {
 public:
+  // Singleton for nsSMILValue objects to hold onto.
+  static SMILEnumType sSingleton;
+
+protected:
+  // nsISMILType Methods
+  // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
                                nsSMILValue& aResult) const;
 
-  static SMILEnumType sSingleton;
-
 private:
-  SMILEnumType() {}
+  // Private constructor & destructor: prevent instances beyond my singleton,
+  // and prevent others from deleting my singleton.
+  SMILEnumType()  {}
+  ~SMILEnumType() {}
 };
 
 } // namespace mozilla
 
 #endif // MOZILLA_SMILENUMTYPE_H_
--- a/content/smil/nsISMILType.h
+++ b/content/smil/nsISMILType.h
@@ -70,17 +70,22 @@ class nsSMILValue;
 // | -- SandwichAdd?     |     -         |    -?       |    X             |
 // | -- ComputeDistance? |     -         |    -        |    X?            |
 // | -- Interpolate?     |     -         |    X        |    X             |
 // +---------------------+---------------+-------------+------------------+
 //
 
 class nsISMILType
 {
-public:
+  /**
+   * Only give the nsSMILValue class access to this interface.
+   */
+  friend class nsSMILValue;
+
+protected:
   /**
    * Initialises aValue and sets it to some identity value such that adding
    * aValue to another value of the same type has no effect.
    *
    * @pre (aValue.mType == this && aValue.mU is valid)
    *      || aValue.mType == null-type
    * @post aValue.mType == this || NS_FAILED(rv)
    */
@@ -206,16 +211,17 @@ public:
    *
    * @pre aStartVal.mType == aEndVal.mType == aResult.mType == this
    */
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
                                nsSMILValue& aResult) const = 0;
 
-  /*
-   * Virtual destructor: Nothing to do here, but subclasses
-   * may need it.
+  /**
+   * Protected destructor, to ensure that no one accidentally deletes an
+   * instance of this class.
+   * (The only instances in existence should be singletons - one per subclass.)
    */
-  virtual ~nsISMILType() {};
+  ~nsISMILType() {}
 };
 
 #endif // NS_ISMILTYPE_H_
--- a/content/smil/nsSMILCSSProperty.cpp
+++ b/content/smil/nsSMILCSSProperty.cpp
@@ -41,23 +41,26 @@
 #include "nsSMILCSSValueType.h"
 #include "nsSMILValue.h"
 #include "nsCSSDeclaration.h"
 #include "nsComputedDOMStyle.h"
 #include "nsStyleAnimation.h"
 #include "nsIContent.h"
 #include "nsIDOMElement.h"
 
+// Helper function
 static PRBool
 GetCSSComputedValue(nsIContent* aElem,
                     nsCSSProperty aPropID,
                     nsAString& aResult)
 {
-  NS_ENSURE_TRUE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
-                 PR_FALSE);
+  NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aPropID),
+                    "Can't look up computed value of shorthand property");
+  NS_ABORT_IF_FALSE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
+                    "Shouldn't get here for non-animatable properties");
 
   nsIDocument* doc = aElem->GetCurrentDoc();
   if (!doc) {
     // This can happen if we process certain types of restyles mid-sample
     // and remove anonymous animated content from the document as a result.
     // See bug 534975.
     return PR_FALSE;
   }
@@ -68,18 +71,17 @@ GetCSSComputedValue(nsIContent* aElem,
     return PR_FALSE;
   }
 
   nsRefPtr<nsComputedDOMStyle> computedStyle;
   nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(aElem));
   nsresult rv = NS_NewComputedDOMStyle(domElement, EmptyString(), shell,
                                        getter_AddRefs(computedStyle));
 
-  if (NS_SUCCEEDED(rv) && computedStyle) {
-    // NOTE: This will produce an empty string for shorthand values
+  if (NS_SUCCEEDED(rv)) {
     computedStyle->GetPropertyValue(aPropID, aResult);
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
 // Class Methods
 nsSMILCSSProperty::nsSMILCSSProperty(nsCSSProperty aPropID,
@@ -89,16 +91,30 @@ nsSMILCSSProperty::nsSMILCSSProperty(nsC
   NS_ABORT_IF_FALSE(IsPropertyAnimatable(mPropID),
                     "Creating a nsSMILCSSProperty for a property "
                     "that's not supported for animation");
 }
 
 nsSMILValue
 nsSMILCSSProperty::GetBaseValue() const
 {
+  // SPECIAL CASE: Shorthands
+  if (nsCSSProps::IsShorthand(mPropID)) {
+    // We can't look up the base (computed-style) value of shorthand
+    // properties, because they aren't guaranteed to have a consistent computed
+    // value.  However, that's not a problem, because it turns out the caller
+    // isn't going to end up using the value we return anyway. Base values only
+    // get used when there's interpolation or addition, and the shorthand
+    // properties we know about don't support those operations. So, we can just
+    // return a dummy value (initialized with the right type, so as not to
+    // indicate failure).
+    return nsSMILValue(&nsSMILCSSValueType::sSingleton);
+  }
+
+  // GENERAL CASE: Non-Shorthands  
   // (1) Put empty string in override style for property mPropID
   // (saving old override style value, so we can set it again when we're done)
   nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
   mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
   nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);
   nsAutoString cachedOverrideStyleVal;
   if (overrideDecl) {
     overrideDecl->GetPropertyValue(mPropID, cachedOverrideStyleVal);
@@ -113,79 +129,64 @@ nsSMILCSSProperty::GetBaseValue() const
   PRBool didGetComputedVal = GetCSSComputedValue(mElement, mPropID,
                                                  computedStyleVal);
 
   // (3) Put cached override style back (if it's non-empty)
   if (overrideDecl && !cachedOverrideStyleVal.IsEmpty()) {
     overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal);
   }
 
+  // (4) Create a nsSMILValue from the computed style
   nsSMILValue baseValue;
   if (didGetComputedVal) {
-    // (4) Create the nsSMILValue from the computed style value
-    nsSMILCSSValueType::sSingleton.Init(baseValue);
-    if (!nsCSSProps::IsShorthand(mPropID) &&
-        !nsSMILCSSValueType::sSingleton.ValueFromString(mPropID, mElement,
-                                                        computedStyleVal,
-                                                        baseValue)) {
-      nsSMILCSSValueType::sSingleton.Destroy(baseValue);
-      NS_ABORT_IF_FALSE(baseValue.IsNull(),
-                        "Destroy should leave us with null-typed value");
-    }
+    nsSMILCSSValueType::ValueFromString(mPropID, mElement,
+                                        computedStyleVal, baseValue);
   }
   return baseValue;
 }
 
 nsresult
 nsSMILCSSProperty::ValueFromString(const nsAString& aStr,
                                    const nsISMILAnimationElement* aSrcElement,
                                    nsSMILValue& aValue) const
 {
   NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
-  nsSMILCSSValueType::sSingleton.Init(aValue);
-  PRBool success =
-    nsSMILCSSValueType::sSingleton.ValueFromString(mPropID, mElement,
-                                                   aStr, aValue);
-  if (!success) {
-    nsSMILCSSValueType::sSingleton.Destroy(aValue);
-  }
-  return success ? NS_OK : NS_ERROR_FAILURE;
+
+  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
+  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
 }
 
 nsresult
 nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue)
 {
   NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
 
-  nsresult rv = NS_OK;
+  // Convert nsSMILValue to string
   nsAutoString valStr;
-
-  if (nsSMILCSSValueType::sSingleton.ValueToString(aValue, valStr)) {
-    // Apply the style to the target element
-    nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
-    mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
-    NS_ABORT_IF_FALSE(overrideStyle, "Need a non-null overrideStyle");
-
-    nsCOMPtr<nsICSSDeclaration> overrideDecl =
-      do_QueryInterface(overrideStyle);
-    if (overrideDecl) {
-      overrideDecl->SetPropertyValue(mPropID, valStr);
-    }
-  } else {
+  if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) {
     NS_WARNING("Failed to convert nsSMILValue for CSS property into a string");
-    rv = NS_ERROR_FAILURE;
+    return NS_ERROR_FAILURE;
   }
 
-  return rv;
+  // Use string value to style the target element
+  nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
+  mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
+  NS_ABORT_IF_FALSE(overrideStyle, "Need a non-null overrideStyle");
+
+  nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);
+  if (overrideDecl) {
+    overrideDecl->SetPropertyValue(mPropID, valStr);
+  }
+  return NS_OK;
 }
 
 void
 nsSMILCSSProperty::ClearAnimValue()
 {
-  // Put empty string in override style for property propID
+  // Put empty string in override style for our property
   nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
   mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
   nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);
   if (overrideDecl) {
     overrideDecl->SetPropertyValue(mPropID, EmptyString());
   }
 }
 
--- a/content/smil/nsSMILCSSValueType.cpp
+++ b/content/smil/nsSMILCSSValueType.cpp
@@ -298,66 +298,86 @@ GetPresContextForElement(nsIContent* aEl
     // and remove anonymous animated content from the document as a result.
     // See bug 534975.
     return nsnull;
   }
   nsIPresShell* shell = doc->GetPrimaryShell();
   return shell ? shell->GetPresContext() : nsnull;
 }
 
-PRBool
-nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
-                                    nsIContent* aTargetElement,
-                                    const nsAString& aString,
-                                    nsSMILValue& aValue) const
+// Helper function to parse a string into a nsStyleAnimation::Value
+static PRBool
+ValueFromStringHelper(nsCSSProperty aPropID,
+                      nsIContent* aTargetElement,
+                      nsPresContext* aPresContext,
+                      const nsAString& aString,
+                      nsStyleAnimation::Value& aStyleAnimValue)
 {
-  NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton,
-                    "Passed-in value is wrong type");
-  NS_ABORT_IF_FALSE(!aValue.mU.mPtr, "expecting barely-initialized outparam");
-
-  nsPresContext* presContext = GetPresContextForElement(aTargetElement);
-  if (!presContext) {
-    NS_WARNING("Not parsing animation value; unable to get PresContext");
-    return PR_FALSE;
-  }
-
   // If value is negative, we'll strip off the "-" so the CSS parser won't
-  // barf, and then manually make the parsed value negative. (This is a partial
-  // solution to let us accept some otherwise out-of-bounds CSS values -- bug
-  // 501188 will provide a more complete fix.)
+  // barf, and then manually make the parsed value negative.
+  // (This is a partial solution to let us accept some otherwise out-of-bounds
+  // CSS values. Bug 501188 will provide a more complete fix.)
   PRBool isNegative = PR_FALSE;
   PRUint32 subStringBegin = 0;
   PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
   if (absValuePos > 0) {
-    subStringBegin = (PRUint32)absValuePos;
     isNegative = PR_TRUE;
+    subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign
   }
   nsDependentSubstring subString(aString, subStringBegin);
-  nsStyleAnimation::Value parsedValue;
-  if (nsStyleAnimation::ComputeValue(aPropID, aTargetElement,
-                                     subString, parsedValue)) {
-    if (isNegative) {
-      InvertSign(parsedValue);
-    }
-    if (aPropID == eCSSProperty_font_size) {
-      // Divide out text-zoom, since SVG is supposed to ignore it
-      NS_ABORT_IF_FALSE(parsedValue.GetUnit() == nsStyleAnimation::eUnit_Coord,
-                        "'font-size' value with unexpected style unit");
-      parsedValue.SetCoordValue(parsedValue.GetCoordValue() /
-                                presContext->TextZoom());
-    }
-    aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
-    return aValue.mU.mPtr != nsnull;
+  if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement,
+                                      subString, aStyleAnimValue)) {
+    return PR_FALSE;
+  }
+  if (isNegative) {
+    InvertSign(aStyleAnimValue);
   }
-  return PR_FALSE;
+  
+  if (aPropID == eCSSProperty_font_size) {
+    // Divide out text-zoom, since SVG is supposed to ignore it
+    NS_ABORT_IF_FALSE(aStyleAnimValue.GetUnit() ==
+                        nsStyleAnimation::eUnit_Coord,
+                      "'font-size' value with unexpected style unit");
+    aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
+                                  aPresContext->TextZoom());
+  }
+  return PR_TRUE;
 }
 
+// static
+void
+nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
+                                    nsIContent* aTargetElement,
+                                    const nsAString& aString,
+                                    nsSMILValue& aValue)
+{
+  NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
+  nsPresContext* presContext = GetPresContextForElement(aTargetElement);
+  if (!presContext) {
+    NS_WARNING("Not parsing animation value; unable to get PresContext");
+    return;
+  }
+
+  nsStyleAnimation::Value parsedValue;
+  if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
+                            aString, parsedValue)) {
+    sSingleton.Init(aValue);
+    aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
+    if (!aValue.mU.mPtr) {
+      // Out of memory! Destroy outparam, to leave it as nsSMILNullType,
+      // which indicates to our caller that we failed.
+      sSingleton.Destroy(aValue);
+    }
+  }
+}
+
+// static
 PRBool
 nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
-                                  nsAString& aString) const
+                                  nsAString& aString)
 {
   NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton,
-                    "Passed-in value is wrong type");
+                    "Unexpected SMIL value type");
   const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
   return !wrapper ||
     nsStyleAnimation::UncomputeValue(wrapper->mPropID, wrapper->mPresContext,
                                      wrapper->mCSSValue, aString);
 }
--- a/content/smil/nsSMILCSSValueType.h
+++ b/content/smil/nsSMILCSSValueType.h
@@ -49,66 +49,75 @@ class nsIContent;
 class nsAString;
 
 /*
  * nsSMILCSSValueType: Represents a SMIL-animated CSS value.
  */
 class nsSMILCSSValueType : public nsISMILType
 {
 public:
-  // nsISMILValueType Methods
-  // ------------------------
+  // Singleton for nsSMILValue objects to hold onto.
+  static nsSMILCSSValueType sSingleton;
+
+protected:
+  // nsISMILType Methods
+  // -------------------
   NS_OVERRIDE virtual nsresult Init(nsSMILValue& aValue) const;
   NS_OVERRIDE virtual void     Destroy(nsSMILValue&) const;
   NS_OVERRIDE virtual nsresult Assign(nsSMILValue& aDest,
                                       const nsSMILValue& aSrc) const;
   NS_OVERRIDE virtual nsresult Add(nsSMILValue& aDest,
                                    const nsSMILValue& aValueToAdd,
                                    PRUint32 aCount) const;
   NS_OVERRIDE virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                                const nsSMILValue& aTo,
                                                double& aDistance) const;
   NS_OVERRIDE virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                            const nsSMILValue& aEndVal,
                                            double aUnitDistance,
                                            nsSMILValue& aResult) const;
 
+public:
+  // Helper Methods
+  // --------------
   /**
    * Sets up the given nsSMILValue to represent the given string value.  The
    * string is interpreted as a value for the given property on the given
    * element.
    *
-   * Note: aValue is expected to be freshly initialized (i.e. it should already
-   * have been passed into nsSMILCSSValueType::Init(), and it should not have
-   * been set up further via e.g. Assign() or another ValueFromString() call.)
+   * On failure, this method leaves aValue.mType == nsSMILNullType::sSingleton.
+   * Otherwise, this method leaves aValue.mType == this class's singleton.
    *
    * @param       aPropID         The property for which we're parsing a value.
    * @param       aTargetElement  The target element to whom the property/value
    *                              setting applies.
    * @param       aString         The string to be parsed as a CSS value.
-   * @param [out] aValue          The nsSMILValue to be populated.
-   * @return                      PR_TRUE on success, PR_FALSE on failure.
+   * @param [out] aValue          The nsSMILValue to be populated. Should
+   *                              initially be null-typed.
+   * @pre  aValue.IsNull()
+   * @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton
    */
-  PRBool ValueFromString(nsCSSProperty aPropID, nsIContent* aTargetElement,
-                         const nsAString& aString, nsSMILValue& aValue) const;
+  static void ValueFromString(nsCSSProperty aPropID,
+                              nsIContent* aTargetElement,
+                              const nsAString& aString, nsSMILValue& aValue);
 
   /**
    * Creates a string representation of the given nsSMILValue.
    *
    * Note: aValue is expected to be of this type (that is, it's expected to
    * have been initialized by nsSMILCSSValueType::sSingleton).  If aValue is a
    * freshly-initialized value, this method will succeed, though the resulting
    * string will be empty.
    *
    * @param       aValue   The nsSMILValue to be converted into a string.
    * @param [out] aString  The string to be populated with the given value.
    * @return               PR_TRUE on success, PR_FALSE on failure.
    */
-  PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString) const;
-
-  // Singleton for nsSMILValue objects to hold onto.
-  static nsSMILCSSValueType sSingleton;
+  static PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString);
 
 private:
-  nsSMILCSSValueType() {}
+  // Private constructor & destructor: prevent instances beyond my singleton,
+  // and prevent others from deleting my singleton.
+  nsSMILCSSValueType()  {}
+  ~nsSMILCSSValueType() {}
 };
 
 #endif // NS_SMILCSSVALUETYPE_H_
--- a/content/smil/nsSMILFloatType.h
+++ b/content/smil/nsSMILFloatType.h
@@ -39,28 +39,35 @@
 #ifndef NS_SMILFLOATTYPE_H_
 #define NS_SMILFLOATTYPE_H_
 
 #include "nsISMILType.h"
 
 class nsSMILFloatType : public nsISMILType
 {
 public:
+  // Singleton for nsSMILValue objects to hold onto.
+  static nsSMILFloatType sSingleton;
+
+protected:
+  // nsISMILType Methods
+  // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
                                nsSMILValue& aResult) const;
 
-  static nsSMILFloatType sSingleton;
-
 private:
-  nsSMILFloatType() {}
+  // Private constructor & destructor: prevent instances beyond my singleton,
+  // and prevent others from deleting my singleton.
+  nsSMILFloatType()  {}
+  ~nsSMILFloatType() {}
 };
 
 #endif // NS_SMILFLOATTYPE_H_
--- a/content/smil/nsSMILNullType.h
+++ b/content/smil/nsSMILNullType.h
@@ -39,28 +39,38 @@
 #ifndef NS_SMILNULLTYPE_H_
 #define NS_SMILNULLTYPE_H_
 
 #include "nsISMILType.h"
 
 class nsSMILNullType : public nsISMILType
 {
 public:
+  // Singleton for nsSMILValue objects to hold onto.
+  static nsSMILNullType sSingleton;
+
+protected:
+  // nsISMILType Methods
+  // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const { return NS_OK; }
   virtual void Destroy(nsSMILValue& aValue) const {}
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
 
   // The remaining methods should never be called, so although they're very
   // simple they don't need to be inline.
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
                                nsSMILValue& aResult) const;
 
-  static nsSMILNullType sSingleton;
+private:
+  // Private constructor & destructor: prevent instances beyond my singleton,
+  // and prevent others from deleting my singleton.
+  nsSMILNullType()  {}
+  ~nsSMILNullType() {}
 };
 
 #endif // NS_SMILNULLTYPE_H_
--- a/content/svg/content/src/nsSVGTransformSMILAttr.cpp
+++ b/content/svg/content/src/nsSVGTransformSMILAttr.cpp
@@ -45,68 +45,51 @@
 #include "nsSVGMatrix.h"
 #include "nsSMILValue.h"
 #include "nsSMILNullType.h"
 #include "nsISMILAnimationElement.h"
 #include "nsSVGElement.h"
 #include "nsISVGValue.h"
 #include "prdtoa.h"
 
-nsISMILType*
-nsSVGTransformSMILAttr::GetSMILType() const
-{
-  return &nsSVGTransformSMILType::sSingleton;
-}
-
 nsresult
 nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
                                      const nsISMILAnimationElement* aSrcElement,
                                      nsSMILValue& aValue) const
 {
   NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
   NS_ASSERTION(aValue.IsNull(),
     "aValue should have been cleared before calling ValueFromString");
 
-  nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
-  if (val.IsNull())
-    return NS_ERROR_FAILURE;
-
   const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
-
   const nsIAtom* transformType = typeAttr
                                ? typeAttr->GetAtomValue()
                                : nsGkAtoms::translate;
 
-  nsresult rv = ParseValue(aStr, transformType, val);
-  if (NS_FAILED(rv))
-    return rv;
-
-  aValue = val;
-
-  return NS_OK;
+  ParseValue(aStr, transformType, aValue);
+  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
 }
 
 nsSMILValue
 nsSVGTransformSMILAttr::GetBaseValue() const
 {
-  nsSVGTransformSMILType *type = &nsSVGTransformSMILType::sSingleton;
-  nsSMILValue val(type);
+  nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
   if (val.IsNull())
-    return val;
+    return val; // Initialization failed
 
   nsIDOMSVGTransformList *list = mVal->mBaseVal.get();
 
   PRUint32 numItems = 0;
   list->GetNumberOfItems(&numItems);
   for (PRUint32 i = 0; i < numItems; i++) {
     nsCOMPtr<nsIDOMSVGTransform> transform;
     nsresult rv = list->GetItem(i, getter_AddRefs(transform));
     if (NS_SUCCEEDED(rv) && transform) {
       rv = AppendSVGTransformToSMILValue(transform.get(), val);
-      NS_ENSURE_SUCCESS(rv,nsSMILValue());
+      NS_ENSURE_SUCCESS(rv, nsSMILValue());
     }
   }
 
   return val;
 }
 
 void
 nsSVGTransformSMILAttr::ClearAnimValue()
@@ -144,88 +127,87 @@ nsSVGTransformSMILAttr::SetAnimValue(con
 
   mVal->DidModify(nsISVGValue::mod_other);
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // Implementation helpers
 
-nsresult
+void
 nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
                                    const nsIAtom* aTransformType,
-                                   nsSMILValue& aResult) const
+                                   nsSMILValue& aResult)
 {
-  nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton;
-  NS_ASSERTION(
-      type == static_cast<nsSVGTransformSMILType const *>(aResult.mType),
-      "Unexpected type for SMIL value result");
-
-  // Reset the result so we can just append to it
-  nsresult rv = type->Init(aResult);
-  NS_ENSURE_SUCCESS(rv,rv);
+  NS_ASSERTION(aResult.IsNull(), "Unexpected type for SMIL value");
 
   float params[3] = { 0.f };
   PRInt32 numParsed = ParseParameterList(aSpec, params, 3);
   nsSVGSMILTransform::TransformType transformType;
 
   if (aTransformType == nsGkAtoms::translate) {
     // tx [ty=0]
     if (numParsed != 1 && numParsed != 2)
-      return NS_ERROR_FAILURE;
+      return;
     transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
   } else if (aTransformType == nsGkAtoms::scale) {
     // sx [sy=sx]
     if (numParsed != 1 && numParsed != 2)
-      return NS_ERROR_FAILURE;
+      return;
     if (numParsed == 1) {
       params[1] = params[0];
     }
     transformType = nsSVGSMILTransform::TRANSFORM_SCALE;
   } else if (aTransformType == nsGkAtoms::rotate) {
     // r [cx=0 cy=0]
     if (numParsed != 1 && numParsed != 3)
-      return NS_ERROR_FAILURE;
+      return;
     transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
   } else if (aTransformType == nsGkAtoms::skewX) {
     // x-angle
     if (numParsed != 1)
-      return NS_ERROR_FAILURE;
+      return;
     transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
   } else if (aTransformType == nsGkAtoms::skewY) {
     // y-angle
     if (numParsed != 1)
-      return NS_ERROR_FAILURE;
+      return;
     transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
   } else {
-    return NS_ERROR_FAILURE;
+    return;
   }
 
-  return type->AppendTransform(nsSVGSMILTransform(transformType, params),
-                               aResult);
+  nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
+  nsSVGSMILTransform transform(transformType, params);
+  if (NS_FAILED(nsSVGTransformSMILType::AppendTransform(transform, val))) {
+    return;
+  }
+
+  // Success! Initialize our outparam with parsed value.
+  aResult = val;
 }
 
 inline PRBool
-nsSVGTransformSMILAttr::IsSpace(const char c) const
+IsSpace(const char c)
 {
   return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20);
 }
 
 inline void
-nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter,
-                               const nsACString::const_iterator& aIterEnd) const
+SkipWsp(nsACString::const_iterator& aIter,
+        const nsACString::const_iterator& aIterEnd)
 {
   while (aIter != aIterEnd && IsSpace(*aIter))
     ++aIter;
 }
 
 PRInt32
 nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
                                            float* aVars,
-                                           PRInt32 aNVars) const
+                                           PRInt32 aNVars)
 {
   NS_ConvertUTF16toUTF8 spec(aSpec);
 
   nsACString::const_iterator start, end;
   spec.BeginReading(start);
   spec.EndReading(end);
 
   SkipWsp(start, end);
@@ -253,19 +235,20 @@ nsSVGTransformSMILAttr::ParseParameterLi
     }
   }
 
   return numArgsFound;
 }
 
 nsresult
 nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
-  nsIDOMSVGTransform* aTransform, nsSMILValue& aValue) const
+  nsIDOMSVGTransform* aTransform, nsSMILValue& aValue)
 {
-  nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton;
+  NS_ASSERTION(aValue.mType == &nsSVGTransformSMILType::sSingleton,
+               "Unexpected type for SMIL value");
 
   PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX;
   aTransform->GetType(&svgTransformType);
 
   nsCOMPtr<nsIDOMSVGMatrix> matrix;
   nsresult rv = aTransform->GetMatrix(getter_AddRefs(matrix));
   if (NS_FAILED(rv) || !matrix)
     return NS_ERROR_FAILURE;
@@ -323,36 +306,34 @@ nsSVGTransformSMILAttr::AppendSVGTransfo
       {
         float mx[6];
         matrix->GetA(&mx[0]);
         matrix->GetB(&mx[1]);
         matrix->GetC(&mx[2]);
         matrix->GetD(&mx[3]);
         matrix->GetE(&mx[4]);
         matrix->GetF(&mx[5]);
-        rv = type->AppendTransform(nsSVGSMILTransform(mx), aValue);
-        transformType = nsSVGSMILTransform::TRANSFORM_MATRIX;
+        return nsSVGTransformSMILType::AppendTransform(nsSVGSMILTransform(mx),
+                                                       aValue);
       }
-      break;
 
     case nsIDOMSVGTransform::SVG_TRANSFORM_UNKNOWN:
       // If it's 'unknown', it's probably not initialised, so just skip it.
       return NS_OK;
 
     default:
       NS_WARNING("Trying to convert unrecognised SVG transform type");
       return NS_ERROR_FAILURE;
   }
 
-  if (transformType != nsSVGSMILTransform::TRANSFORM_MATRIX) {
-    rv =
-      type->AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
-  }
+  NS_ABORT_IF_FALSE(transformType != nsSVGSMILTransform::TRANSFORM_MATRIX,
+                    "generalized matrix case should have returned above");
 
-  return rv;
+  return nsSVGTransformSMILType::
+    AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
 }
 
 nsresult
 nsSVGTransformSMILAttr::UpdateFromSMILValue(
   nsIDOMSVGTransformList* aTransformList, const nsSMILValue& aValue)
 {
   PRUint32 svgLength = -1;
   aTransformList->GetNumberOfItems(&svgLength);
@@ -391,57 +372,53 @@ nsSVGTransformSMILAttr::UpdateFromSMILVa
   }
 
   return NS_OK;
 }
 
 nsresult
 nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue(
     const nsSVGSMILTransform& aSMILTransform,
-    nsIDOMSVGTransform* aSVGTransform) const
+    nsIDOMSVGTransform* aSVGTransform)
 {
-  nsresult rv = NS_ERROR_FAILURE;
-
   switch (aSMILTransform.mTransformType)
   {
     case nsSVGSMILTransform::TRANSFORM_TRANSLATE:
-      rv = aSVGTransform->SetTranslate(aSMILTransform.mParams[0],
-                                       aSMILTransform.mParams[1]);
-      break;
+      return aSVGTransform->SetTranslate(aSMILTransform.mParams[0],
+                                         aSMILTransform.mParams[1]);
 
     case nsSVGSMILTransform::TRANSFORM_SCALE:
-      rv = aSVGTransform->SetScale(aSMILTransform.mParams[0],
+      return aSVGTransform->SetScale(aSMILTransform.mParams[0],
                                    aSMILTransform.mParams[1]);
-      break;
 
     case nsSVGSMILTransform::TRANSFORM_ROTATE:
-      rv = aSVGTransform->SetRotate(aSMILTransform.mParams[0],
-                                    aSMILTransform.mParams[1],
-                                    aSMILTransform.mParams[2]);
-      break;
+      return aSVGTransform->SetRotate(aSMILTransform.mParams[0],
+                                      aSMILTransform.mParams[1],
+                                      aSMILTransform.mParams[2]);
 
     case nsSVGSMILTransform::TRANSFORM_SKEWX:
-      rv = aSVGTransform->SetSkewX(aSMILTransform.mParams[0]);
-      break;
+      return aSVGTransform->SetSkewX(aSMILTransform.mParams[0]);
 
     case nsSVGSMILTransform::TRANSFORM_SKEWY:
-      rv = aSVGTransform->SetSkewY(aSMILTransform.mParams[0]);
-      break;
+      return aSVGTransform->SetSkewY(aSMILTransform.mParams[0]);
 
     case nsSVGSMILTransform::TRANSFORM_MATRIX:
-      {
-        nsCOMPtr<nsIDOMSVGMatrix> svgMatrix;
-        rv = NS_NewSVGMatrix(getter_AddRefs(svgMatrix),
-                             aSMILTransform.mParams[0],
-                             aSMILTransform.mParams[1],
-                             aSMILTransform.mParams[2],
-                             aSMILTransform.mParams[3],
-                             aSMILTransform.mParams[4],
-                             aSMILTransform.mParams[5]);
-        NS_ENSURE_SUCCESS(rv,rv);
-        NS_ENSURE_TRUE(svgMatrix,NS_ERROR_FAILURE);
-        rv = aSVGTransform->SetMatrix(svgMatrix);
-      }
-      break;
+    {
+      nsCOMPtr<nsIDOMSVGMatrix> svgMatrix;
+      nsresult rv =
+        NS_NewSVGMatrix(getter_AddRefs(svgMatrix),
+                        aSMILTransform.mParams[0],
+                        aSMILTransform.mParams[1],
+                        aSMILTransform.mParams[2],
+                        aSMILTransform.mParams[3],
+                        aSMILTransform.mParams[4],
+                        aSMILTransform.mParams[5]);
+      NS_ENSURE_SUCCESS(rv, rv);
+      NS_ABORT_IF_FALSE(svgMatrix,
+                        "NS_NewSVGMatrix succeeded, so it should have "
+                        "given us a non-null result");
+      return aSVGTransform->SetMatrix(svgMatrix);
+    }
+    default:
+      NS_WARNING("Unexpected transform type");
+      return NS_ERROR_FAILURE;
   }
-
-  return rv;
 }
--- a/content/svg/content/src/nsSVGTransformSMILAttr.h
+++ b/content/svg/content/src/nsSVGTransformSMILAttr.h
@@ -49,48 +49,40 @@ class nsIDOMSVGTransform;
 class nsIDOMSVGTransformList;
 class nsSVGSMILTransform;
 
 class nsSVGTransformSMILAttr : public nsISMILAttr
 {
 public:
   nsSVGTransformSMILAttr(nsSVGAnimatedTransformList* aTransform,
                          nsSVGElement* aSVGElement)
-    : mVal(aTransform),
-      mSVGElement(aSVGElement) {}
+    : mVal(aTransform) {}
 
   // nsISMILAttr methods
-  virtual nsISMILType* GetSMILType() const;
   virtual nsresult     ValueFromString(const nsAString& aStr,
                                    const nsISMILAnimationElement* aSrcElement,
                                    nsSMILValue& aValue) const;
   virtual nsSMILValue  GetBaseValue() const;
   virtual void         ClearAnimValue();
   virtual nsresult     SetAnimValue(const nsSMILValue& aValue);
 
 protected:
-  nsresult ParseValue(const nsAString& aSpec,
-                      const nsIAtom* aTransformType,
-                      nsSMILValue& aResult) const;
-  PRInt32  ParseParameterList(const nsAString& aSpec, float* aVars,
-                              PRInt32 aNVars) const;
-  PRBool   IsSpace(const char c) const;
-  void     SkipWsp(nsACString::const_iterator& aIter,
-                   const nsACString::const_iterator& aIterEnd) const;
-  nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform,
-                                         nsSMILValue& aValue) const;
-  nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList,
-                               const nsSMILValue& aValue);
-  nsresult GetSVGTransformFromSMILValue(
-                        const nsSVGSMILTransform& aSMILTransform,
-                        nsIDOMSVGTransform* aSVGTransform) const;
-  already_AddRefed<nsIDOMSVGTransform> GetSVGTransformFromSMILValue(
-                                        const nsSMILValue& aValue) const;
+  static void ParseValue(const nsAString& aSpec,
+                         const nsIAtom* aTransformType,
+                         nsSMILValue& aResult);
+  static PRInt32  ParseParameterList(const nsAString& aSpec, float* aVars,
+                                     PRInt32 aNVars);
+  static nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform,
+                                                nsSMILValue& aValue);
+  static nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList,
+                                      const nsSMILValue& aValue);
+  static nsresult GetSVGTransformFromSMILValue(
+                    const nsSVGSMILTransform& aSMILTransform,
+                    nsIDOMSVGTransform* aSVGTransform);
 
 private:
   // Raw pointers are OK here because this nsSVGTransformSMILAttr is both
   // created & destroyed during a SMIL sample-step, during which time the DOM
   // isn't modified.
   nsSVGAnimatedTransformList* mVal;
-  nsSVGElement* mSVGElement;
 };
 
 #endif // NS_SVGTRANSFORMSMILATTR_H_
--- a/content/svg/content/src/nsSVGTransformSMILType.cpp
+++ b/content/svg/content/src/nsSVGTransformSMILType.cpp
@@ -37,38 +37,30 @@
 
 #include "nsSVGTransformSMILType.h"
 #include "nsSMILValue.h"
 #include "nsCRT.h"
 #include <math.h>
 
 /*static*/ nsSVGTransformSMILType nsSVGTransformSMILType::sSingleton;
 
+typedef nsTArray<nsSVGSMILTransform> TransformArray;
+
 //----------------------------------------------------------------------
 // nsISMILType implementation
 
 nsresult
 nsSVGTransformSMILType::Init(nsSMILValue &aValue) const
 {
-  NS_PRECONDITION(aValue.mType == this || aValue.IsNull(),
-                  "Unexpected value type");
-  NS_ASSERTION(aValue.mType != this || aValue.mU.mPtr,
-               "Invalid nsSMILValue of SVG transform type: NULL data member");
+  NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
 
-  if (aValue.mType != this || !aValue.mU.mPtr) {
-    // Different type, or no data member: allocate memory and set type
-    TransformArray* transforms = new TransformArray(1);
-    NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY);
-    aValue.mU.mPtr = transforms;
-    aValue.mType = this;
-  } else {
-    // Same type, just set clear
-    TransformArray* transforms = static_cast<TransformArray*>(aValue.mU.mPtr);
-    transforms->Clear();
-  }
+  TransformArray* transforms = new TransformArray(1);
+  NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY);
+  aValue.mU.mPtr = transforms;
+  aValue.mType = this;
 
   return NS_OK;
 }
 
 void
 nsSVGTransformSMILType::Destroy(nsSMILValue& aValue) const
 {
   NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
@@ -308,49 +300,49 @@ nsSVGTransformSMILType::Interpolate(cons
   NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY);
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // Transform array accessors
 
+// static
 PRUint32
-nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) const
+nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue)
 {
-  NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
+  NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
 
   const TransformArray& transforms =
     *static_cast<const TransformArray*>(aValue.mU.mPtr);
 
   return transforms.Length();
 }
 
+// static
 const nsSVGSMILTransform*
 nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex,
-                                       const nsSMILValue& aValue) const
+                                       const nsSMILValue& aValue)
 {
-  NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
+  NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
 
   const TransformArray& transforms =
     *static_cast<const TransformArray*>(aValue.mU.mPtr);
 
   if (aIndex >= transforms.Length()) {
     NS_ERROR("Attempting to access invalid transform");
     return nsnull;
   }
 
   return &transforms[aIndex];
 }
 
+// static
 nsresult
 nsSVGTransformSMILType::AppendTransform(const nsSVGSMILTransform& aTransform,
-                                        nsSMILValue& aValue) const
+                                        nsSMILValue& aValue)
 {
-  NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
+  NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
 
   TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
-
-  nsSVGSMILTransform* transform = transforms.AppendElement(aTransform);
-  NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY);
-
-  return NS_OK;
+  return transforms.AppendElement(aTransform) ?
+    NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
--- a/content/svg/content/src/nsSVGTransformSMILType.h
+++ b/content/svg/content/src/nsSVGTransformSMILType.h
@@ -101,41 +101,48 @@ class nsSMILValue;
 // Similar conditions hold for Interpolate() which in cases such as to-animation
 // may have use a start-value the base value of the target attribute (which as
 // we have seen above can contain 0..n elements) whilst the end-value comes from
 // the <animateTransform> and so can only hold 1 transform.
 //
 class nsSVGTransformSMILType : public nsISMILType
 {
 public:
-  // nsISMILType
+  // Singleton for nsSMILValue objects to hold onto.
+  static nsSVGTransformSMILType sSingleton;
+
+protected:
+  // nsISMILType Methods
+  // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue& aValue) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
   virtual nsresult Add(nsSMILValue& aDest,
                        const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult SandwichAdd(nsSMILValue& aDest,
                                const nsSMILValue& aValueToAdd) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
                                nsSMILValue& aResult) const;
+
+public:
   // Transform array accessors
-  PRUint32 GetNumTransforms(const nsSMILValue& aValue) const;
-  const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex,
-                                           const nsSMILValue& aValue) const;
-  nsresult AppendTransform(const nsSVGSMILTransform& aTransform,
-                           nsSMILValue& aValue) const;
+  // -------------------------
+  static PRUint32 GetNumTransforms(const nsSMILValue& aValue);
+  static const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex,
+                                                  const nsSMILValue& aValue);
+  static nsresult AppendTransform(const nsSVGSMILTransform& aTransform,
+                                  nsSMILValue& aValue);
 
-  static nsSVGTransformSMILType sSingleton;
-
-protected:
-  typedef nsTArray<nsSVGSMILTransform> TransformArray;
 
 private:
-  nsSVGTransformSMILType() {}
+  // Private constructor & destructor: prevent instances beyond my singleton,
+  // and prevent others from deleting my singleton.
+  nsSVGTransformSMILType()  {}
+  ~nsSVGTransformSMILType() {}
 };
 
 #endif // NS_SVGTRANSFORMSMILTYPE_H_
--- a/content/xul/templates/tests/chrome/templates_shared.js
+++ b/content/xul/templates/tests/chrome/templates_shared.js
@@ -47,16 +47,17 @@
  * the generated output are pseudo-random.
  */
 
 const ZOO_NS = "http://www.some-fictitious-zoo.com/";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const debug = false;
 
 var expectedConsoleMessages = [];
+var expectLoggedMessages = null;
 
 try {
   const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].
                 getService(Components.interfaces.nsIRDFService);
   const ContainerUtils = Components.classes["@mozilla.org/rdf/container-utils;1"].
                            getService(Components.interfaces.nsIRDFContainerUtils);
 } catch(ex) { }
 
@@ -83,16 +84,19 @@ function test_template()
     xmlDoc.open("get", src, false);
     xmlDoc.send(null);
   }
 
   // open menus if necessary
   if (needsOpen)
     root.open = true;
 
+  if (expectLoggedMessages)
+    expectLoggedMessages();
+
   checkResults(root, 0);
 
   if (changes.length) {
     var usedds = ds;
     // within these chrome tests, RDF datasources won't be modifiable unless
     // an in-memory datasource is used instead. Call copyRDFDataSource to
     // copy the datasource.
     if (queryType == "rdf")
--- a/content/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul
+++ b/content/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul
@@ -2,17 +2,17 @@
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 
 <!--
   xml query with binding in rule
 -->
 
 <window title="XUL Template Tests" width="500" height="600"
-        onload="expectLoggedMessages(); test_template();"
+        onload="test_template();"
         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>
 
   <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
 
@@ -32,17 +32,17 @@ var expectedOutput =
 <output>
   <label anyid="true" container="true" empty="true" value="Class Reptiles"/>
   <label anyid="true" container="true" empty="true" value="Class Birds"/>
 </output>;
 
 Components.classes["@mozilla.org/consoleservice;1"].
            getService(Components.interfaces.nsIConsoleService).reset();
 
-function expectLoggedMessages()
+expectLoggedMessages = function()
 {
   // check log to ensure that two rows have been added
   var initialNumber = Number(document.getElementById("root").firstChild.nextSibling.id.substring(3));
   expectConsoleMessage('', 'row' + initialNumber, true, true, '1 matching rule 1');
   expectConsoleMessage('', 'row' + (initialNumber + 1), true, true, '1 matching rule 1');
 }
 
 var changes = [];
new file mode 100644
--- /dev/null
+++ b/docshell/base/crashtests/500328-1.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<body onload="test();">
+<script>
+  function test() {
+    // Test that calling pushState() with a state object which calls
+    // history.back() doesn't crash. We need to make sure that there's at least
+    // one entry in the history before we do anything else.
+    history.pushState(null, "");
+
+    x = {};
+    x.toJSON = { history.back(); return "{a:1}"; };
+    history.pushState(x, "");
+  }
+</script>
+</body>
+</html>
--- a/docshell/base/crashtests/crashtests.list
+++ b/docshell/base/crashtests/crashtests.list
@@ -1,8 +1,9 @@
 load 40929-1.html
 load 369126-1.html
 load 403574-1.xhtml
 load 430124-1.html
 load 430628-1.html
 load 432114-1.html
 load 432114-2.html
 load 436900-1.html
+load 500328-1.html
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -104,16 +104,17 @@
 #include "nsDOMJSUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIView.h"
 #include "nsIViewManager.h"
 #include "nsIScriptChannel.h"
 #include "nsIURIClassifier.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsCPrefetchService.h"
+#include "nsJSON.h"
 
 // we want to explore making the document own the load group
 // so we can associate the document URI with the load group.
 // until this point, we have an evil hack:
 #include "nsIHttpChannelInternal.h"  
 
 
 // Local Includes
@@ -650,16 +651,18 @@ DispatchPings(nsIContent *content, nsIUR
     return;
 
   info.numPings = 0;
   info.referrer = referrer;
 
   ForEachPing(content, SendPing, &info);
 }
 
+static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
+
 //*****************************************************************************
 //***    nsDocShell: Object Management
 //*****************************************************************************
 
 // Note: operator new zeros our memory
 nsDocShell::nsDocShell():
     nsDocLoader(),
     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
@@ -858,16 +861,24 @@ NS_IMETHODIMP nsDocShell::GetInterface(c
              NS_SUCCEEDED(EnsureScriptEnvironment())) {
         return mScriptGlobal->QueryInterface(aIID, aSink);
     }
     else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
              NS_SUCCEEDED(EnsureContentViewer())) {
         mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
         return *aSink ? NS_OK : NS_NOINTERFACE;
     }
+    else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
+             NS_SUCCEEDED(EnsureContentViewer())) {
+        nsCOMPtr<nsIDOMDocument> domDoc;
+        mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
+        if (!domDoc)
+            return NS_NOINTERFACE;
+        return domDoc->QueryInterface(aIID, aSink);
+    }
     else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
         *aSink = nsnull;
 
         // Return application cache associated with this docshell, if any
 
         nsCOMPtr<nsIContentViewer> contentViewer;
         GetContentViewer(getter_AddRefs(contentViewer));
         if (!contentViewer)
@@ -1191,17 +1202,17 @@ nsDocShell::LoadURI(nsIURI * aURI,
                     // This is a newly created frame. Check for exception cases first. 
                     // By default the subframe will inherit the parent's loadType.
                     if (shEntry && (parentLoadType == LOAD_NORMAL ||
                                     parentLoadType == LOAD_LINK   ||
                                     parentLoadType == LOAD_NORMAL_EXTERNAL)) {
                         // The parent was loaded normally. In this case, this *brand new* child really shouldn't
                         // have a SHEntry. If it does, it could be because the parent is replacing an
                         // existing frame with a new frame, in the onLoadHandler. We don't want this
-                        // url to get into session history. Clear off shEntry, and set laod type to
+                        // url to get into session history. Clear off shEntry, and set load type to
                         // LOAD_BYPASS_HISTORY. 
                         PRBool inOnLoadHandler=PR_FALSE;
                         parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
                         if (inOnLoadHandler) {
                             loadType = LOAD_NORMAL_REPLACE;
                             shEntry = nsnull;
                         }
                     }   
@@ -3221,21 +3232,21 @@ nsDocShell::GetChildSHEntry(PRInt32 aChi
                 (*aResult)->SetLoadType(loadType);            
         }
     }
     return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
-                            PRInt32 aChildOffset)
+                            PRInt32 aChildOffset, PRUint32 loadType)
 {
     nsresult rv;
 
-    if (mLSHE) {
+    if (mLSHE && loadType != LOAD_PUSHSTATE) {
         /* You get here if you are currently building a 
          * hierarchy ie.,you just visited a frameset page
          */
         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
         if (container) {
             rv = container->AddChild(aNewEntry, aChildOffset);
         }
     }
@@ -3280,17 +3291,18 @@ nsDocShell::AddChildSHEntry(nsISHEntry *
             }
         }
     }
     else {
         /* Just pass this along */
         nsCOMPtr<nsIDocShellHistory> parent =
             do_QueryInterface(GetAsSupports(mParent), &rv);
         if (parent) {
-            rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset);
+            rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
+                                         loadType);
         }          
     }
     return rv;
 }
 
 nsresult
 nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset)
 {
@@ -3308,17 +3320,17 @@ nsDocShell::DoAddChildSHEntry(nsISHEntry
     if (rootSH) {
         rootSH->GetIndex(&mPreviousTransIndex);
     }
 
     nsresult rv;
     nsCOMPtr<nsIDocShellHistory> parent =
         do_QueryInterface(GetAsSupports(mParent), &rv);
     if (parent) {
-        rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset);
+        rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType);
     }
 
 
     if (rootSH) {
         rootSH->GetIndex(&mLoadedTransIndex);
 #ifdef DEBUG_PAGE_CACHE
         printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
                mLoadedTransIndex);
@@ -3452,17 +3464,16 @@ NS_IMETHODIMP nsDocShell::GotoIndex(PRIn
     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
     rv = webnav->GotoIndex(aIndex);
     return rv;
 
 }
 
-
 NS_IMETHODIMP
 nsDocShell::LoadURI(const PRUnichar * aURI,
                     PRUint32 aLoadFlags,
                     nsIURI * aReferringURI,
                     nsIInputStream * aPostStream,
                     nsIInputStream * aHeaderStream)
 {
     NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
@@ -3841,16 +3852,23 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, 
                ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
                 spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
     }
 #endif
     mFailedChannel = aFailedChannel;
     mFailedURI = aURI;
     mFailedLoadType = mLoadType;
 
+    if (mLSHE) {
+        // If we don't give mLSHE a new doc identifier here, when we go back or
+        // forward to another SHEntry with the same doc identifier, the error
+        // page will persist.
+        mLSHE->SetUniqueDocIdentifier();
+    }
+
     nsCAutoString url;
     nsCAutoString charset;
     if (aURI)
     {
         nsresult rv = aURI->GetSpec(url);
         rv |= aURI->GetOriginCharset(charset);
         NS_ENSURE_SUCCESS(rv, rv);
     }
@@ -5709,23 +5727,23 @@ nsDocShell::EndPageLoad(nsIWebProgress *
     // someone is so very very rude as to bring this window down
     // during this load handler.
     //
     nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
 
     // We're done with the URI classifier for this channel
     mClassifier = nsnull;
 
-    //
-    // Notify the ContentViewer that the Document has finished loading...
-    //
-    // This will cause any OnLoad(...) handlers to fire, if it is a HTML
-    // document...
-    //
+    // Notify the ContentViewer that the Document has finished loading.  This
+    // will cause any OnLoad(...) and PopState(...) handlers to fire.
     if (!mEODForCurrentDocument && mContentViewer) {
+        // Set the pending state object which will be returned to the page in
+        // the popstate event.
+        SetDocPendingStateObj(mLSHE);
+
         mIsExecutingOnLoadHandler = PR_TRUE;
         mContentViewer->LoadComplete(aStatus);
         mIsExecutingOnLoadHandler = PR_FALSE;
 
         mEODForCurrentDocument = PR_TRUE;
 
         // If all documents have completed their loading
         // favor native event dispatch priorities
@@ -7363,16 +7381,36 @@ nsDocShell::SetupNewViewer(nsIContentVie
 
     // We don't show the mContentViewer yet, since we want to draw the old page
     // until we have enough of the new page to show.  Just return with the new
     // viewer still set to hidden.
 
     return NS_OK;
 }
 
+nsresult
+nsDocShell::SetDocPendingStateObj(nsISHEntry *shEntry)
+{
+    nsresult rv;
+
+    nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
+    NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
+
+    nsAutoString stateData;
+    if (shEntry) {
+        rv = shEntry->GetStateData(stateData);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        // if shEntry is null, we just set the pending state object to the
+        // empty string.
+    }
+
+    document->SetPendingStateObject(stateData);
+    return NS_OK;
+}
 
 nsresult
 nsDocShell::CheckLoadingPermissions()
 {
     // This method checks whether the caller may load content into
     // this docshell. Even though we've done our best to hide windows
     // from code that doesn't have the right to access them, it's
     // still possible for an evil site to open a window and access
@@ -7839,86 +7877,121 @@ nsDocShell::InternalLoad(nsIURI * aURI,
         if (allowScroll) {
             nsCOMPtr<nsIInputStream> currentPostData;
             mOSHE->GetPostData(getter_AddRefs(currentPostData));
             NS_ASSERTION(currentPostData == aPostData,
                          "Different POST data for entries for the same page?");
         }
 #endif
     }
-    
-    if ((aLoadType == LOAD_NORMAL ||
-         aLoadType == LOAD_STOP_CONTENT ||
-         LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
-         aLoadType == LOAD_HISTORY ||
-         aLoadType == LOAD_LINK) && allowScroll) {
+
+    if (aLoadType == LOAD_NORMAL ||
+        aLoadType == LOAD_STOP_CONTENT ||
+        LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
+        aLoadType == LOAD_HISTORY ||
+        aLoadType == LOAD_LINK) {
+
         PRBool wasAnchor = PR_FALSE;
         PRBool doHashchange = PR_FALSE;
         nscoord cx, cy;
-        NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx, &cy,
-                                         &doHashchange),
-                          NS_ERROR_FAILURE);
-
-        if (wasAnchor) {
+
+        if (allowScroll) {
+            NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx,
+                                             &cy, &doHashchange),
+                              NS_ERROR_FAILURE);
+        }
+
+        // If this is a history load, aSHEntry will have document identifier X
+        // if it was created as a result of a History.pushState() from a
+        // SHEntry with doc ident X, or if it was created by changing the hash
+        // of the URI corresponding to a SHEntry with doc ident X.
+        PRBool sameDocIdent = PR_FALSE;
+        if (mOSHE && aSHEntry) {
+          PRUint64 ourDocIdent, otherDocIdent;
+          mOSHE->GetDocIdentifier(&ourDocIdent);
+          aSHEntry->GetDocIdentifier(&otherDocIdent);
+          sameDocIdent = (ourDocIdent == otherDocIdent);
+        }
+
+        // Do a short-circuited load if the new URI differs from the current
+        // URI only in the hash, or if the two entries belong to the same
+        // document and don't point to the same object.
+        //
+        // (If we didn't check that the SHEntries are different objects,
+        // history.go(0) would short-circuit instead of triggering a true
+        // load, and we wouldn't dispatch an onload event to the page.)
+        if (wasAnchor || (sameDocIdent && (mOSHE != aSHEntry))) {
             mLoadType = aLoadType;
             mURIResultedInDocument = PR_TRUE;
 
-            /* we need to assign mLSHE to aSHEntry right here, so that on History loads, 
-             * SetCurrentURI() called from OnNewURI() will send proper 
+            /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
+             * SetCurrentURI() called from OnNewURI() will send proper
              * onLocationChange() notifications to the browser to update
-             * back/forward buttons. 
+             * back/forward buttons.
              */
             SetHistoryEntry(&mLSHE, aSHEntry);
 
             /* This is a anchor traversal with in the same page.
              * call OnNewURI() so that, this traversal will be 
              * recorded in session and global history.
              */
             nsCOMPtr<nsISupports> owner;
             if (mOSHE) {
                 mOSHE->GetOwner(getter_AddRefs(owner));
             }
             OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE);
+
             nsCOMPtr<nsIInputStream> postData;
             PRUint32 pageIdent = PR_UINT32_MAX;
             nsCOMPtr<nsISupports> cacheKey;
-            
+
             if (mOSHE) {
                 /* save current position of scroller(s) (bug 59774) */
                 mOSHE->SetScrollPosition(cx, cy);
                 // Get the postdata and page ident from the current page, if
                 // the new load is being done via normal means.  Note that
                 // "normal means" can be checked for just by checking for
                 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
                 // above -- it filters out some LOAD_CMD_NORMAL cases that we
                 // wouldn't want here.
                 if (aLoadType & LOAD_CMD_NORMAL) {
                     mOSHE->GetPostData(getter_AddRefs(postData));
                     mOSHE->GetPageIdentifier(&pageIdent);
                     mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
                 }
+
+                if (mLSHE && wasAnchor) {
+                    // If it's an anchor load, set mLSHE's doc identifier to
+                    // mOSHE's doc identifier -- These are the same documents,
+                    // as far as HTML5 is concerned.
+                    PRUint64 docIdent;
+                    rv = mOSHE->GetDocIdentifier(&docIdent);
+                    if (NS_SUCCEEDED(rv)) {
+                        mLSHE->SetDocIdentifier(docIdent);
+                    }
+                }
             }
-            
+
             /* Assign mOSHE to mLSHE. This will either be a new entry created
              * by OnNewURI() for normal loads or aSHEntry for history loads.
              */
             if (mLSHE) {
                 SetHistoryEntry(&mOSHE, mLSHE);
                 // Save the postData obtained from the previous page
                 // in to the session history entry created for the 
                 // anchor page, so that any history load of the anchor
                 // page will restore the appropriate postData.
                 if (postData)
                     mOSHE->SetPostData(postData);
 
                 // Make sure we won't just repost without hitting the
                 // cache first
                 if (cacheKey)
                     mOSHE->SetCacheKey(cacheKey);
-                
+
                 // Propagate our page ident to the new mOSHE so that
                 // we'll know it just differed by a scroll on the page.
                 if (pageIdent != PR_UINT32_MAX)
                     mOSHE->SetPageIdentifier(pageIdent);
             }
 
             /* restore previous position of scroller(s), if we're moving
              * back in history (bug 59774)
@@ -7944,22 +8017,37 @@ nsDocShell::InternalLoad(nsIURI * aURI,
                 mSessionHistory->GetEntryAtIndex(index, PR_FALSE,
                                                  getter_AddRefs(hEntry));
                 NS_ENSURE_TRUE(hEntry, NS_ERROR_FAILURE);
                 nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(hEntry));
                 if (shEntry)
                     shEntry->SetTitle(mTitle);
             }
 
-            if (doHashchange) {
-                nsCOMPtr<nsPIDOMWindow> window =
-                    do_QueryInterface(mScriptGlobal);
-
-                if (window)
-                    window->DispatchSyncHashchange();
+            if (sameDocIdent) {
+                // Set the doc's URI according to the new history entry's URI
+                nsCOMPtr<nsIURI> newURI;
+                mOSHE->GetURI(getter_AddRefs(newURI));
+                NS_ENSURE_TRUE(newURI, NS_ERROR_FAILURE);
+                nsCOMPtr<nsIDocument> doc =
+                  do_GetInterface(GetAsSupports(this));
+                NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+
+                doc->SetDocumentURI(newURI);
+            }
+
+            SetDocPendingStateObj(mOSHE);
+
+            // Dispatch the popstate and hashchange events, as appropriate
+            nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal);
+            if (window) {
+                window->DispatchSyncPopState();
+
+                if (doHashchange)
+                  window->DispatchSyncHashchange();
             }
 
             return NS_OK;
         }
     }
     
     // mContentViewer->PermitUnload can destroy |this| docShell, which
     // causes the next call of CanSavePresentation to crash. 
@@ -8832,16 +8920,24 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
         }
 
         if (httpChannel) {
             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
             if (uploadChannel) {
                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
             }
+
+            // If the response status indicates an error, unlink this session
+            // history entry from any entries sharing its doc ident.
+            PRUint32 responseStatus;
+            nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
+            if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
+                mLSHE->SetUniqueDocIdentifier();
+            }
         }
     }
     /* Create SH Entry (mLSHE) only if there is a  SessionHistory object (mSessionHistory) in
      * the current frame or in the root docshell
      */
     nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
     if (!rootSH) {
         // Get the handle to SH from the root docshell          
@@ -8853,17 +8949,17 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
 
     // Determine if this type of load should update history.
     if (aLoadType == LOAD_BYPASS_HISTORY ||
         aLoadType == LOAD_ERROR_PAGE ||
         aLoadType & LOAD_CMD_HISTORY ||
         aLoadType & LOAD_CMD_RELOAD)
         updateHistory = PR_FALSE;
 
-    // Check if the url to be loaded is the same as the one already loaded. 
+    // Check if the url to be loaded is the same as the one already loaded.
     if (mCurrentURI)
         aURI->Equals(mCurrentURI, &equalUri);
 
 #ifdef DEBUG
     PR_LOG(gDocShellLog, PR_LOG_DEBUG,
            ("  shAvailable=%i updateHistory=%i equalURI=%i\n",
             shAvailable, updateHistory, equalUri));
 #endif
@@ -8890,17 +8986,16 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
     }
 
     // If this is a refresh to the currently loaded url, we don't
     // have to update session or global history.
     if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
         SetHistoryEntry(&mLSHE, mOSHE);
     }
 
-
     /* If the user pressed shift-reload, cache will create a new cache key
      * for the page. Save the new cacheKey in Session History. 
      * see bug 90098
      */
     if (aChannel &&
         (aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
          aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
          aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
@@ -8980,17 +9075,293 @@ nsDocShell::OnLoadingSite(nsIChannel * a
 void
 nsDocShell::SetReferrerURI(nsIURI * aURI)
 {
     mReferrerURI = aURI;        // This assigment addrefs
 }
 
 //*****************************************************************************
 // nsDocShell: Session History
-//*****************************************************************************   
+//*****************************************************************************
+
+nsresult
+nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
+{
+    nsresult rv;
+    aResult.Truncate();
+
+    // First, try to extract a jsval from the variant |aData|.  This works only
+    // if the variant implements GetAsJSVal.
+    jsval jsData;
+    rv = aData->GetAsJSVal(&jsData);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
+
+    // Now get the JSContext associated with the current document.
+    // First get the current document.
+    nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
+    NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
+
+    // Get the JSContext from the document, like we do in
+    // nsContentUtils::GetContextFromDocument().
+    nsIScriptGlobalObject *sgo = document->GetScopeObject();
+    NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
+
+    nsIScriptContext *scx = sgo->GetContext();
+    NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
+
+    JSContext *cx = (JSContext *)scx->GetNativeContext();
+
+    // If our json call triggers a JS-to-C++ call, we want that call to use cx
+    // as the context.  So we push cx onto the context stack.
+    nsCOMPtr<nsIJSContextStack> contextStack =
+        do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    contextStack->Push(cx);
+
+    nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
+    if(json) {
+        // Do the encoding
+        rv = json->EncodeFromJSVal(&jsData, cx, aResult);
+    }
+    else {
+        rv = NS_ERROR_FAILURE;
+    }
+
+    // Always pop the stack!
+    contextStack->Pop(&cx);
+
+    return rv;
+}
+
+NS_IMETHODIMP
+nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
+                     const nsAString& aURL, PRBool aReplace)
+{
+    // Implements History.pushState and History.replaceState
+
+    // Here's what we do, roughly in the order specified by HTML5:
+    // 1. Serialize aData to JSON.
+    // 2. If the third argument is present,
+    //     a. Resolve the url, relative to the first script's base URL
+    //     b. If (a) fails, raise a SECURITY_ERR
+    //     c. Compare the resulting absolute URL to the document's address.  If
+    //        any part of the URLs difer other than the <path>, <query>, and
+    //        <fragment> components, raise a SECURITY_ERR and abort.
+    // 3. If !aReplace:
+    //     Remove from the session history all entries after the current entry,
+    //     as we would after a regular navigation.
+    // 4. As apropriate, either add a state object entry to the session history
+    //    after the current entry with the following properties, or modify the
+    //    current session history entry to set
+    //      a. cloned data as the state object,
+    //      b. the given title as the title, and,
+    //      c. if the third argument was present, the absolute URL found in
+    //         step 2
+    // 5. If aReplace is false (i.e. we're doing a pushState instead of a
+    //    replaceState), notify bfcache that we've navigated to a new page.
+    // 6. If the third argument is present, set the document's current address
+    //    to the absolute URL found in step 2.
+    //
+    // It's important that this function not run arbitrary scripts after step 1
+    // and before completing step 5.  For example, if a script called
+    // history.back() before we completed step 5, bfcache might destroy an
+    // active content viewer.  Since EvictContentViewers at the end of step 5
+    // might run script, we can't just put a script blocker around the critical
+    // section.
+
+    nsresult rv;
+
+    nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
+    NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
+
+    mLoadType = LOAD_PUSHSTATE;
+
+    // Step 1: Clone aData by getting its JSON representation
+    nsString dataStr;
+    rv = StringifyJSValVariant(aData, dataStr);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Check that the state object isn't too long.
+    // Default max length: 640k chars.
+    PRInt32 maxStateObjSize = 0xA0000;
+    if (mPrefs) {
+      mPrefs->GetIntPref("browser.history.maxStateObjectSize",
+                         &maxStateObjSize);
+    }
+    if (maxStateObjSize < 0)
+      maxStateObjSize = 0;
+    NS_ENSURE_TRUE(dataStr.Length() <= (PRUint32)maxStateObjSize,
+                   NS_ERROR_ILLEGAL_VALUE);
+
+    // Step 2: Resolve aURL
+    PRBool equalURIs = PR_TRUE;
+    nsCOMPtr<nsIURI> oldURI = mCurrentURI;
+    nsCOMPtr<nsIURI> newURI;
+    if (aURL.Length() == 0) {
+      newURI = mCurrentURI;
+    }
+    else {
+        // 2a: Resolve aURL relative to mURI
+
+        nsIURI* docBaseURI = document->GetBaseURI();
+        if (!docBaseURI)
+            return NS_ERROR_FAILURE;
+
+        nsCAutoString spec;
+        docBaseURI->GetSpec(spec);
+
+        nsCAutoString charset;
+        rv = docBaseURI->GetOriginCharset(charset);
+        NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+
+        rv = NS_NewURI(getter_AddRefs(newURI), aURL,
+                       charset.get(), docBaseURI);
+
+        // 2b: If 2a fails, raise a SECURITY_ERR
+        if (NS_FAILED(rv)) {
+            return NS_ERROR_DOM_SECURITY_ERR;
+        }
+
+        // 2c: Same-origin check.
+        if (!URIIsLocalFile(newURI)) {
+            // In addition to checking that the security manager says that
+            // the new URI has the same origin as our current URI, we also
+            // check that the two URIs have the same userpass. (The
+            // security manager says that |http://foo.com| and
+            // |http://me@foo.com| have the same origin.)  mCurrentURI
+            // won't contain the password part of the userpass, so this
+            // means that it's never valid to specify a password in a
+            // pushState or replaceState URI.
+
+            nsCOMPtr<nsIScriptSecurityManager> secMan =
+                do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
+            NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
+
+            // It's very important that we check that newURI is of the same
+            // origin as mCurrentURI, not docBaseURI, because a page can
+            // set docBaseURI arbitrarily to any domain.
+            nsCAutoString currentUserPass, newUserPass;
+            NS_ENSURE_SUCCESS(mCurrentURI->GetUserPass(currentUserPass),
+                              NS_ERROR_FAILURE);
+            NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass),
+                              NS_ERROR_FAILURE);
+            if (NS_FAILED(secMan->CheckSameOriginURI(mCurrentURI,
+                                                     newURI, PR_TRUE)) ||
+                !currentUserPass.Equals(newUserPass)) {
+
+                return NS_ERROR_DOM_SECURITY_ERR;
+            }
+        }
+        else {
+            // It's a file:// URI
+            nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
+                do_QueryInterface(document);
+
+            if (!docScriptObj) {
+                return NS_ERROR_DOM_SECURITY_ERR;
+            }
+
+            nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
+
+            if (!principal ||
+                NS_FAILED(principal->CheckMayLoad(newURI, PR_TRUE))) {
+
+                return NS_ERROR_DOM_SECURITY_ERR;
+            }
+        }
+
+        mCurrentURI->Equals(newURI, &equalURIs);
+
+    } // end of same-origin check
+
+    nsCOMPtr<nsISHistory> sessionHistory = mSessionHistory;
+    if (!sessionHistory) {
+        // Get the handle to SH from the root docshell
+        GetRootSessionHistory(getter_AddRefs(sessionHistory));
+    }
+    NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE);
+
+    nsCOMPtr<nsISHistoryInternal> shInternal =
+      do_QueryInterface(sessionHistory, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Step 3: Create a new entry in the session history; this will erase
+    // all SHEntries after the new entry and make this entry the current
+    // one.  This operation may modify mOSHE, which we need later, so we
+    // keep a reference here.
+    NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
+    nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
+
+    nsCOMPtr<nsISHEntry> newSHEntry;
+    if (!aReplace) {
+        rv = AddToSessionHistory(newURI, nsnull, nsnull,
+                                 getter_AddRefs(newSHEntry));
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
+
+        // Set the new SHEntry's document identifier, if we can.
+        PRUint64 ourDocIdent;
+        NS_ENSURE_SUCCESS(oldOSHE->GetDocIdentifier(&ourDocIdent),
+                          NS_ERROR_FAILURE);
+        NS_ENSURE_SUCCESS(newSHEntry->SetDocIdentifier(ourDocIdent),
+                          NS_ERROR_FAILURE);
+
+        // AddToSessionHistory may not modify mOSHE.  In case it doesn't,
+        // we'll just set mOSHE here.
+        mOSHE = newSHEntry;
+
+    } else {
+        newSHEntry = mOSHE;
+        newSHEntry->SetURI(newURI);
+    }
+
+    // Step 4: Modify new/original session history entry
+    newSHEntry->SetStateData(dataStr);
+
+    // Step 5: If aReplace is false, indicating that we're doing a pushState
+    // rather than a replaceState, notify bfcache that we've added a page to
+    // the history so it can evict content viewers if appropriate.
+    if (!aReplace) {
+        nsCOMPtr<nsISHistory> rootSH;
+        GetRootSessionHistory(getter_AddRefs(rootSH));
+        NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
+
+        nsCOMPtr<nsISHistoryInternal> internalSH =
+            do_QueryInterface(rootSH);
+        NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
+
+        PRInt32 curIndex = -1;
+        rv = rootSH->GetIndex(&curIndex);
+        if (NS_SUCCEEDED(rv) && curIndex > -1) {
+            internalSH->EvictContentViewers(curIndex - 1, curIndex);
+        }
+    }
+
+    // Step 6: If the document's URI changed, update document's URI and update
+    // global history
+    if (!equalURIs) {
+        SetCurrentURI(newURI, nsnull, PR_TRUE);
+        document->SetDocumentURI(newURI);
+
+        AddToGlobalHistory(newURI, PR_FALSE, oldURI);
+    }
+
+    // Try to set the title of the current history element
+    if (mOSHE)
+      mOSHE->SetTitle(aTitle);
+
+    // We need this to ensure that the back button is enabled after a
+    // pushState, if it wasn't already enabled.
+    FireOnLocationChange(this, nsnull, mCurrentURI);
+
+    return NS_OK;
+}
+
 PRBool
 nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
 {
     // I believe none of the about: urls should go in the history. But then
     // that could just be me... If the intent is only deny about:blank then we
     // should just do a spec compare, rather than two gets of the scheme and
     // then the path.  -Gagan
     nsresult rv;
@@ -9423,17 +9794,16 @@ nsDocShell::CloneAndReplace(nsISHEntry *
 
     CloneAndReplaceData data(aCloneID, aReplaceEntry, nsnull);
     nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
 
     data.resultEntry.swap(*aResultEntry);
     return rv;
 }
 
-
 void
 nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
 {
     if (aOldEntry == mOSHE)
         mOSHE = aNewEntry;
 
     if (aOldEntry == mLSHE)
         mLSHE = aNewEntry;
@@ -9674,51 +10044,59 @@ NS_IMETHODIMP nsDocShell::MakeEditable(P
 
   return mEditorData->MakeEditable(inWaitForUriLoad);
 }
 
 nsresult
 nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
                                nsIChannel * aChannel)
 {
-    if (mItemType != typeContent || !mGlobalHistory)
-        return NS_OK;
-
     // If this is a POST request, we do not want to include this in global
     // history, so return early.
     nsCOMPtr<nsIHttpChannel> hchan(do_QueryInterface(aChannel));
     if (hchan) {
         nsCAutoString type;
         nsresult rv = hchan->GetRequestMethod(type);
         if (NS_SUCCEEDED(rv) && type.EqualsLiteral("POST"))
             return NS_OK;
     }
 
+    nsCOMPtr<nsIURI> referrer;
+    if (aChannel)
+        NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
+
+    return AddToGlobalHistory(aURI, aRedirect, referrer);
+}
+
+nsresult
+nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
+                               nsIURI * aReferrer)
+{
+    if (mItemType != typeContent || !mGlobalHistory)
+        return NS_OK;
+
     PRBool visited;
     nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
     if (NS_FAILED(rv))
         return rv;
 
-    nsCOMPtr<nsIURI> referrer;
-    if (aChannel)
-        NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
-
-    rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), referrer);
+    rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer);
     if (NS_FAILED(rv))
         return rv;
 
     if (!visited) {
         nsCOMPtr<nsIObserverService> obsService =
             do_GetService("@mozilla.org/observer-service;1");
         if (obsService) {
             obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
         }
     }
 
     return NS_OK;
+
 }
 
 //*****************************************************************************
 // nsDocShell: Helper Routines
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsDocShell::SetLoadType(PRUint32 aLoadType)
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -359,16 +359,20 @@ protected:
     // exists).  The channel will be suspended until the classification is
     // complete.
     nsresult CheckClassifier(nsIChannel *aChannel);
 
     nsresult ScrollIfAnchor(nsIURI * aURI, PRBool * aWasAnchor,
                             PRUint32 aLoadType, nscoord *cx, nscoord *cy,
                             PRBool * aDoHashchange);
 
+    // Tries to stringify a given variant by converting it to JSON.  This only
+    // works if the variant is backed by a JSVal.
+    nsresult StringifyJSValVariant(nsIVariant *aData, nsAString &aResult);
+
     // Returns PR_TRUE if would have called FireOnLocationChange,
     // but did not because aFireOnLocationChange was false on entry.
     // In this case it is the caller's responsibility to ensure
     // FireOnLocationChange is called.
     // In all other cases PR_FALSE is returned.
     PRBool OnLoadingSite(nsIChannel * aChannel,
                          PRBool aFireOnLocationChange,
                          PRBool aAddToGlobalHistory = PR_TRUE);
@@ -460,18 +464,21 @@ protected:
     // overridden from nsDocLoader, this provides more information than the
     // normal OnStateChange with flags STATE_REDIRECTING
     virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
                                        nsIChannel* aNewChannel,
                                        PRUint32 aRedirectFlags,
                                        PRUint32 aStateFlags);
 
     // Global History
+
     nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
                                 nsIChannel * aChannel);
+    nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
+                                nsIURI * aReferrer);
 
     // Helper Routines
     nsresult   ConfirmRepost(PRBool * aRepost);
     NS_IMETHOD GetPromptAndStringBundle(nsIPrompt ** aPrompt,
         nsIStringBundle ** aStringBundle);
     NS_IMETHOD GetChildOffset(nsIDOMNode * aChild, nsIDOMNode * aParent,
         PRInt32 * aOffset);
     nsIScrollableFrame* GetRootScrollFrame();
@@ -510,16 +517,21 @@ protected:
     //
     // Helper method that is called when a new document (including any
     // sub-documents - ie. frames) has been completely loaded.
     //
     virtual nsresult EndPageLoad(nsIWebProgress * aProgress,
                                  nsIChannel * aChannel,
                                  nsresult aResult);
 
+    // Sets the current document's pending state object to the given SHEntry's
+    // state object.  The pending state object is eventually given to the page
+    // in the PopState event.
+    nsresult SetDocPendingStateObj(nsISHEntry *shEntry);
+
     nsresult CheckLoadingPermissions();
 
     // Security checks to prevent frameset spoofing.  See comments at
     // implementation sites.
     static PRBool CanAccessItem(nsIDocShellTreeItem* aTargetItem,
                                 nsIDocShellTreeItem* aAccessingItem,
                                 PRBool aConsiderOpener = PR_TRUE);
     static PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
--- a/docshell/base/nsDocShellLoadTypes.h
+++ b/docshell/base/nsDocShellLoadTypes.h
@@ -87,16 +87,17 @@ enum LoadType {
     LOAD_RELOAD_BYPASS_PROXY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
     LOAD_RELOAD_BYPASS_PROXY_AND_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
     LOAD_LINK = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_IS_LINK),
     LOAD_REFRESH = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_IS_REFRESH),
     LOAD_RELOAD_CHARSET_CHANGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE),
     LOAD_BYPASS_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY),
     LOAD_STOP_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT),
     LOAD_STOP_CONTENT_AND_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT | nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY),
+    LOAD_PUSHSTATE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_PUSHSTATE, nsIWebNavigation::LOAD_FLAGS_NONE),
     /**
      * Load type for an error page. These loads are never triggered by users of
      * Docshell. Instead, Docshell triggers the load itself when a
      * consumer-triggered load failed.
      */
     LOAD_ERROR_PAGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, LOAD_FLAGS_ERROR_PAGE)
 
     // NOTE: Adding a new value? Remember to update IsValidLoadType!
@@ -117,16 +118,17 @@ static inline PRBool IsValidLoadType(PRU
     case LOAD_RELOAD_BYPASS_PROXY:
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
     case LOAD_LINK:
     case LOAD_REFRESH:
     case LOAD_RELOAD_CHARSET_CHANGE:
     case LOAD_BYPASS_HISTORY:
     case LOAD_STOP_CONTENT:
     case LOAD_STOP_CONTENT_AND_REPLACE:
+    case LOAD_PUSHSTATE:
     case LOAD_ERROR_PAGE:
         return PR_TRUE;
     }
     return PR_FALSE;
 }
 
 #endif // MOZILLA_INTERNAL_API
 #endif 
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -64,18 +64,19 @@ interface nsISimpleEnumerator;
 interface nsIInputStream;
 interface nsIRequest;
 interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
+interface nsIVariant;
 
-[scriptable, uuid(c95eaff1-14e6-4db1-a806-46be97d5a9b6)]
+[scriptable, uuid(3adde256-05a9-43a7-a190-f8fe75eecfd6)]
 interface nsIDocShell : nsISupports
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -165,16 +166,23 @@ interface nsIDocShell : nsISupports
                               in nsIInputStream aHeadersStream,
                               in unsigned long aLoadFlags,
                               in nsISHEntry aSHEntry,
                               in boolean firstParty,
                               out nsIDocShell aDocShell,
                               out nsIRequest aRequest);
 
   /**
+   * Do either a history.pushState() or history.replaceState() operation,
+   * depending on the value of aReplace.
+   */
+  void addState(in nsIVariant aData, in DOMString aTitle,
+                in DOMString aURL, in boolean aReplace);
+
+  /**
    * Creates a DocShellLoadInfo object that you can manipulate and then pass
    * to loadURI.
    */
   void createLoadInfo(out nsIDocShellLoadInfo loadInfo);
 
   /**
    * Reset state to a new content model within the current document and the document
    * viewer.  Called by the document before initiating an out of band document.write().
@@ -334,19 +342,20 @@ interface nsIDocShell : nsISupports
   const unsigned long BUSY_FLAGS_NONE             = 0;
   const unsigned long BUSY_FLAGS_BUSY             = 1;
   const unsigned long BUSY_FLAGS_BEFORE_PAGE_LOAD = 2;
   const unsigned long BUSY_FLAGS_PAGE_LOADING     = 4;
 
   /**
    * Load commands for the document 
    */
-  const unsigned long LOAD_CMD_NORMAL  = 0x1; // Normal load
-  const unsigned long LOAD_CMD_RELOAD  = 0x2; // Reload
-  const unsigned long LOAD_CMD_HISTORY = 0x4; // Load from history
+  const unsigned long LOAD_CMD_NORMAL  = 0x1;   // Normal load
+  const unsigned long LOAD_CMD_RELOAD  = 0x2;   // Reload
+  const unsigned long LOAD_CMD_HISTORY = 0x4;   // Load from history
+  const unsigned long LOAD_CMD_PUSHSTATE = 0x8; // History.pushState()
 
   readonly attribute unsigned long busyFlags;
 
   /* 
    * attribute to access the loadtype  for the document
    */
   attribute unsigned long  loadType;
 
--- a/docshell/base/nsIDocShellHistory.idl
+++ b/docshell/base/nsIDocShellHistory.idl
@@ -34,29 +34,30 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 interface nsISHEntry;
 
-[scriptable, uuid(89caa9f0-8b1c-47fb-b0d3-f0aef0bff749)]
+[scriptable, uuid(a89b80a8-3c44-4a25-9d2c-2fb42358b46e)]
 interface nsIDocShellHistory : nsISupports
 {
   /**
    * Get the SHEntry associated with a child docshell
    */
   nsISHEntry getChildSHEntry(in long aChildOffset);
 
   /**
-   * Add a Child SHEntry for a frameset page
+   * Add a Child SHEntry for a frameset page, given the child's loadtype.
    */
   void addChildSHEntry(in nsISHEntry aCloneReference,
                        in nsISHEntry aHistoryEntry,
-                       in long aChildOffset);
+                       in long aChildOffset,
+                       in unsigned long aLoadType);
 
   /*
    * Whether this docshell should save entries in global history.
    */
   attribute boolean useGlobalHistory;
 };
 
--- a/docshell/shistory/public/nsISHEntry.idl
+++ b/docshell/shistory/public/nsISHEntry.idl
@@ -53,17 +53,17 @@ interface nsISupportsArray;
 %{C++
 struct nsIntRect;
 class nsDocShellEditorData;
 %}
 [ref] native nsIntRect(nsIntRect);
 [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
 
 
-[scriptable, uuid(09fecea6-5453-43ba-bf91-3ff32618f037)]
+[scriptable, uuid(62b0603f-57ca-439e-a0fb-6f6978500755)]
 interface nsISHEntry : nsIHistoryEntry
 {
     /** URI for the document */
     void setURI(in nsIURI aURI);
 
     /** Referrer URI */
     attribute nsIURI referrerURI;
 
@@ -144,16 +144,31 @@ interface nsISHEntry : nsIHistoryEntry
      * attached to the same docshell only if the two entries are entries for
      * the same page in the sense that one could go from the state represented
      * by one to the state represented by the other simply by scrolling (so the
      * entries are separated by an anchor traversal or a subframe navigation in
      * some other frame).
      */
     attribute unsigned long pageIdentifier;
 
+    /**
+     * docIdentifier is an integer that should be the same for two entries
+     * attached to the same docshell if and only if the two entries are entries
+     * for the same document.  In practice, two entries A and B will have the
+     * same docIdentifier if they have the same pageIdentifier or if B was
+     * created by A calling history.pushState().
+     */
+    attribute unsigned long long docIdentifier;
+
+    /**
+     * Changes this entry's doc identifier to a new value which is unique
+     * among those of all other entries.
+     */
+    void setUniqueDocIdentifier();
+
     /** attribute to set and get the cache key for the entry */
     attribute nsISupports cacheKey;
 
     /** attribute to indicate whether layoutHistoryState should be saved */
     attribute boolean saveLayoutStateFlag;
 
     /** attribute to indicate whether the page is already expired in cache */
     attribute boolean expirationStatus;
@@ -188,16 +203,22 @@ interface nsISHEntry : nsIHistoryEntry
     /**
      * Get the owner, if any, that was associated with the channel
      * that the document that was loaded to create this history entry
      * came from.
      */
     attribute nsISupports owner;
 
     /**
+     * Get/set data associated with this history state via a pushState() call,
+     * encoded as JSON.
+     **/
+    attribute AString stateData;
+
+    /**
      * Gets the owning pointer to the editor data assosicated with
      * this shistory entry. This forgets its pointer, so free it when
      * you're done.
      */
     [noscript, notxpcom] nsDocShellEditorDataPtr forgetEditorData();
 
     /**
      * Sets the owning pointer to the editor data assosicated with
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -70,16 +70,17 @@ protected:
   virtual void NotifyExpired(nsSHEntry* aObj) {
     RemoveObject(aObj);
     aObj->Expire();
   }
 };
 
 static HistoryTracker *gHistoryTracker = nsnull;
 static PRUint32 gEntryID = 0;
+static PRUint64 gEntryDocIdentifier = 0;
 
 nsresult nsSHEntry::Startup()
 {
   gHistoryTracker = new HistoryTracker();
   return gHistoryTracker ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 void nsSHEntry::Shutdown()
@@ -99,16 +100,17 @@ static void StopTrackingEntry(nsSHEntry 
 //***    nsSHEntry: Object Management
 //*****************************************************************************
 
 
 nsSHEntry::nsSHEntry() 
   : mLoadType(0)
   , mID(gEntryID++)
   , mPageIdentifier(mID)
+  , mDocIdentifier(gEntryDocIdentifier++)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
   , mIsFrameNavigation(PR_FALSE)
   , mSaveLayoutState(PR_TRUE)
   , mExpired(PR_FALSE)
   , mSticky(PR_TRUE)
   , mParent(nsnull)
   , mViewerBounds(0, 0, 0, 0)
@@ -120,16 +122,17 @@ nsSHEntry::nsSHEntry(const nsSHEntry &ot
   , mReferrerURI(other.mReferrerURI)
   // XXX why not copy mDocument?
   , mTitle(other.mTitle)
   , mPostData(other.mPostData)
   , mLayoutHistoryState(other.mLayoutHistoryState)
   , mLoadType(0)         // XXX why not copy?
   , mID(other.mID)
   , mPageIdentifier(other.mPageIdentifier)
+  , mDocIdentifier(other.mDocIdentifier)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
   , mIsFrameNavigation(other.mIsFrameNavigation)
   , mSaveLayoutState(other.mSaveLayoutState)
   , mExpired(other.mExpired)
   , mSticky(PR_TRUE)
   // XXX why not copy mContentType?
   , mCacheKey(other.mCacheKey)
@@ -388,16 +391,40 @@ NS_IMETHODIMP nsSHEntry::GetPageIdentifi
 }
 
 NS_IMETHODIMP nsSHEntry::SetPageIdentifier(PRUint32 aPageIdentifier)
 {
   mPageIdentifier = aPageIdentifier;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsSHEntry::GetDocIdentifier(PRUint64 * aResult)
+{
+  *aResult = mDocIdentifier;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsSHEntry::SetDocIdentifier(PRUint64 aDocIdentifier)
+{
+  // This ensures that after a session restore, gEntryDocIdentifier is greater
+  // than all SHEntries' docIdentifiers, which ensures that we'll never repeat
+  // a doc identifier.
+  if (aDocIdentifier >= gEntryDocIdentifier)
+    gEntryDocIdentifier = aDocIdentifier + 1;
+
+  mDocIdentifier = aDocIdentifier;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsSHEntry::SetUniqueDocIdentifier()
+{
+  mDocIdentifier = gEntryDocIdentifier++;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsSHEntry::GetIsSubFrame(PRBool * aFlag)
 {
   *aFlag = mIsFrameNavigation;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsSHEntry::SetIsSubFrame(PRBool  aFlag)
 {
@@ -465,17 +492,17 @@ nsSHEntry::Create(nsIURI * aURI, const n
                   nsISupports* aOwner)
 {
   mURI = aURI;
   mTitle = aTitle;
   mPostData = aInputStream;
   mCacheKey = aCacheKey;
   mContentType = aContentType;
   mOwner = aOwner;
-    
+
   // Set the LoadType by default to loadHistory during creation
   mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory;
 
   // By default all entries are set false for subframe flag. 
   // nsDocShell::CloneAndReplace() which creates entries for
   // all subframe navigations, sets the flag to true.
   mIsFrameNavigation = PR_FALSE;
 
@@ -861,8 +888,22 @@ nsSHEntry::SetEditorData(nsDocShellEdito
 }
 
 PRBool
 nsSHEntry::HasDetachedEditor()
 {
   return mEditorData != nsnull;
 }
 
+NS_IMETHODIMP
+nsSHEntry::GetStateData(nsAString &aStateData)
+{
+  aStateData.Assign(mStateData);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetStateData(const nsAString &aDataStr)
+{
+  mStateData.Assign(aDataStr);
+  return NS_OK;
+}
+
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -91,30 +91,32 @@ private:
   nsCOMPtr<nsIURI>                mURI;
   nsCOMPtr<nsIURI>                mReferrerURI;
   nsCOMPtr<nsIContentViewer>      mContentViewer;
   nsCOMPtr<nsIDocument>           mDocument; // document currently being observed
   nsString                        mTitle;
   nsCOMPtr<nsIInputStream>        mPostData;
   nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
   nsCOMArray<nsISHEntry>          mChildren;
-  PRUint32                        mLoadType;  
+  PRUint32                        mLoadType;
   PRUint32                        mID;
   PRUint32                        mPageIdentifier;
+  PRInt64                         mDocIdentifier;
   PRInt32                         mScrollPositionX;
   PRInt32                         mScrollPositionY;
   PRPackedBool                    mIsFrameNavigation;
   PRPackedBool                    mSaveLayoutState;
   PRPackedBool                    mExpired;
   PRPackedBool                    mSticky;
   nsCString                       mContentType;
   nsCOMPtr<nsISupports>           mCacheKey;
   nsISHEntry *                    mParent;  // weak reference
   nsCOMPtr<nsISupports>           mWindowState;
   nsIntRect                       mViewerBounds;
   nsCOMArray<nsIDocShellTreeItem> mChildShells;
   nsCOMPtr<nsISupportsArray>      mRefreshURIList;
   nsCOMPtr<nsISupports>           mOwner;
   nsExpirationState               mExpirationState;
   nsAutoPtr<nsDocShellEditorData> mEditorData;
+  nsString                        mStateData;
 };
 
 #endif /* nsSHEntry_h */
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -473,35 +473,36 @@ nsSHistory::PrintHistory()
     nsCOMPtr<nsISHEntry>  entry;
     rv = txn->GetSHEntry(getter_AddRefs(entry));
     if (NS_FAILED(rv) && !entry)
       return NS_ERROR_FAILURE;
 
     nsCOMPtr<nsILayoutHistoryState> layoutHistoryState;
     nsCOMPtr<nsIURI>  uri;
     nsXPIDLString title;
-              
+
     entry->GetLayoutHistoryState(getter_AddRefs(layoutHistoryState));
     nsCOMPtr<nsIHistoryEntry> hEntry(do_QueryInterface(entry));
     if (hEntry) {
       hEntry->GetURI(getter_AddRefs(uri));
       hEntry->GetTitle(getter_Copies(title));              
     }
 
 #if 0
     nsCAutoString url;
     if (uri)
      uri->GetSpec(url);
 
     printf("**** SH Transaction #%d, Entry = %x\n", index, entry.get());
-    printf("\t\t URL = %s\n", url);
+    printf("\t\t URL = %s\n", url.get());
+
     printf("\t\t Title = %s\n", NS_LossyConvertUTF16toASCII(title).get());
-    printf("\t\t layout History Data = %x\n", layoutHistoryState);
+    printf("\t\t layout History Data = %x\n", layoutHistoryState.get());
 #endif
-      
+
     nsCOMPtr<nsISHTransaction> next;
     rv = txn->GetNext(getter_AddRefs(next));
     if (NS_SUCCEEDED(rv) && next) {
       txn = next;
       index++;
       continue;
     }
     else
@@ -859,17 +860,17 @@ nsSHistory::EvictContentViewersInRange(P
     trans->GetSHEntry(getter_AddRefs(entry));
     nsCOMPtr<nsIContentViewer> viewer;
     nsCOMPtr<nsISHEntry> ownerEntry;
     entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
                                getter_AddRefs(viewer));
     if (viewer) {
       NS_ASSERTION(ownerEntry,
                    "ContentViewer exists but its SHEntry is null");
-#ifdef DEBUG_PAGE_CACHE 
+#ifdef DEBUG_PAGE_CACHE
       nsCOMPtr<nsIURI> uri;
       ownerEntry->GetURI(getter_AddRefs(uri));
       nsCAutoString spec;
       if (uri)
         uri->GetSpec(spec);
 
       printf("per SHistory limit: evicting content viewer: %s\n", spec.get());
 #endif
@@ -1144,33 +1145,33 @@ NS_IMETHODIMP
 nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
 {
   nsCOMPtr<nsIDocShell> docShell;
   nsCOMPtr<nsISHEntry> shEntry;
   // Keep note of requested history index in mRequestedIndex.
   mRequestedIndex = aIndex;
 
   nsCOMPtr<nsISHEntry> prevEntry;
-  GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(prevEntry));  
-   
-  nsCOMPtr<nsISHEntry> nextEntry;   
+  GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(prevEntry));
+
+  nsCOMPtr<nsISHEntry> nextEntry;
   GetEntryAtIndex(mRequestedIndex, PR_FALSE, getter_AddRefs(nextEntry));
   nsCOMPtr<nsIHistoryEntry> nHEntry(do_QueryInterface(nextEntry));
-  if (!nextEntry || !prevEntry || !nHEntry) {    
+  if (!nextEntry || !prevEntry || !nHEntry) {
     mRequestedIndex = -1;
     return NS_ERROR_FAILURE;
   }
-  
+
   // Send appropriate listener notifications
   PRBool canNavigate = PR_TRUE;
   // Get the uri for the entry we are about to visit
   nsCOMPtr<nsIURI> nextURI;
   nHEntry->GetURI(getter_AddRefs(nextURI));
- 
-  if(mListener) {    
+
+  if(mListener) {
     nsCOMPtr<nsISHistoryListener> listener(do_QueryReferent(mListener));
     if (listener) {
       if (aHistCmd == HIST_CMD_BACK) {
         // We are going back one entry. Send GoBack notifications
         listener->OnHistoryGoBack(nextURI, &canNavigate);
       }
       else if (aHistCmd == HIST_CMD_FORWARD) {
         // We are going forward. Send GoForward notification
@@ -1217,31 +1218,28 @@ nsSHistory::LoadEntry(PRInt32 aIndex, lo
         mRequestedIndex = -1;
         return NS_ERROR_FAILURE; 
       }
       return rv;
     }   // (pCount >0)
     else
       docShell = mRootDocShell;
     }
-  
 
   if (!docShell) {
     // we did not successfully go to the proper index.
     // return error.
     mRequestedIndex = -1;
     return NS_ERROR_FAILURE;
   }
 
   // Start the load on the appropriate docshell
   return InitiateLoad(nextEntry, docShell, aLoadType);
 }
 
-
-
 nsresult
 nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound)
 {
   if (!aPrevEntry || !aNextEntry || !aParent)
     return PR_FALSE;
 
   nsresult result = NS_OK;
   PRUint32 prevID, nextID;
--- a/docshell/shistory/src/nsSHistory.h
+++ b/docshell/shistory/src/nsSHistory.h
@@ -61,17 +61,17 @@ class nsIDocShell;
 class nsSHEnumerator;
 class nsSHistoryObserver;
 class nsSHistory: public PRCList,
                   public nsISHistory,
                   public nsISHistoryInternal,
                   public nsIWebNavigation
 {
 public:
-	nsSHistory();
+  nsSHistory();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISHISTORY
   NS_DECL_NSISHISTORYINTERNAL
   NS_DECL_NSIWEBNAVIGATION
 
   // One time initialization method called upon docshell module construction
   static nsresult Startup();
@@ -89,17 +89,17 @@ protected:
 
    // Could become part of nsIWebNavigation
    NS_IMETHOD GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsISHEntry** aResult);
    NS_IMETHOD GetTransactionAtIndex(PRInt32 aIndex, nsISHTransaction ** aResult);
    nsresult CompareFrames(nsISHEntry * prevEntry, nsISHEntry * nextEntry, nsIDocShell * rootDocShell, long aLoadType, PRBool * aIsFrameFound);
    nsresult InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType);
 
    NS_IMETHOD LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 histCmd);
-	
+
 #ifdef DEBUG
    nsresult PrintHistory();
 #endif
 
   // Evict the viewers at indices between aStartIndex and aEndIndex,
   // including aStartIndex but not aEndIndex.
   void EvictContentViewersInRange(PRInt32 aStartIndex, PRInt32 aEndIndex);
   void EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex);
--- a/docshell/test/navigation/blank.html
+++ b/docshell/test/navigation/blank.html
@@ -1,1 +1,1 @@
-<html><body>This is a blank document.</body></html>
+<html><body>This is a blank document.</body></html>
\ No newline at end of file
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -77,16 +77,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOM3Document.h"
 #include "nsIDOMXMLDocument.h"
 #include "nsIDOMNSDocument.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMEventListener.h"
+#include "nsIDOMPopStateEvent.h"
 #include "nsContentUtils.h"
 #include "nsDOMWindowUtils.h"
 
 // Window scriptable helper includes
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIScriptExternalNameSet.h"
@@ -1325,23 +1326,25 @@ static nsDOMClassInfoData sClassInfoData
 
   NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PaintRequestList, nsPaintRequestListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(PopStateEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TransitionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 };
 
-// Objects that shuld be constructable through |new Name();|
+// Objects that should be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
   const char *mContractID;
 };
 
 #define NS_DEFINE_CONSTRUCTOR_DATA(_class, _contract_id)                      \
   { eDOMClassInfo_##_class##_id, _contract_id },
@@ -1415,16 +1418,17 @@ jsval nsDOMClassInfo::sOnkeypress_id    
 jsval nsDOMClassInfo::sOnmousemove_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnfocus_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnblur_id          = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnsubmit_id        = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnreset_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnchange_id        = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnselect_id        = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnload_id          = JSVAL_VOID;
+jsval nsDOMClassInfo::sOnpopstate_id      = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnbeforeunload_id  = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnunload_id        = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnhashchange_id    = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnpageshow_id      = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnpagehide_id      = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnabort_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnerror_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnpaint_id         = JSVAL_VOID;
@@ -1609,16 +1613,17 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
   SET_JSVAL_TO_STRING(sOnmousemove_id,     cx, "onmousemove");
   SET_JSVAL_TO_STRING(sOnfocus_id,         cx, "onfocus");
   SET_JSVAL_TO_STRING(sOnblur_id,          cx, "onblur");
   SET_JSVAL_TO_STRING(sOnsubmit_id,        cx, "onsubmit");
   SET_JSVAL_TO_STRING(sOnreset_id,         cx, "onreset");
   SET_JSVAL_TO_STRING(sOnchange_id,        cx, "onchange");
   SET_JSVAL_TO_STRING(sOnselect_id,        cx, "onselect");
   SET_JSVAL_TO_STRING(sOnload_id,          cx, "onload");
+  SET_JSVAL_TO_STRING(sOnpopstate_id,      cx, "onpopstate");
   SET_JSVAL_TO_STRING(sOnbeforeunload_id,  cx, "onbeforeunload");
   SET_JSVAL_TO_STRING(sOnunload_id,        cx, "onunload");
   SET_JSVAL_TO_STRING(sOnhashchange_id,    cx, "onhashchange");
   SET_JSVAL_TO_STRING(sOnpageshow_id,      cx, "onpageshow");
   SET_JSVAL_TO_STRING(sOnpagehide_id,      cx, "onpagehide");
   SET_JSVAL_TO_STRING(sOnabort_id,         cx, "onabort");
   SET_JSVAL_TO_STRING(sOnerror_id,         cx, "onerror");
   SET_JSVAL_TO_STRING(sOnpaint_id,         cx, "onpaint");
@@ -2227,16 +2232,21 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(DragEvent, nsIDOMDragEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDragEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMouseEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSMouseEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(PopStateEvent, nsIDOMPopStateEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMPopStateEvent)
+    DOM_CLASSINFO_EVENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLDocument)
     DOM_CLASSINFO_DOCUMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLOptionsCollection, nsIDOMHTMLOptionsCollection)
     // Order is significant.  nsIDOMHTMLOptionsCollection.length shadows
@@ -7322,17 +7332,18 @@ nsEventReceiverSH::ReallyIsEventName(jsv
   case 'h' :
     return id == sOnhashchange_id;
   case 'l' :
     return id == sOnload_id;
   case 'p' :
     return (id == sOnpaint_id        ||
             id == sOnpageshow_id     ||
             id == sOnpagehide_id     ||
-            id == sOnpaste_id);
+            id == sOnpaste_id        ||
+            id == sOnpopstate_id);
   case 'k' :
     return (id == sOnkeydown_id      ||
             id == sOnkeypress_id     ||
             id == sOnkeyup_id);
   case 'u' :
     return id == sOnunload_id;
   case 'm' :
     return (id == sOnmousemove_id    ||
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -322,16 +322,17 @@ protected:
   static jsval sOnmousemove_id;
   static jsval sOnfocus_id;
   static jsval sOnblur_id;
   static jsval sOnsubmit_id;
   static jsval sOnreset_id;
   static jsval sOnchange_id;
   static jsval sOnselect_id;
   static jsval sOnload_id;
+  static jsval sOnpopstate_id;
   static jsval sOnbeforeunload_id;
   static jsval sOnunload_id;
   static jsval sOnhashchange_id;
   static jsval sOnpageshow_id;
   static jsval sOnpagehide_id;
   static jsval sOnabort_id;
   static jsval sOnerror_id;
   static jsval sOnpaint_id;
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -468,16 +468,17 @@ enum nsDOMClassInfoID {
   eDOMClassInfo_WebGLShader_id,
   eDOMClassInfo_WebGLFramebuffer_id,
   eDOMClassInfo_WebGLRenderbuffer_id,
 
   eDOMClassInfo_PaintRequest_id,
   eDOMClassInfo_PaintRequestList_id,
 
   eDOMClassInfo_ScrollAreaEvent_id,
+  eDOMClassInfo_PopStateEvent_id,
 
   eDOMClassInfo_EventListenerInfo_id,
 
   eDOMClassInfo_TransitionEvent_id,
 
   // This one better be the last one in this list
   eDOMClassInfoIDCount
 };
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -74,16 +74,17 @@
 #include "nsPluginArray.h"
 #include "nsIPluginHost.h"
 #include "nsGeolocation.h"
 #include "nsContentCID.h"
 #include "nsLayoutStatics.h"
 #include "nsCycleCollector.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsDOMThreadService.h"
+#include "nsAutoJSValHolder.h"
 
 // Interfaces Needed
 #include "nsIFrame.h"
 #include "nsCanvasFrame.h"
 #include "nsIWidget.h"
 #include "nsIBaseWindow.h"
 #include "nsIAccelerometer.h"
 #include "nsWidgetsCID.h"
@@ -107,16 +108,17 @@
 #include "nsIDOMElement.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMessageEvent.h"
 #include "nsIDOMPopupBlockedEvent.h"
+#include "nsIDOMPopStateEvent.h"
 #include "nsIDOMOfflineResourceList.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsPIDOMStorage.h"
 #include "nsDOMString.h"
 #include "nsIEmbeddingSiteWindow2.h"
 #include "nsThreadUtils.h"
 #include "nsIEventStateManager.h"
 #include "nsIHttpProtocolHandler.h"
@@ -164,16 +166,17 @@
 #include "nsCSSProps.h"
 #include "nsIURIFixup.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsEventDispatcher.h"
 #include "nsIObserverService.h"
 #include "nsIXULAppInfo.h"
 #include "nsNetUtil.h"
 #include "nsFocusManager.h"
+#include "nsIJSON.h"
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #include "nsIDOMXULControlElement.h"
 #include "nsIFrame.h"
 #endif
 
 #include "plbase64.h"
 
@@ -356,16 +359,18 @@ static PRBool               gDOMWindowDu
 // CIDs
 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
 
 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 
 static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
 static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
 
+static const char sPopStatePrefStr[] = "browser.history.allowPopState";
+
 static PRBool
 IsAboutBlank(nsIURI* aURI)
 {
   NS_PRECONDITION(aURI, "Must have URI");
     
   // GetSpec can be expensive for some URIs, so check the scheme first.
   PRBool isAbout = PR_FALSE;
   if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
@@ -650,19 +655,19 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mIsChrome(PR_FALSE),
     mNeedsFocus(PR_TRUE),
     mHasFocus(PR_FALSE),
     mHasAcceleration(PR_FALSE),
     mTimeoutInsertionPoint(nsnull),
     mTimeoutPublicIdCounter(1),
     mTimeoutFiringDepth(0),
     mJSObject(nsnull),
+    mPendingStorageEventsObsolete(nsnull),
     mTimeoutsSuspendDepth(0),
-    mFocusMethod(0),
-    mPendingStorageEventsObsolete(nsnull)
+    mFocusMethod(0)
 #ifdef DEBUG
     , mSetOpenerWindowCalled(PR_FALSE)
 #endif
 {
   memset(mScriptGlobals, 0, sizeof(mScriptGlobals));
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
@@ -6973,26 +6978,138 @@ nsresult
 nsGlobalWindow::DispatchSyncHashchange()
 {
   FORWARD_TO_INNER(DispatchSyncHashchange, (), NS_OK);
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
                "Must be safe to run script here.");
 
   // Don't do anything if the window is frozen.
   if (IsFrozen())
-      return NS_OK;
+    return NS_OK;
 
   // Dispatch the hashchange event, which doesn't bubble and isn't cancelable,
   // to the outer window.
   return nsContentUtils::DispatchTrustedEvent(mDoc, GetOuterWindow(),
                                               NS_LITERAL_STRING("hashchange"),
                                               PR_FALSE, PR_FALSE);
 }
 
-// Find an nsCanvasFrame under aFrame.  Only search the principal
+nsresult
+nsGlobalWindow::DispatchSyncPopState()
+{
+  FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
+
+  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
+               "Must be safe to run script here.");
+
+  // Check that PopState hasn't been pref'ed off.
+  if (!nsContentUtils::GetBoolPref(sPopStatePrefStr, PR_FALSE))
+    return NS_OK;
+
+  nsresult rv = NS_OK;
+
+  // Bail if the window is frozen.
+  if (IsFrozen()) {
+    return NS_OK;
+  }
+
+  // Bail if there's no document or the document's readystate isn't "complete".
+  if (!mDoc) {
+    return NS_OK;
+  }
+
+  nsIDocument::ReadyState readyState = mDoc->GetReadyStateEnum();
+  if (readyState != nsIDocument::READYSTATE_COMPLETE) {
+    return NS_OK;
+  }
+
+  // Get the document's pending state object -- it contains the data we're
+  // going to send along with the popstate event.  The object is serialized as
+  // JSON.
+  nsAString& stateObjJSON = mDoc->GetPendingStateObject();
+
+  nsCOMPtr<nsIVariant> stateObj;
+  // Parse the JSON, if there's any to parse.
+  if (!stateObjJSON.IsEmpty()) {
+    // Get the JSContext associated with our document. We need this for
+    // deserialization.
+    nsCOMPtr<nsIDocument> document = do_QueryInterface(mDocument);
+    NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
+
+    // Get the JSContext from the document, like we do in
+    // nsContentUtils::GetContextFromDocument().
+    nsIScriptGlobalObject *sgo = document->GetScopeObject();
+    NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
+
+    nsIScriptContext *scx = sgo->GetContext();
+    NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
+
+    JSContext *cx = (JSContext*) scx->GetNativeContext();
+
+    // If our json call triggers a JS-to-C++ call, we want that call to use cx
+    // as the context.  So we push cx onto the context stack.
+    nsCxPusher cxPusher;
+
+    jsval jsStateObj = JSVAL_NULL;
+    // Root the container which will hold our decoded state object.
+    nsAutoGCRoot(&jsStateObj, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Deserialize the state object into an nsIVariant.
+    nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
+    NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE);
+    rv = json->DecodeToJSVal(stateObjJSON, cx, &jsStateObj);
+    NS_ENSURE_SUCCESS(rv, rv);
+    cxPusher.Pop();
+
+    nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
+    NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
+    rv = xpconnect->JSValToVariant(cx, &jsStateObj, getter_AddRefs(stateObj));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Obtain a presentation shell for use in creating a popstate event.
+  nsIPresShell *shell = mDoc->GetPrimaryShell();
+  nsCOMPtr<nsPresContext> presContext;
+  if (shell) {
+    presContext = shell->GetPresContext();
+  }
+
+  // Create a new popstate event
+  nsCOMPtr<nsIDOMEvent> domEvent;
+  rv = nsEventDispatcher::CreateEvent(presContext, nsnull,
+                                      NS_LITERAL_STRING("popstateevent"),
+                                      getter_AddRefs(domEvent));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
+  NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
+
+  // Initialize the popstate event, which does bubble but isn't cancellable.
+  nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
+  rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
+                                        PR_TRUE, PR_FALSE,
+                                        stateObj);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = privateEvent->SetTrusted(PR_TRUE);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIDOMEventTarget> outerWindow =
+    do_QueryInterface(GetOuterWindow());
+  NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
+
+  rv = privateEvent->SetTarget(outerWindow);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRBool dummy; // default action
+  return DispatchEvent(popstateEvent, &dummy);
+}
+
+// Find an nsICanvasFrame under aFrame.  Only search the principal
 // child lists.  aFrame must be non-null.
 static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
 {
     nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
     if (canvasFrame) {
         return canvasFrame;
     }
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -443,16 +443,18 @@ public:
   virtual NS_HIDDEN_(void)
     CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
                              nsScriptObjectHolder& aHandler);
 
   virtual PRBool TakeFocus(PRBool aFocus, PRUint32 aFocusMethod);
   virtual void SetReadyForFocus();
   virtual void PageHidden();
   virtual nsresult DispatchSyncHashchange();
+  virtual nsresult DispatchSyncPopState();
+
   virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
 
   static PRBool DOMWindowDumpEnabled();
 
 protected:
   // Object Management
   virtual ~nsGlobalWindow();
   void CleanUp();
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -52,16 +52,23 @@
 #include "nsIHistoryEntry.h"
 #include "nsIURI.h"
 #include "nsIServiceManager.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsContentUtils.h"
+#include "nsIDOMNSDocument.h"
+#include "nsISHistoryInternal.h"
+
+static const char* sAllowPushStatePrefStr  =
+  "browser.history.allowPushState";
+static const char* sAllowReplaceStatePrefStr =
+  "browser.history.allowReplaceState";
 
 //
 //  History class implementation 
 //
 nsHistory::nsHistory(nsIDocShell* aDocShell) : mDocShell(aDocShell)
 {
 }
 
@@ -253,31 +260,72 @@ nsHistory::Go(PRInt32 aDelta)
   NS_ENSURE_TRUE(session_history, NS_ERROR_FAILURE);
 
   // QI SHistory to nsIWebNavigation
   nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history));
   NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
 
   PRInt32 curIndex=-1;
   PRInt32 len = 0;
-  nsresult rv = session_history->GetIndex(&curIndex);  
+  nsresult rv = session_history->GetIndex(&curIndex);
   rv = session_history->GetCount(&len);
 
   PRInt32 index = curIndex + aDelta;
   if (index > -1  &&  index < len)
     webnav->GotoIndex(index);
 
   // We always want to return a NS_OK, since returning errors 
   // from GotoIndex() can lead to exceptions and a possible leak
   // of history length
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle,
+                     const nsAString& aURL)
+{
+  // Check that PushState hasn't been pref'ed off.
+  if (!nsContentUtils::GetBoolPref(sAllowPushStatePrefStr, PR_FALSE))
+    return NS_OK;
+
+  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
+
+  // AddState might run scripts, so we need to hold a strong reference to the
+  // docShell here to keep it from going away.
+  nsCOMPtr<nsIDocShell> docShell = mDocShell;
+
+  // PR_FALSE tells the docshell to add a new history entry instead of
+  // modifying the current one.
+  nsresult rv = mDocShell->AddState(aData, aTitle, aURL, PR_FALSE);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHistory::ReplaceState(nsIVariant *aData, const nsAString& aTitle,
+                        const nsAString& aURL)
+{
+  // Check that ReplaceState hasn't been pref'ed off
+  if (!nsContentUtils::GetBoolPref(sAllowReplaceStatePrefStr, PR_FALSE))
+    return NS_OK;
+
+  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
+
+  // As in PushState(), we need to keep a strong reference to the docShell
+  // here.
+  nsCOMPtr<nsIDocShell> docShell = mDocShell;
+
+  // PR_TRUE tells the docshell to modify the current SHEntry, rather than
+  // create a new one.
+  return mDocShell->AddState(aData, aTitle, aURL, PR_TRUE);
+}
+
+NS_IMETHODIMP
 nsHistory::Item(PRUint32 aIndex, nsAString& aReturn)
 {
   aReturn.Truncate();
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsISHistory>  session_history;
 
   GetSessionHistoryFromDocShell(mDocShell, getter_AddRefs(session_history));
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -189,17 +189,16 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDo
     return NS_ERROR_FAILURE;
 
   JSContext *cx;
 
   if (NS_FAILED(GetContextFromStack(stack, &cx)))
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsISupports> owner;
-  nsCOMPtr<nsIURI> sourceURI;
 
   if (cx) {
     // No cx means that there's no JS running, or at least no JS that
     // was run through code that properly pushed a context onto the
     // context stack (as all code that runs JS off of web pages
     // does). We won't bother with security checks in this case, but
     // we need to create the loadinfo etc.
 
@@ -217,30 +216,31 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDo
       return result;
 
     // Now get the principal to use when loading the URI
     nsCOMPtr<nsIPrincipal> principal;
     if (NS_FAILED(secMan->GetSubjectPrincipal(getter_AddRefs(principal))) ||
         !principal)
       return NS_ERROR_FAILURE;
     owner = do_QueryInterface(principal);
-    principal->GetURI(getter_AddRefs(sourceURI));
   }
 
   // Create load info
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
 
   loadInfo->SetOwner(owner);
 
-  // now set the referrer on the loadinfo
-  if (sourceURI) {
+  // Now set the referrer on the loadinfo.  We need to do this in order to get
+  // the correct referrer URI from a document which was pushStated.
+  nsCOMPtr<nsIURI> sourceURI;
+  result = GetURI(getter_AddRefs(sourceURI));
+  if (NS_SUCCEEDED(result))
     loadInfo->SetReferrer(sourceURI);
-  }
 
   loadInfo.swap(*aLoadInfo);
 
   return NS_OK;
 }
 
 nsresult
 nsLocation::GetURI(nsIURI** aURI, PRBool aGetInnermostURI)
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -456,16 +456,20 @@ public:
    */
   virtual void PageHidden() = 0;
 
   /**
    * Instructs this window to synchronously dispatch a hashchange event.
    */
   virtual nsresult DispatchSyncHashchange() = 0;
 
+  /**
+   * Instructs this window to synchronously dispatch a popState event.
+   */
+  virtual nsresult DispatchSyncPopState() = 0;
 
   /**
    * Tell this window that there is an observer for orientation changes
    */
   virtual void SetHasOrientationEventListener() = 0;
 
   /**
    * Set a arguments for this window. This will be set on the window
--- a/dom/interfaces/base/nsIDOMHistory.idl
+++ b/dom/interfaces/base/nsIDOMHistory.idl
@@ -34,22 +34,30 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(896d1d20-b4c4-11d2-bd93-00805f8ae3f4)]
+interface nsIVariant;
+
+[scriptable, uuid(208f2af7-9f2e-497c-8a53-9e7803280898)]
 interface nsIDOMHistory : nsISupports
 {
   readonly attribute long             length;
   readonly attribute DOMString        current;
   readonly attribute DOMString        previous;
   readonly attribute DOMString        next;
 
   void                       back();
   void                       forward();
 
   void                       go([optional] in long aDelta);
   DOMString                  item(in unsigned long index);
+  void                       pushState(in nsIVariant aData,
+                                       in DOMString aTitle,
+                                       [optional] in DOMString aURL);
+  void                       replaceState(in nsIVariant aData,
+                                          in DOMString aTitle,
+                                          [optional] in DOMString aURL);
 };
--- a/dom/interfaces/events/Makefile.in
+++ b/dom/interfaces/events/Makefile.in
@@ -78,11 +78,12 @@ XPIDLSRCS =					\
 	nsIDOMNotifyPaintEvent.idl              \
 	nsIDOMPaintRequest.idl			\
 	nsIDOMPaintRequestList.idl		\
 	nsIDOMSimpleGestureEvent.idl		\
 	nsIDOMNSMouseEvent.idl			\
 	nsIDOMOrientationEvent.idl              \
 	nsIDOMScrollAreaEvent.idl		\
 	nsIDOMTransitionEvent.idl		\
+	nsIDOMPopStateEvent.idl			\
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/events/nsIDOMPopStateEvent.idl
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * 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 ***** */
+
+#include "nsIDOMEvent.idl"
+
+interface nsIVariant;
+
+[scriptable, uuid(f3834fd5-0ef5-4ccd-a741-0b6685414342)]
+interface nsIDOMPopStateEvent : nsIDOMEvent
+{
+  /**
+   * The state associated with this popstate event
+   */
+  readonly attribute nsIVariant state;
+
+  void initPopStateEvent(in DOMString typeArg,
+                         in boolean canBubbleArg,
+                         in boolean cancelableArg,
+                         in nsIVariant stateArg);
+};
--- a/dom/interfaces/json/nsIJSON.idl
+++ b/dom/interfaces/json/nsIJSON.idl
@@ -37,26 +37,39 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIInputStream;
 interface nsIOutputStream;
 interface nsIScriptGlobalObject;
 
+%{ C++
+#include "jspubtd.h"
+%}
+
+      native JSVal(jsval);
+[ptr] native JSValPtr(jsval);
+[ptr] native JSContext(JSContext);
+
 /**
  * Encode and decode JSON text.
  */
-[scriptable, uuid(45464c36-efde-4cb5-8e00-07480533ff35)]
+[scriptable, uuid(6fcf09ee-87d0-42ec-a72a-8d60114e974f)]
 interface nsIJSON : nsISupports
 {
   AString encode(/* in JSObject value */);
 
   void encodeToStream(in nsIOutputStream stream,
                       in string charset,
                       in boolean writeBOM
                       /* in JSObject value */);
 
   void /* JSObject */ decode(in AString str);
 
   void /* JSObject */ decodeFromStream(in nsIInputStream stream,
                                        in long contentLength);
+
+  [noscript] AString  encodeFromJSVal(in JSValPtr value, in JSContext cx);
+
+  // Make sure you GCroot the result of this function before using it.
+  [noscript] JSVal    decodeToJSVal(in AString str, in JSContext cx);
 };
--- a/dom/locales/en-US/chrome/plugins.properties
+++ b/dom/locales/en-US/chrome/plugins.properties
@@ -7,11 +7,10 @@ installedplugins_label=Installed plugins
 nopluginsareenabled_label=No enabled plugins found
 findmore_label=Find more information about browser plugins at
 installhelp_label=Help for installing plugins is available from
 file_label=File:
 version_label=Version:
 mimetype_label=MIME Type
 description_label=Description
 suffixes_label=Suffixes
-enabled_label=Enabled
 yes_label=Yes
 no_label=No
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -230,16 +230,20 @@ wrap_gtk_plug_embedded(GtkPlug* plug) {
 }
 #endif
 
 bool
 PluginModuleChild::InitGraphics()
 {
     // FIXME/cjones: is this the place for this?
 #if defined(MOZ_WIDGET_GTK2)
+    // Work around plugins that don't interact well with GDK
+    // client-side windows.
+    PR_SetEnv("GDK_NATIVE_WINDOWS=1");
+
     gtk_init(0, 0);
 
     // GtkPlug is a static class so will leak anyway but this ref makes sure.
     gpointer gtk_plug_class = g_type_class_ref(GTK_TYPE_PLUG);
 
     // The dispose method is a good place to hook into the destruction process
     // because the reference count should be 1 the last time dispose is
     // called.  (Toggle references wouldn't detect if the reference count
--- a/dom/plugins/PluginModuleParent.cpp
+++ b/dom/plugins/PluginModuleParent.cpp
@@ -144,16 +144,18 @@ PluginModuleParent::WriteExtraDataForMin
     if (filePos == std::string::npos)
         filePos = 0;
     else
         filePos++;
     WriteExtraDataEntry(stream, "PluginFilename",
                         pluginFile.substr(filePos).c_str());
     //TODO: add plugin name and version: bug 539841
     // (as PluginName, PluginVersion)
+    WriteExtraDataEntry(stream, "PluginName", "");
+    WriteExtraDataEntry(stream, "PluginVersion", "");
     stream->Close();
 }
 
 void
 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
 {
     switch (why) {
     case AbnormalShutdown: {
--- a/dom/src/json/Makefile.in
+++ b/dom/src/json/Makefile.in
@@ -46,16 +46,19 @@ MODULE         = dom
 LIBRARY_NAME   = json_s
 LIBXUL_LIBRARY = 1
 
 
 CPPSRCS =                      \
        nsJSON.cpp              \
        $(NULL)
 
+EXPORTS = nsJSON.h \
+          $(NULL)
+
 FORCE_STATIC_LIB = 1
 
 LOCAL_INCLUDES = \
 		-I$(srcdir)/../base \
 		-I$(topsrcdir)/content/events/src
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -190,16 +190,37 @@ WriteCallback(const jschar *buf, uint32 
   nsJSONWriter *writer = static_cast<nsJSONWriter*>(data);
   nsresult rv =  writer->Write((const PRUnichar*)buf, (PRUint32)len);
   if (NS_FAILED(rv))
     return JS_FALSE;
 
   return JS_TRUE;
 }
 
+NS_IMETHODIMP
+nsJSON::EncodeFromJSVal(jsval *value, JSContext *cx, nsAString &result)
+{
+  result.Truncate();
+
+  // Begin a new request
+  JSAutoRequest ar(cx);
+
+  nsJSONWriter writer;
+  JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL,
+                           WriteCallback, &writer);
+  if (!ok) {
+    return NS_ERROR_XPC_BAD_CONVERT_JS;
+  }
+
+  NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED);
+  writer.FlushBuffer();
+  result.Assign(writer.mOutputString);
+  return NS_OK;
+}
+
 nsresult
 nsJSON::EncodeInternal(nsJSONWriter *writer)
 {
   nsresult rv;
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   if (!xpc)
     return NS_ERROR_FAILURE;
 
@@ -377,16 +398,40 @@ nsJSON::Decode(const nsAString& json)
 }
 
 NS_IMETHODIMP
 nsJSON::DecodeFromStream(nsIInputStream *aStream, PRInt32 aContentLength)
 {
   return DecodeInternal(aStream, aContentLength, PR_TRUE);
 }
 
+NS_IMETHODIMP
+nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx, jsval *result)
+{
+  JSAutoRequest ar(cx);
+
+  JSONParser *parser = JS_BeginJSONParse(cx, result);
+  NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
+
+  JSBool ok = JS_ConsumeJSONText(cx, parser,
+                                 (jschar*)PromiseFlatString(str).get(),
+                                 (uint32)str.Length());
+
+  // Since we've called JS_BeginJSONParse, we have to call JS_FinishJSONParse,
+  // even if JS_ConsumeJSONText fails.  But if either fails, we'll report an
+  // error.
+  ok = ok && JS_FinishJSONParse(cx, parser, JSVAL_NULL);
+
+  if (!ok) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
 nsresult
 nsJSON::DecodeInternal(nsIInputStream *aStream,
                        PRInt32 aContentLength,
                        PRBool aNeedsConverter)
 {
   nsresult rv;
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   if (!xpc)
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -545,32 +545,32 @@ NS_NewDOMStorage2(nsISupports* aOuter, R
     return NS_ERROR_OUT_OF_MEMORY;
 
   return storage->QueryInterface(aIID, aResult);
 }
 
 nsDOMStorage::nsDOMStorage()
   : mUseDB(PR_FALSE)
   , mSessionOnly(PR_TRUE)
+  , mStorageType(nsPIDOMStorage::Unknown)
   , mItemsCached(PR_FALSE)
-  , mStorageType(nsPIDOMStorage::Unknown)
   , mEventBroadcaster(nsnull)
 {
   mSecurityChecker = this;
   mItems.Init(8);
   if (nsDOMStorageManager::gStorageManager)
     nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
 }
 
 nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
   : mUseDB(PR_FALSE) // Any clone is not using the database
+  , mDomain(aThat.mDomain)
   , mSessionOnly(PR_TRUE)
+  , mStorageType(aThat.mStorageType)
   , mItemsCached(PR_FALSE)
-  , mDomain(aThat.mDomain)
-  , mStorageType(aThat.mStorageType)
 #ifdef MOZ_STORAGE
   , mScopeDBKey(aThat.mScopeDBKey)
 #endif
   , mEventBroadcaster(nsnull)
 {
   mSecurityChecker = this;
   mItems.Init(8);
 
--- a/dom/tests/mochitest/whatwg/Makefile.in
+++ b/dom/tests/mochitest/whatwg/Makefile.in
@@ -72,16 +72,19 @@ include $(topsrcdir)/config/rules.mk
 		test_postMessage_origin.xhtml \
 		postMessage_origin_helper.xhtml \
 		test_postMessage_closed.html \
 		postMessage_closed_helper.html \
 		test_postMessage_jar.html \
 		postMessage.jar \
 		postMessage.jar^headers^ \
 		test_bug477323.html \
+		test_bug500328.html \
+		file_bug500328_1.html \
+		file_bug500328_2.html \
 		$(NULL)
 
 _CHROME_FILES	= \
 		test_postMessage_chrome.html \
 		$(NULL)		
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/file_bug500328_1.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Inner frame for testing bug 500328.
+https://bugzilla.mozilla.org/show_bug.cgi?id=500328
+-->
+<head>
+<title>test 1</title>
+</head>
+<body onload="load();" onpopstate="popstate(event);">
+<script type="application/javascript">
+  function load() {
+    if(parent && parent.onChildLoad)
+      parent.onChildLoad();
+    if(opener && opener.onChildLoad)
+      opener.onChildLoad();
+  }
+
+  function popstate(e) {
+    if(parent && parent.onChildLoad)
+      parent.onChildPopState(e);
+    if(opener && opener.onChildLoad)
+      opener.onChildPopState(e);
+  }
+
+  function navigateTo(loc) {
+    location = loc;
+  }
+</script>
+
+<a id="link-anchor1", href="#1">Link Anchor1</a>
+<a id="link-self" href="file_bug500328_1.html">Self</a>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/file_bug500328_2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Inner frame for testing bug 500328.
+https://bugzilla.mozilla.org/show_bug.cgi?id=500328
+-->
+<head>
+</head>
+<body>
+<!--
+ Yes, this page is basically blank.  But no, about:blank wouldn't do as a
+ replacement, because we use this page to test that pushstate has correct
+ same-origin checks.
+-->
+file_bug500328_2.html
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_bug500328.html
@@ -0,0 +1,740 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=500328
+-->
+<head>
+  <title>Test for Bug 500328</title>
+  <script type="application/javascript" src="/MochiKit/packed.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=500328">Mozilla Bug 500328</a>
+<p id="display"></p>
+<div id="status"></div>
+<div id="content">
+  <iframe id="iframe"></iframe>
+  <iframe id="iframe2"></iframe>
+  <a id="link">link</a>
+</div>
+<pre id="test">
+<script type="application/javascript;version=1.7">
+
+/** Test for Bug 500328 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var iframe = document.getElementById("iframe");
+var iframeCw = iframe.contentWindow;
+
+var iframe2 = document.getElementById("iframe2");
+var iframe2Cw = iframe2.contentWindow;
+
+var unvisitedColor;
+var visitedColor;
+
+var gCallbackOnIframeLoad = false;
+var gCallbackOnPopState = false;
+var gNumPopStates = 0;
+var gLastPopStateEvent;
+
+var gGen;
+
+function statusMsg(msg) {
+  var msgElem = document.createElement("p");
+  msgElem.appendChild(document.createTextNode(msg));
+
+  document.getElementById("status").appendChild(msgElem);
+}
+
+function longWait() {
+  setTimeout(function() { gGen.next(); }, 1000);
+}
+
+function shortWait() {
+  setTimeout(function() { gGen.next(); }, 0);
+}
+
+function onChildPopState(e) {
+  gNumPopStates++;
+  gLastPopStateEvent = e;
+  if (gCallbackOnPopState) {
+    statusMsg("Popstate(" + JSON.stringify(e.state) + ").  Calling gGen.next().");
+    gCallbackOnPopState = false;
+    gGen.next();
+  }
+  else {
+    statusMsg("Popstate(" + JSON.stringify(e.state) + ").  NOT calling gGen.next().");
+  }
+}
+
+function onChildLoad() {
+  if(gCallbackOnIframeLoad) {
+    statusMsg("Got load.  About to call gGen.next().");
+    gCallbackOnIframeLoad = false;
+    gGen.next();
+  }
+  else {
+    statusMsg("Got load, but not calling gGen.next() because gCallbackOnIframeLoad was false.");
+  }
+}
+
+function enableChildLoadCallback() {
+  gCallbackOnIframeLoad = true;
+}
+
+function enableChildPopStateCallback() {
+  gCallbackOnPopState = true;
+}
+
+function clearPopStateCounter() {
+  gNumPopStates = 0;
+}
+
+function noPopStateExpected(msg) {
+  is(gNumPopStates, 0, msg);
+
+  // Even if there's an error, set gNumPopStates to 0 so other tests don't
+  // fail.
+  gNumPopStates = 0;
+}
+
+function popstateExpected(msg) {
+  is(gNumPopStates, 1, msg);
+  gNumPopStates = 0;
+}
+
+function getColor(elem) {
+  return document.defaultView.getComputedStyle(elem, "").color;
+}
+
+function getSHistory(theWindow)
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  const Ci = Components.interfaces;
+  var sh = theWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIWebNavigation)
+                    .sessionHistory;
+  if (!sh || sh == null)
+    throw("Couldn't get shistory for window!");
+
+  return sh;
+}
+
+function getChromeWin(theWindow)
+{
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+ const Ci = Components.interfaces;
+ return theWindow
+           .QueryInterface(Ci.nsIInterfaceRequestor)
+           .getInterface(Ci.nsIWebNavigation)
+           .QueryInterface(Ci.nsIDocShellTreeItem)
+           .rootTreeItem
+           .QueryInterface(Ci.nsIInterfaceRequestor)
+           .getInterface(Ci.nsIDOMWindow)
+           .QueryInterface(Ci.nsIDOMChromeWindow);
+}
+
+function getSHTitle(sh, offset)
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  if (!offset)
+    offset = 0;
+
+  // False instructs the SHistory not to modify its current index.
+  return sh.getEntryAtIndex(sh.index + offset, false).title;
+}
+
+// Tests that win's location ends with str
+function locationEndsWith(win, str) {
+  var exp = new RegExp(str + "$");
+  ok(win.location.toString().match(exp),
+     "Wrong window location.  Expected it to end with " +
+     str + ", but actuall was " + win.location);
+}
+
+function expectException(func, msg) {
+  var failed = false;
+  try {
+    func();
+  } catch(ex) {
+    failed = true;
+  }
+
+  ok(failed, msg + " succeeded, but should have failed.");
+}
+
+function runTest() {
+  // We can't enable universal XPConnect privleges in this function, because
+  // test 5 needs to be running at normal privleges in order to test the
+  // same-origin policy.
+
+  /**
+   * PRELIMINARY:
+   *  1. Clear the popstate counter
+   *  2. Get the visited and unvisited link colors.
+   */
+
+  clearPopStateCounter();
+
+  // Set the link's href to somewhere we haven't been so we can get the
+  // unvisited link color.
+  var rand = Date.now() + "-" + Math.random();
+  $("link").href = rand;
+  unvisitedColor = getColor($("link"));
+  statusMsg("Unvisited color is " + unvisitedColor);
+
+  // Set the link's href to our current location so we can get the visited link
+  // color.
+  $("link").href = document.location;
+  visitedColor = getColor($("link"));
+  statusMsg("Visited color is " + visitedColor);
+  isnot(visitedColor, unvisitedColor, "visited/unvisited link colors are the same?");
+
+  // The URL of file_bug500328_1.html on http://localhost:8888
+  var innerLoc;
+
+  // Now we can start the tests
+
+  /**
+   * TEST 1 tests basic pushState functionality
+   */
+  enableChildLoadCallback();
+  iframeCw.location = "file_bug500328_1.html";
+  yield;
+  innerLoc = iframeCw.location.toString();
+  // Load should be fired before popstate.
+  enableChildPopStateCallback();
+  yield;
+  popstateExpected("Expected initial popstate.");
+  statusMsg("Awake after first popstate.");
+
+  var testObj1 = 42;
+  var testObj2 = 4.2;
+  iframeCw.history.pushState(testObj1, "test 1");
+  is(iframeCw.location.search, "",
+     "First pushstate should leave us where we were.");
+
+  // Make sure that this pushstate doesn't trigger a hashchange.
+  iframeCw.onhashchange = function() {
+    ok(false, "Pushstate shouldn't trigger a hashchange.");
+  };
+
+  iframeCw.history.pushState(testObj2, "test 1#foo", "?test1#foo");
+  is(iframeCw.location.search, "?test1",
+     "Second pushstate should push us to '?test1'.");
+  is(iframeCw.location.hash, "#foo",
+     "Second pushstate should push us to '#foo'");
+  shortWait();
+  yield;
+
+  // Let the hashchange event fire, if it's going to.
+  longWait();
+  yield;
+  iframeCw.onhashchange = null;
+
+  statusMsg("About to go back to page 1.");
+  // We don't have to yield here because this back() and the resulting popstate
+  // are completely synchronous.  In fact, if we did yield, JS would throw an
+  // error because we'd be calling gGen.next from within gGen.next.
+  iframeCw.history.back();
+
+  statusMsg("Awake after going back to page 1.");
+  popstateExpected("Going back to page 1 should trigger a popstate.");
+  is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1),
+     "Wrong state object popped after going back to page 1.");
+  ok(iframeCw.location.toString().match(/file_bug500328_1.html$/),
+      "Going back to page 1 hould take us to original page.");
+
+  iframeCw.history.back();
+  popstateExpected("Going back to page 0 should trigger a popstate.");
+  is(gLastPopStateEvent.state, null,
+      "Going back to page 0 should pop a null state.");
+  is(iframeCw.location.search, "",
+      "Going back to page 0 should clear the querystring.");
+
+  iframeCw.history.forward();
+  popstateExpected("Going forward to page 1 should trigger a popstate.");
+  is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1),
+      "Wrong state object popped after going forward to page 1.");
+  ok(iframeCw.location.toString().match(/file_bug500328_1.html$/),
+      "Going forward to page 1 should leave us at original page.");
+
+
+  statusMsg("About to go forward to page 2.");
+  iframeCw.history.forward();
+  statusMsg("Awake after going forward to page 2.");
+  popstateExpected("Going forward to page 2 should trigger a popstate.");
+  is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj2),
+     "Wrong state object popped after going forward to page 2.");
+  ok(iframeCw.location.toString().match(/file_bug500328_1.html\?test1#foo$/),
+     "Going forward to page 2 took us to " + iframeCw.location.toString());
+
+  // The iframe's current location is file_bug500328_1.html?test1#foo.
+  // Clicking link1 should take us to file_bug500328_1.html?test1#1.
+
+  enableChildPopStateCallback();
+  sendMouseEvent({type:'click'}, 'link-anchor1', iframeCw);
+  yield;
+  popstateExpected("Clicking on link-anchor1 should trigger a popstate.");
+  is(iframeCw.location.search, "?test1",
+      "search should be ?test1 after clicking link.");
+  is(iframeCw.location.hash, "#1",
+      "hash should be #1 after clicking link.");
+
+  /*
+   * Reload file_bug500328_1.html; we're now going to test that link hrefs
+   * and colors are updated correctly on push/popstates.
+   */
+
+  iframe.onload = onChildLoad;
+  enableChildLoadCallback();
+  iframeCw.location = "about:blank";
+  yield;
+  iframe.onload = null;
+  iframeCw.location = "file_bug500328_1.html";
+  enableChildPopStateCallback();
+  yield;
+  popstateExpected("No popstate after re-loading file_bug500328_1.html");
+  statusMsg("Done loading file_bug500328_1.html for the second time.");
+
+  var ifLink = iframeCw.document.getElementById("link-anchor1");
+  ifLink.href = rand;
+
+  // Poll the document until the link has the correct color, or this test times
+  // out.  Unfortunately I can't come up with a more elegant way to do this.
+  // We could listen to MozAfterPaint, but that doesn't guarantee that we'll
+  // observe the new color.
+  while (getColor(ifLink) != unvisitedColor) {
+    // Dump so something shows up in the mochitest logs if we spin here.
+    dump("ifLink has wrong initial color.  Spinning...\n");
+    setTimeout(function() { gGen.next(); }, 10);
+    yield;
+  }
+
+  // Navigate iframe2 to dir/${rand}
+  iframe2.onload = onChildLoad;
+  enableChildLoadCallback();
+  iframe2Cw.location = "mytestdir/" + rand;
+  yield;
+
+  // PushState the iframe into the mytestdir directory.  This should cause
+  // ifLink to turn purple, since we just visited mytestdir/${rand} in iframe2.
+  iframeCw.history.pushState(null, "foo", "mytestdir/foo");
+
+  // Check that the link's color is now visitedColor
+  while (getColor(ifLink) != visitedColor) {
+    dump("ifLink has wrong color after pushstate.  Spinning...\n");
+    setTimeout(function() { gGen.next(); }, 10);
+    yield;
+  }
+
+  ok(ifLink.href.match("mytestdir\\/" + rand + "$"),
+     "inner frame's link should end with 'mytestdir/${rand}'");
+
+  // Navigate out of the mytestdir directory.  This should cause ifLink to turn
+  // blue again.
+  iframeCw.history.pushState(null, "bar", "../file_bug500328_1.html");
+
+  // Check that the link's color is back to the unvisited color.
+  while (getColor(ifLink) != unvisitedColor) {
+    dump("ifLink has wrong color after pushstating out of dir.  Spinning...\n");
+    setTimeout(function() { gGen.next(); }, 10);
+    yield;
+  }
+
+  ok(!ifLink.href.match("mytestdir"),
+     "inner frame's link shouldn't contain 'mytestdir'.");
+
+  /*
+   * TEST 2 tests that pushstate's same-origin checks are correct.
+   */
+  var filename = 'file_bug500328_2.html';
+  // Get the directory we're currently in
+  var dirname = document.location.pathname.replace(/[^\/]*$/, '');
+  statusMsg("Dirname is: " + dirname);
+  var loc = 'http://example.com' + dirname + filename;
+  statusMsg("About to transfer iframe to " + loc);
+  iframeCw.location = loc;
+  // We have to register a listener like this because this file is hosted on a
+  // different domain and can't notify us on load.
+  iframe.onload = onChildLoad;
+  enableChildLoadCallback();
+  yield;
+
+  // This function tries to pushstate and replacestate to the given URL and
+  // fails the test if the calls succeed.
+  var tryBadPushAndReplaceState = function(url) {
+    // XXX ex should be a SECURITY_ERR, not a plain Error.
+
+    var hist = iframeCw.history;
+    var url2 = url + dirname + filename;
+
+    expectException(function() { hist.pushState({}, "foo", url); },
+                    'pushState to ' + url);
+
+    expectException(function() { hist.pushState({}, "foo", url2); },
+                    'pushState to ' + url2);
+
+    expectException(function() { hist.replaceState({}, "foo", url); },
+                    'replaceState to ' + url);
+
+    expectException(function() { hist.replaceState({}, "foo", url2); },
+                    'replaceState to ' + url2);
+  }
+
+  // We're currently at http://example.com/[dirname]/[filename]
+  tryBadPushAndReplaceState("https://example.com");
+  tryBadPushAndReplaceState("http://foo.example.com");
+  tryBadPushAndReplaceState("http://example.com:1234");
+  tryBadPushAndReplaceState("http://example.com.a");
+  tryBadPushAndReplaceState("http://example.con");
+  tryBadPushAndReplaceState("http://eexample.com");
+  tryBadPushAndReplaceState("http://me@example.com");
+
+  /**
+   * TEST 3 tests that the session history entries' titles are properly sync'ed
+   * after push/pop states.
+   *
+   * We have to run this test in a popup rather than an iframe because only the
+   * root docshell has a session history object.
+   */
+  statusMsg("About to open popup.");
+  var popup = window.open("file_bug500328_1.html", "popup0",
+                          "height=200,width=200,location=yes," +
+                          "menubar=yes,status=yes,toolbar=yes,dependent=yes");
+
+  var shistory = getSHistory(popup);
+
+  enableChildPopStateCallback();
+  yield;
+  popstateExpected("Didn't get popstate after opening window.");
+
+  popup.history.pushState(null, "title 0");
+  ok(!getChromeWin(popup).document
+        .getElementById("Browser:Back").hasAttribute("disabled"),
+     "Back button was not enabled after initial pushstate.");
+
+  popup.document.title = "title 1";
+
+  // Yield to the event loop so listeners will be notified of the title change
+  // and so that the hash change we trigger below generates a new session
+  // history entry.
+  shortWait();
+  yield;
+
+  // Check that the current session history entry's title has been updated to
+  // reflect the new document title.
+  is(getSHTitle(shistory), "title 1", "SHEntry title test 1");
+
+  // Change the page's hash to #1, which will trigger a popstate event.
+  // We don't have to wait, because this happens synchronously.
+  popup.location.hash = "#1";
+  popstateExpected("Didn't get popstate after changing hash.");
+
+  popup.document.title = "title 2";
+
+  // Yield so listeners will be notified of the title change we just performed.
+  shortWait();
+  yield;
+
+  is(getSHTitle(shistory), "title 2", "SHEntry title test 2");
+
+  // Go back.  Happens synchronously.  We should get a popstate.
+  statusMsg("About to go back.");
+  popup.history.go(-1);
+  popstateExpected("Didn't get a popstate after going back.");
+
+  // Even though we went back, we expect the SHEntry title to remain the same
+  // because the document didn't change.
+  is(getSHTitle(shistory), "title 2", "SHEntry title test 3");
+
+  popup.document.title = "Changed 1";
+  shortWait();
+  yield;
+
+  // This check is really a test of bug 509055.
+  is(getSHTitle(shistory), "Changed 1", "SHEntry title test 4");
+
+  popup.close();
+
+  /**
+   * TEST 4 tests replaceState and that we don't get double popstates on
+   * window.open.  It also stress-tests the system and its interaction with
+   * bfcache by making many push/replace state calls.
+   */
+  popup = window.open("file_bug500328_1.html", "popup1",
+                      "height=200,width=200,location=yes," +
+                      "menubar=yes,status=yes,toolbar=yes,dependent=yes");
+
+  // The initial about:blank load into the new window shouldn't result in us
+  // seeing a popstate.  Once file_bug500328_1.html is loaded, it'll overwrite
+  // popup.onpopstate, and this assertion won't fire for that popstate and
+  // others after.
+  //
+  // If we fired the popstate event asynchronously, we'd expect this assert to
+  // fire.
+  popup.onpopstate = function() {
+    ok(false, "Initial load of popup shouldn't give us a popstate.");
+  };
+
+  shistory = getSHistory(popup);
+
+  enableChildPopStateCallback();
+  yield;
+  statusMsg("Awake after loading content into popup.");
+
+  popup.history.replaceState({n:1, ok:true}, "state 1", "good1.html");
+  locationEndsWith(popup, "good1.html");
+  is(getSHTitle(shistory), "state 1", "SHEntry title 'state 1'");
+
+  // Flush the event loop so our next load creates a new session history entry.
+  shortWait();
+  yield;
+
+  enableChildPopStateCallback();
+  popup.location = "file_bug500328_1.html";
+  yield;
+
+  // Flush the event loop so nsDocShell::OnNewURI runs and our load is recorded
+  // properly.  OnNewURI is called after PopState fires, because OnNewURI
+  // results from an async event, while PopState is sync.  We'd have to do the
+  // same thing if we were listening to onload here, so this isn't
+  // unreasonable.
+  shortWait();
+  yield;
+
+  // Now go back and make sure everything is as it should be.
+  enableChildPopStateCallback();
+  popup.history.back();
+  yield;
+
+  // Flush the event loop so the document's location is updated.
+  shortWait();
+  yield;
+
+  // We had some popstates above without corresponding popstateExpected()
+  // calls, so we need to clear the counter.
+  clearPopStateCounter();
+
+  locationEndsWith(popup, "good1.html");
+  is(JSON.stringify(gLastPopStateEvent.state), '{"n":1,"ok":true}',
+     "Wrong state popped after going back to initial state.");
+
+  // We're back at state 0, which was replaceState-ed to state1.html.  Let's do
+  // some push/pop/replaces to make sure everything works OK when we involve
+  // large numbers of SHEntries.
+  for(var i = 2; i <= 30; i++) {
+    if (i % 3 == 0) {
+      popup.history.pushState({n:i, ok:true}, "state " + i, "good" + i + ".html");
+    }
+    else {
+      popup.history.pushState({n:i}, "state " + i, "state" + i + ".html");
+      for(var j = 0; j < i % 4; j++) {
+        popup.history.replaceState({n:i, nn:j}, "state " + i + ", " + j);
+      }
+      popup.history.replaceState({n:i, ok:true}, "state " + i, "good" + i + ".html");
+    }
+  }
+
+  for(var i = 29; i >= 1; i--) {
+    popup.history.back();
+    popstateExpected("Didn't get a popstate on iteration " + i);
+    locationEndsWith(popup, "good" + i + ".html");
+    is(gLastPopStateEvent.state.n, i, "Bad counter on last popstate event.");
+    ok(gLastPopStateEvent.state.ok,
+       "Last popstate event should have 'ok' set to true.");
+  }
+
+  popup.close();
+
+  /**
+   * TEST 5 tests misc security features and implementation details of
+   * Push/ReplaceState
+   */
+
+  /*
+   * Test that we can't push/replace an object with a large (over 640k
+   * characters) JSON representation.
+   */
+
+  // (In case you're curious, this loop generates an object which serializes to
+  // 694581 characters.)
+  var bigObject = new Object();
+  for(var i = 0; i < 51200; i++) {
+    bigObject[i] = i;
+  }
+  // statusMsg("Big object has size " + JSON.stringify(bigObject).length);
+
+  // We shouldn't be able to pushstate this large object, due to space
+  // constraints.
+  expectException(
+    function() { iframeCw.history.pushState(bigObject, "foo"); },
+    "pushState-ing large object");
+
+  expectException(
+    function() { iframeCw.history.replaceState(bigObject, "foo"); },
+    "replaceState-ing large object");
+
+  /*
+   * Make sure we can't push/replace state on an iframe of a different origin.
+   * This will work if this function has requested Universal XPConnect
+   * privileges, so any code which needs those privileges can't be in this
+   * function.
+   */
+  enableChildLoadCallback();
+  iframeCw.location = "http://example.com";
+  iframe.onload = onChildLoad;
+  yield;
+  iframe.onload = null;
+
+  expectException(
+    function() { iframeCw.history.pushState({}, "foo"); },
+    "pushState-ing in a different origin");
+
+  expectException(
+    function() { iframeCw.history.replaceState({}, "foo"); },
+    "replaceState-ing in a different origin");
+
+  /*
+   * If we do the following:
+   *   * Start at page A.
+   *   * PushState to page B.
+   *   * Refresh.  The server responds with a 404
+   *   * Go back.
+   * Then at the end, page A should be displayed, not the 404 page.
+   */
+  enableChildLoadCallback();
+  iframe.onload = onChildLoad;
+  iframeCw.location = "about:blank";
+  yield;
+  iframe.onload = null;
+
+  enableChildPopStateCallback();
+  // navigate to http://localhost:8888/[...]/file_bug500328_1.html
+  iframeCw.location = innerLoc;
+  yield;
+
+  // Let the PopState handler finish.  If we call refresh (below) from within
+  // the handler, we get slightly confused and can't tell that we're at a 404
+  // after the refresh.
+  shortWait();
+  yield;
+
+  // PushState to a URL which doesn't exist
+  iframeCw.history.pushState({}, "", rand);
+
+  // Refresh.  We'll end up a 404 page.
+  iframe.onload = onChildLoad;
+  enableChildLoadCallback();
+  iframeCw.location.reload(true);
+  yield;
+
+  // Since the last page was a 404, going back should actually show the
+  // contents of the old page, instead of persisting the contents of the 404
+  // page.
+  clearPopStateCounter();
+  enableChildPopStateCallback();
+  iframeCw.history.back();
+  yield;
+  popstateExpected("Didn't get popstate after going back.");
+
+  // Make sure that we're actually showing the contents of
+  // file_bug500328_1.html, as opposed to the 404 page.
+  var identifierElem = iframeCw.document.getElementById("link-anchor1");
+  ok(identifierElem != undefined && identifierElem != null,
+     "iframe didn't contain file_bug500328_1.html's contents.");
+
+  /**
+   * TEST 6 tests that the referrer is set properly after push/replace states.
+   */
+
+  /*
+   * First, a simple test:
+   *   * Load file_bug500328_1.html into iframe
+   *   * PushState to newpage1.html#foo
+   *   * Instruct the iframe to load file_bug500328_1.html into itself.
+   * The referer should be newpage1.html, without the hash.
+   *
+   * This also tests that we can call pushState from within the onload handler.
+   */
+  enableChildLoadCallback();
+  iframeCw.location = "file_bug500328_1.html";
+  yield;
+
+  // Run within the onload handler.  This should work without issue.
+  iframeCw.history.pushState(null, "", "newpage1.html");
+
+  // iframeCw.navigateTo() causes the iframe to set its location on our
+  // behalf.  We can't just set its location ourselves, because then *we*
+  // become the referrer.
+  enableChildPopStateCallback();
+  iframeCw.navigateTo("file_bug500328_1.html");
+  yield;
+
+  ok(iframeCw.document.referrer.toString().match(/newpage1.html$/),
+     "Wrong referrer after replaceState.  Expected newpage1.html, but was " +
+     iframeCw.document.referrer);
+
+  /*
+   * We're back at file_bug500328_1.html.  Now do the following:
+   *   * replaceState to newpage2.html#foo
+   *   * Click a link back to file_bug500328_1.html
+   * The referrer should be newpage2.html, without the hash.
+   */
+  iframeCw.history.replaceState(null, null, "newpage2.html#foo");
+  enableChildPopStateCallback();
+  sendMouseEvent({type:'click'}, 'link-self', iframeCw);
+  yield;
+
+  ok(iframeCw.document.referrer.toString().match(/newpage2.html$/),
+     "Wrong referrer after replaceState.  Expected newpage2.html, but was " +
+     iframeCw.document.referrer);
+
+
+  /*
+   * Set up a cycle with the popstate event to make sure it's properly
+   * collected.
+   */
+  var evt = document.createEvent("popstateevent");
+  evt.initEvent("foo", false, false, evt);
+
+  /* */
+  SimpleTest.finish();
+  statusMsg("********** Finished tests ***********");
+  while(true)
+  {
+    yield;
+
+    // I don't think this will actually make the mochitest fail, but there's
+    // not much we can do about this.  Realistically, though, regressions are
+    // not likely to fire extra events -- this trap is here mostly to catch
+    // errors made while wriring tests.
+    ok(false, "Got extra event!");
+  }
+
+  /*
+  statusMsg("XXXXXXXXXXXXXX");
+  while(true) {
+    yield;
+    statusMsg("Woken up.");
+  }
+  */
+}
+
+// Important: Wait to start the tests until the page has loaded.  Otherwise,
+// the test will occasionally fail when it begins running before the iframes
+// have finished their initial load of about:blank.
+window.addEventListener('load', function() {
+  gGen = runTest();
+  gGen.next();
+}, false);
+
+</script>
+</pre>
+</body>
+</html>
deleted file mode 100644
deleted file mode 100644
--- a/intl/locale/src/mac/nsDateTimeFormatMac.cpp
+++ b/intl/locale/src/mac/nsDateTimeFormatMac.cpp
@@ -130,19 +130,16 @@ nsresult nsDateTimeFormatMac::FormatTMTi
   (void) Initialize(locale);
   
   // return, nothing to format
   if (dateFormatSelector == kDateFormatNone && timeFormatSelector == kTimeFormatNone) {
     stringOut.Truncate();
     return NS_OK;
   }
 
-  // set the default string, in case for API/conversion errors
-  CopyASCIItoUTF16(nsDependentCString(asctime(tmTime)), stringOut);
-  
   NS_ASSERTION(tmTime->tm_mon >= 0, "tm is not set correctly");
   NS_ASSERTION(tmTime->tm_mday >= 1, "tm is not set correctly");
   NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly");
   NS_ASSERTION(tmTime->tm_min >= 0, "tm is not set correctly");
   NS_ASSERTION(tmTime->tm_sec >= 0, "tm is not set correctly");
   NS_ASSERTION(tmTime->tm_wday >= 0, "tm is not set correctly");
 
   // Got the locale for the formatter:
--- a/js/src/xpconnect/idl/nsIDispatchSupport.idl
+++ b/js/src/xpconnect/idl/nsIDispatchSupport.idl
@@ -52,17 +52,16 @@
 // as a class
 #pragma warning(push)
 #pragma warning(disable : 4099)
 #endif
 %}
 
 native COMVARIANT(VARIANT);
 [ptr] native COMVARIANTPtr(VARIANT);
-native JSVal(jsval);
 [ptr] native JSContextPtr(JSContext);
 
 interface IDispatch;
 
 [uuid(38df70e9-12f8-4732-af91-df36c38dc6f6)]
 interface nsIDispatchSupport : nsISupports
 {
     /**
--- a/js/src/xpconnect/idl/nsIXPConnect.idl
+++ b/js/src/xpconnect/idl/nsIXPConnect.idl
@@ -54,21 +54,22 @@
 %{ C++
 #include "jspubtd.h"
 #include "xptinfo.h"
 #include "nsAXPCNativeCallContext.h"
 %}
 
 /***************************************************************************/
 
+// NB: JSVal is declared in nsIVariant.idl
+
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSClassPtr(JSClass);
 [ptr] native JSObjectPtr(JSObject);
 [ptr] native JSValPtr(jsval);
-      native JSVal(jsval);
       native JSEqualityOp(JSEqualityOp);
       native JSID(jsid);
 [ptr] native voidPtrPtr(void*);
 [ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer);
 [ref] native nsCCTraversalCallbackRef(nsCycleCollectionTraversalCallback);
 [ptr] native nsAXPCNativeCallContextPtr(nsAXPCNativeCallContext);
 
 /***************************************************************************/
@@ -526,16 +527,22 @@ interface nsIXPConnect : nsISupports
     */
     void
     wrapJS(in JSContextPtr aJSContext,
            in JSObjectPtr  aJSObj,
            in nsIIDRef     aIID,
            [iid_is(aIID),retval] out nsQIResult result);
 
     /**
+     * Wraps the given JSVal in a nsIVariant and returns the new variant.
+     */
+    nsIVariant
+    jSValToVariant(in JSContextPtr cx, in JSValPtr aJSVal);
+
+    /**
     * This only succeeds if the JSObject is a nsIXPConnectWrappedNative.
     * A new wrapper is *never* constructed.
     */
     nsIXPConnectWrappedNative
     getWrappedNativeOfJSObject(in JSContextPtr aJSContext,
                                in JSObjectPtr  aJSObj);
 
     [noscript, notxpcom] nsISupports
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -1353,24 +1353,16 @@ NS_IMETHODIMP
 FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
                                      JSObject * aJSObject,
                                      const char *aClassName,
                                      jsval aProperty, PRUint32 aAction)
 {
     return NS_OK;
 }
 
-/* [noscript] void checkConnect (in JSContextPtr aJSContext, in nsIURI aTargetURI, in string aClassName, in string aProperty); */
-NS_IMETHODIMP
-FullTrustSecMan::CheckConnect(JSContext * aJSContext, nsIURI *aTargetURI,
-                              const char *aClassName, const char *aProperty)
-{
-    return NS_OK;
-}
-
 /* [noscript] void checkLoadURIFromScript (in JSContextPtr cx, in nsIURI uri); */
 NS_IMETHODIMP
 FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx, nsIURI *uri)
 {
     return NS_OK;
 }
 
 /* void checkLoadURIWithPrincipal (in nsIPrincipal aPrincipal, in nsIURI uri, in unsigned long flags); */
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1046,17 +1046,17 @@ static PRBool
 InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj)
 {
     // this is unrooted, but it's a property on aGlobalJSObj so won't go away
     jsval v;
 
     // Alias WebGLArrayBuffer -> ArrayBuffer
     if(!JS_GetProperty(aJSContext, aGlobalJSObj, "ArrayBuffer", &v) ||
        !JS_DefineProperty(aJSContext, aGlobalJSObj, "WebGLArrayBuffer", v,
-                          NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
+                          NULL, NULL, JSPROP_PERMANENT))
         return PR_FALSE;
 
     const int webglTypes[] = {
         js::TypedArray::TYPE_INT8,
         js::TypedArray::TYPE_UINT8,
         js::TypedArray::TYPE_INT16,
         js::TypedArray::TYPE_UINT16,
         js::TypedArray::TYPE_INT32,
@@ -1075,17 +1075,17 @@ InitWebGLTypes(JSContext *aJSContext, JS
     };
 
     for(size_t i = 0;
         i < NS_ARRAY_LENGTH(webglTypes);
         ++i)
     {
         if(!JS_GetProperty(aJSContext, aGlobalJSObj, js::TypedArray::slowClasses[webglTypes[i]].name, &v) ||
            !JS_DefineProperty(aJSContext, aGlobalJSObj, webglNames[i], v,
-                              NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
+                              NULL, NULL, JSPROP_PERMANENT))
             return PR_FALSE;
     }
 
     return PR_TRUE;
 }
 
 
 /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
@@ -1365,16 +1365,35 @@ nsXPConnect::WrapJS(JSContext * aJSConte
 
     nsresult rv;
     if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
                                              &aIID, nsnull, &rv))
         return rv;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsXPConnect::JSValToVariant(JSContext *cx,
+                            jsval *aJSVal,
+                            nsIVariant ** aResult)
+{
+    NS_PRECONDITION(aJSVal, "bad param");
+    NS_PRECONDITION(aResult, "bad param");
+    *aResult = nsnull;
+
+    XPCCallContext ccx(NATIVE_CALLER, cx);
+    if(!ccx.IsValid())
+      return NS_ERROR_FAILURE;
+
+    *aResult = XPCVariant::newVariant(ccx, *aJSVal);
+    NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+
+    return NS_OK;
+}
+
 /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
 NS_IMETHODIMP
 nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,
                                       JSContext * aJSContext,
                                       JSObject * aJSObj,
                                       const nsIID & aIID,
                                       void * *result)
 {
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -4193,16 +4193,20 @@ public:
     // that case.
 
     // We #define and iid so that out module local code can use QI to detect 
     // if a given nsIVariant is in fact an XPCVariant. 
     NS_DECLARE_STATIC_IID_ACCESSOR(XPCVARIANT_IID)
 
     static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal);
 
+    /**
+     * nsIVariant exposes a GetAsJSVal() method, which also returns mJSVal.
+     * But if you can, you should call this one, since it can be inlined.
+     */
     jsval GetJSVal() const {return mJSVal;}
 
     XPCVariant(XPCCallContext& ccx, jsval aJSVal);
 
     /**
      * Convert a variant into a jsval.
      *
      * @param ccx the context for the whole procedure
--- a/js/src/xpconnect/src/xpcvariant.cpp
+++ b/js/src/xpconnect/src/xpcvariant.cpp
@@ -385,62 +385,69 @@ JSBool XPCVariant::InitializeData(XPCCal
     const nsIID& iid = NS_GET_IID(nsISupports);
 
     return nsnull != (xpc = nsXPConnect::GetXPConnect()) &&
            NS_SUCCEEDED(xpc->WrapJS(ccx, jsobj,
                         iid, getter_AddRefs(wrapper))) &&
            NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper));
 }
 
+NS_IMETHODIMP
+XPCVariant::GetAsJSVal(jsval* result)
+{
+  NS_PRECONDITION(result, "null result arg.");
+  *result = GetJSVal();
+  return NS_OK;
+}
+
 // static 
 JSBool 
 XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx, 
                             nsIVariant* variant,
                             JSObject* scope, nsresult* pErr,
                             jsval* pJSVal)
 {
     // Get the type early because we might need to spoof it below.
     PRUint16 type;
-    if(NS_FAILED(variant->GetDataType(&type)))
+    if (NS_FAILED(variant->GetDataType(&type)))
         return JS_FALSE;
 
+    jsval realVal;
+    nsresult rv = variant->GetAsJSVal(&realVal);
+
+    if(NS_SUCCEEDED(rv) &&
+      (JSVAL_IS_PRIMITIVE(realVal) ||
+       type == nsIDataType::VTYPE_ARRAY ||
+       type == nsIDataType::VTYPE_EMPTY_ARRAY ||
+       type == nsIDataType::VTYPE_ID))
+    {
+        // It's not a JSObject (or it's a JSArray or a JSObject representing an
+        // nsID).  Just pass through the underlying data.
+        *pJSVal = realVal;
+        return JS_TRUE;
+    }
+
     nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
-    if(xpcvariant)
+    if(xpcvariant && xpcvariant->mReturnRawObject)
     {
-        jsval realVal = xpcvariant->GetJSVal();
-        if(JSVAL_IS_PRIMITIVE(realVal) || 
-           type == nsIDataType::VTYPE_ARRAY ||
-           type == nsIDataType::VTYPE_EMPTY_ARRAY ||
-           type == nsIDataType::VTYPE_ID)
-        {
-            // Not a JSObject (or is a JSArray or is a JSObject representing 
-            // an nsID),.
-            // So, just pass through the underlying data.
-            *pJSVal = realVal;
-            return JS_TRUE;
-        }
-
-        if(xpcvariant->mReturnRawObject)
-        {
-            NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
-                         type == nsIDataType::VTYPE_INTERFACE_IS,
-                         "Weird variant");
-            *pJSVal = realVal;
-            return JS_TRUE;
-        }
+        NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
+                     type == nsIDataType::VTYPE_INTERFACE_IS,
+                     "Weird variant");
+        *pJSVal = realVal;
+        return JS_TRUE;
 
         // else, it's an object and we really need to double wrap it if we've 
         // already decided that its 'natural' type is as some sort of interface.
-        
+
         // We just fall through to the code below and let it do what it does.
     }
 
     // The nsIVariant is not a XPCVariant (or we act like it isn't).
     // So we extract the data and do the Right Thing.
-    
+
     // We ASSUME that the variant implementation can do these conversions...
 
     nsXPTCVariant xpctvar;
     nsID iid;
     nsAutoString astring;
     nsCAutoString cString;
     nsUTF8String utf8String;
     PRUint32 size;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -993,17 +993,17 @@ DocumentViewerImpl::LoadComplete(nsresul
   // Flush out layout so it's up-to-date by the time onload is called.
   // Note that this could destroy the window, so do this before
   // checking for our mDocument and its window.
   if (mPresShell && !mStopped) {
     // Hold strong ref because this could conceivably run script
     nsCOMPtr<nsIPresShell> shell = mPresShell;
     shell->FlushPendingNotifications(Flush_Layout);
   }
-  
+
   nsresult rv = NS_OK;
   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 
   // First, get the window from the document...
   nsPIDOMWindow *window = mDocument->GetWindow();
 
   mLoaded = PR_TRUE;
 
@@ -1033,18 +1033,16 @@ DocumentViewerImpl::LoadComplete(nsresul
     docShell->GetRestoringDocument(&restoring);
     if (!restoring) {
       nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull,
                                   &status);
 #ifdef MOZ_TIMELINE
       // if navigator.xul's load is complete, the main nav window is visible
       // mark that point.
 
-      //printf("DEBUG: getting uri from document (%p)\n", mDocument.get());
-
       nsIURI *uri = mDocument ? mDocument->GetDocumentURI() : nsnull;
 
       if (uri) {
         //printf("DEBUG: getting spec for uri (%p)\n", uri.get());
         nsCAutoString spec;
         uri->GetSpec(spec);
         if (spec.EqualsLiteral("chrome://navigator/content/navigator.xul") ||
             spec.EqualsLiteral("chrome://browser/content/browser.xul")) {
@@ -1092,16 +1090,20 @@ DocumentViewerImpl::LoadComplete(nsresul
     mPrintIsPending        = PR_FALSE;
     mPrintDocIsFullyLoaded = PR_TRUE;
     Print(mCachedPrintSettings, mCachedPrintWebProgressListner);
     mCachedPrintSettings           = nsnull;
     mCachedPrintWebProgressListner = nsnull;
   }
 #endif
 
+  if (!mStopped) {
+    window->DispatchSyncPopState();
+  }
+
   return rv;
 }
 
 NS_IMETHODIMP
 DocumentViewerImpl::PermitUnload(PRBool aCallerClosesWindow, PRBool *aPermitUnload)
 {
   *aPermitUnload = PR_TRUE;
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1292,17 +1292,17 @@ AddItemsToRegion(nsDisplayListBuilder* a
                            clipFrame, clippedOutSource);
  #endif
           aRegion->Or(*aRegion, clippedOutSource);
 
           // Invalidate the destination area that is clipped out
           nsRegion clippedOutDestination;
           clippedOutDestination.Sub(aUpdateRect, clip);
  #ifdef DEBUG
-          PrintAddedRegion("Adding region for clipped out source frame %p",
+          PrintAddedRegion("Adding region for clipped out destination frame %p",
                            clipFrame, clippedOutDestination);
  #endif
           aRegion->Or(*aRegion, clippedOutDestination);
         }
         AddItemsToRegion(aBuilder, sublist, aUpdateRect, clip, aDelta, aRegion);
       } else {
         // opacity, or a generic sublist
         AddItemsToRegion(aBuilder, sublist, aUpdateRect, aClipRect, aDelta, aRegion);
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -928,17 +928,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
     else if (nsGkAtoms::brFrame == frameType) {
       pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, PR_TRUE);
       isEmpty = PR_FALSE;
     } else {
       if (nsGkAtoms::letterFrame==frameType) {
         pfd->SetFlag(PFD_ISLETTERFRAME, PR_TRUE);
       }
       if (pfd->mSpan) {
-        isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty();
+        isEmpty = !pfd->mSpan->mHasNonemptyContent;
       } else {
         isEmpty = pfd->mFrame->IsEmpty();
       }
     }
   }
 
   mFloatManager->Translate(-tx, -ty);
 
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -2174,16 +2174,18 @@ DoStopPlugin(nsPluginInstanceOwner *aIns
 
     if (window) 
       window->CallSetWindow(nullinst);
     else 
       inst->SetWindow(nsnull);
     
     if (DoDelayedStop(aInstanceOwner, aDelayedStop))
       return;
+    
+    inst->Stop();
 
     nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
     if (pluginHost)
       pluginHost->StopPluginInstance(inst);
 
     // the frame is going away along with its widget so tell the
     // window to forget its widget too
     if (window)
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -6121,17 +6121,17 @@ nsTextFrame::Reflow(nsPresContext*      
   // whitespace, restricting to first-letter, and restricting preformatted text
   // to nearest newline
   PRInt32 length = maxContentLength;
   PRInt32 offset = GetContentOffset();
 
   // Restrict preformatted text to the nearest newline
   PRInt32 newLineOffset = -1; // this will be -1 or a content offset
   // Pointer to the nsGkAtoms::newline set on this frame's element
-  NewlineProperty* cachedNewlineOffset;
+  NewlineProperty* cachedNewlineOffset = nsnull;
   if (textStyle->NewlineIsSignificant()) {
     cachedNewlineOffset =
       static_cast<NewlineProperty*>(mContent->GetProperty(nsGkAtoms::newline));
     if (cachedNewlineOffset && cachedNewlineOffset->mStartOffset <= offset &&
         (cachedNewlineOffset->mNewlineOffset == -1 ||
          cachedNewlineOffset->mNewlineOffset >= offset)) {
       newLineOffset = cachedNewlineOffset->mNewlineOffset;
     } else {
--- a/layout/generic/test/plugin_clipping_helper2.xhtml
+++ b/layout/generic/test/plugin_clipping_helper2.xhtml
@@ -39,71 +39,64 @@ var p1 = document.getElementById("p1");
 var d2 = document.getElementById("d2");
 
 function runTests() {
 
   checkClipRegion("p1", [[0, 0, 200, 100]]);
   checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 150], [150, 50, 200, 150], [0, 150, 200, 200]]);
 
   scroll.scrollTop = 150;
-  checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 200], [150, 50, 200, 200]]);
 
-  zbox.style.zIndex = -1;
-
-  flush();
   // A non-zero timeout is needed on X11 (unless an XSync could be performed)
   // to delay an OOP plugin's X requests enough so that the X server processes
   // them after the parent processes requests (for the changes above).
   setTimeout(part2, 1000);
 }
 
 function part2() {
-  checkClipRegion("p2", [[0, 0, 200, 100], [0, 100, 50, 200], [150, 100, 200, 200]]);
+  checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 200], [150, 50, 200, 200]]);
 
-  sbox.style.background = "";
+  zbox.style.zIndex = -1;
 
-  flush();
   setTimeout(part3, 1000);
 }
 
 function part3() {
+  checkClipRegion("p2", [[0, 0, 200, 100], [0, 100, 50, 200], [150, 100, 200, 200]]);
+
+  sbox.style.background = "";
+
+  setTimeout(part4, 1000);
+}
+
+function part4() {
   checkClipRegion("p2", [[0, 0, 200, 200]]);
   
   p1.style.zIndex = 1;
 
-  flush();
-  setTimeout(part4, 1000);
+  setTimeout(part5, 1000);
 }
 
-function part4() {
+function part5() {
   checkClipRegion("p1", [[0, 0, 200, 200]]);
   checkClipRegion("p2", [[0, 100, 200, 200]]);
 
   // Test subpixel stuff
   p1.style.zIndex = -1;
   zbox.style.zIndex = 1;
   zbox.style.top = "50.3px;"
   d2.style.top = "100.3px";
 
-  flush();
   setTimeout(done, 1000);
 }
 
 function done() {
   checkClipRegionNoBounds("p2", [[0, 0, 200, 50], [0, 50, 50, 150], [150, 50, 200, 150], [0, 150, 200, 200]]);
 
   window.opener.SimpleTest.finish();
   window.close();
 }
 
-function flush() {
-  // This function is for X11 to flush the Xlib request queue.  It takes
-  // advantage of the current scrolling implementation, which will do this for
-  // us.  Beware though, it does not wait for the X server to process the
-  // events.
-  ++scroll.scrollTop;
-  --scroll.scrollTop;
-}
 ]]>
 </script>
 
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/538935-1-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div>Hello</div>
+<div style="padding-left:2px;">Hello</div>
+<div>Hello</div>
+<div style="padding-left:2px;">Hello</div>
+<div style="padding-left:1px;">Hello</div>
+
+<div>Hello</div>
+<div style="padding-left:2px;">Hello</div>
+<div>Hello</div>
+<div style="padding-left:2px;">Hello</div>
+<div style="padding-left:1px;">Hello</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/538935-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div><span></span> Hello</div>
+<div><span style="border:1px solid transparent"></span> Hello</div>
+<div><span style="outline:1px transparent"></span> Hello</div>
+<div><span style="padding:1px"></span> Hello</div>
+<div><span style="margin:1px"></span> Hello</div>
+
+<div><span> </span> Hello</div>
+<div><span style="border:1px solid transparent"> </span> Hello</div>
+<div><span style="outline:1px transparent"> </span> Hello</div>
+<div><span style="padding:1px"> </span> Hello</div>
+<div><span style="margin:1px"> </span> Hello</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/542620-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<table>
+  <tr><td style="background:lime; width:100px; height:100px;"></td></tr>
+</table>
+<table>
+  <tr><td style="background:lime; width:100px; height:100px;"></td></tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/542620-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<table>
+  <col style="background: lime"></col>
+  <tr><td style="width:100px; height:100px;"></td></tr>
+</table>
+<table>
+  <colgroup style="background: lime"></colgroup>
+  <tr><td style="width:100px; height:100px;"></td></tr>
+</table>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1374,10 +1374,12 @@ fails HTTP(..) == 518172-2b.html 518172-
 == 531098-1.html 531098-1-ref.html
 == 531371-1.html 531371-1-ref.html
 == 534808-1.html 534808-1-ref.html
 == 534808-2.html 534808-2-ref.html
 == 534919-1.html 534919-1-ref.html
 == 537507-1.xul 537507-1-ref.xul
 == 537507-2.html 537507-2-ref.html
 == 537471-1.html 537471-1-ref.html
+== 538935-1.html 538935-1-ref.html
 == 539226-1.html about:blank
+== 542620-1.html 542620-1-ref.html
 == 541382-1.html 541382-1-ref.html
--- a/layout/reftests/mathml/table-width-1-ref.xhtml
+++ b/layout/reftests/mathml/table-width-1-ref.xhtml
@@ -77,10 +77,22 @@
 	    <mtr><mtd><mn>5</mn></mtd></mtr>
 	    <mtr><mtd><mn>9</mn></mtd></mtr>
 	  </mtable>
 	  <mo>}</mo>
 	</mphantom>
       </math>
     </td>
   </table>
+  <table>
+    <td>
+      <math xmlns="http://www.w3.org/1998/Math/MathML">
+        <mphantom>
+          <mfrac bevelled="true" linethickness="30px">
+            <mn>1473903823894702</mn>
+            <mn>2808472638402743</mn>
+          </mfrac>
+        </mphantom>
+      </math>
+    </td>
+  </table>
 </body>
 </html>
--- a/layout/reftests/mathml/table-width-1.xhtml
+++ b/layout/reftests/mathml/table-width-1.xhtml
@@ -72,10 +72,20 @@
 	    <mtr><mtd><mn>5</mn></mtd></mtr>
 	    <mtr><mtd><mn>9</mn></mtd></mtr>
 	  </mtable>
 	  <mo>}</mo>
 	</mrow>
       </math>
     </td>
   </table>
+  <table>
+    <td>
+      <math xmlns="http://www.w3.org/1998/Math/MathML">
+        <mfrac bevelled="true" linethickness="30px">
+            <mn>1473903823894702</mn>
+            <mn>2808472638402743</mn>
+        </mfrac>
+      </math>
+    </td>
+  </table>
 </body>
 </html>
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1268,38 +1268,33 @@ IsFrameAllowedInTable(nsIAtom* aType)
          nsGkAtoms::scrollFrame == aType ||
          nsGkAtoms::tableFrame == aType ||
          nsGkAtoms::tableColFrame == aType ||
          nsGkAtoms::tableColGroupFrame == aType;
 }
 #endif
 
 static PRBool
-AnyTablePartHasBorderOrBackground(nsIFrame* aFrame)
-{
-  NS_ASSERTION(IsFrameAllowedInTable(aFrame->GetType()), "unexpected frame type");
-
-  nsIScrollableFrame *scrollFrame = do_QueryFrame(aFrame);
-  if (scrollFrame) {
-    return AnyTablePartHasBorderOrBackground(scrollFrame->GetScrolledFrame());
-  }
-
-  if (aFrame->GetStyleVisibility()->IsVisible() &&
-      (!aFrame->GetStyleBackground()->IsTransparent() ||
-       aFrame->GetStyleDisplay()->mAppearance ||
-       aFrame->HasBorder()))
-    return PR_TRUE;
-
-  nsTableCellFrame *cellFrame = do_QueryFrame(aFrame);
-  if (cellFrame)
-    return PR_FALSE;
-
-  nsFrameList children = aFrame->GetChildList(nsnull);
-  for (nsIFrame* f = children.FirstChild(); f; f = f->GetNextSibling()) {
-    if (AnyTablePartHasBorderOrBackground(f))
+AnyTablePartHasBorderOrBackground(const nsFrameList& aFrames)
+{
+  for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
+    nsIFrame* f = e.get();
+    NS_ASSERTION(IsFrameAllowedInTable(f->GetType()), "unexpected frame type");
+
+    if (f->GetStyleVisibility()->IsVisible() &&
+        (!f->GetStyleBackground()->IsTransparent() ||
+         f->GetStyleDisplay()->mAppearance ||
+         f->HasBorder()))
+      return PR_TRUE;
+
+    nsTableCellFrame *cellFrame = do_QueryFrame(f);
+    if (cellFrame)
+      continue;
+
+    if (AnyTablePartHasBorderOrBackground(f->GetChildList(nsnull)))
       return PR_TRUE;
   }
 
   return PR_FALSE;
 }
 
 // table paint code is concerned primarily with borders and bg color
 // SEC: TODO: adjust the rect for captions 
@@ -1326,17 +1321,18 @@ nsTableFrame::BuildDisplayList(nsDisplay
 
   nsDisplayTableItem* item = nsnull;
   // This background is created if any of the table parts are visible,
   // or if we're doing event handling (since DisplayGenericTablePart
   // needs the item for the |sortEventBackgrounds|-dependent code).
   // Specific visibility decisions are delegated to the table background
   // painter, which handles borders and backgrounds for the table.
   if (aBuilder->IsForEventDelivery() ||
-      AnyTablePartHasBorderOrBackground(this)) {
+      AnyTablePartHasBorderOrBackground(nsFrameList(this, GetNextSibling())) ||
+      AnyTablePartHasBorderOrBackground(mColGroups)) {
     item = new (aBuilder) nsDisplayTableBorderBackground(this);
     nsresult rv = aLists.BorderBackground()->AppendNewToTop(item);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item);
 }
 
@@ -3478,17 +3474,17 @@ nsTableFrame::DumpRowGroup(nsIFrame* aKi
       printf("row(%d)=%p ", rowFrame->GetRowIndex(),
              static_cast<void*>(rowFrame));
       nsIFrame* childFrame = cFrame->GetFirstChild(nsnull);
       while (childFrame) {
         nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
         if (cellFrame) {
           PRInt32 colIndex;
           cellFrame->GetColIndex(colIndex);
-          printf("cell(%d)=%p ", colIndex, childFrame);
+          printf("cell(%d)=%p ", colIndex, static_cast<void*>(childFrame));
         }
         childFrame = childFrame->GetNextSibling();
       }
       printf("\n");
     }
     else {
       DumpRowGroup(rowFrame);
     }
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -2833,16 +2833,22 @@ pref("html5.offmainthread", true);
 // first time the flush timer fires in the off-the-main-thread HTML5 parser.
 pref("html5.flushtimer.startdelay", 200);
 // Time in milliseconds between the return to non-speculating more and the 
 // first time the flush timer fires thereafter.
 pref("html5.flushtimer.continuedelay", 150);
 // Time in milliseconds between timer firings once the timer has starting 
 // firing.
 pref("html5.flushtimer.interval", 100);
+
+// Push/Pop/Replace State prefs
+pref("browser.history.allowPushState", true);
+pref("browser.history.allowReplaceState", true);
+pref("browser.history.allowPopState", true);
+pref("browser.history.maxStateObjectSize", 655360);
 // Initial max length for number of tree ops in on flush.
 pref("html5.opqueue.initiallengthlimit", 200);
 // Maximum time in milliseconds to spend flushing the tree op queue when not forced to completion
 pref("html5.opqueue.maxtime", 100);
 // Minimun number of tree ops to flush regardless of time (takes precedence over the maxtime pref)
 pref("html5.opqueue.minlength", 100);
 // Maximum number of tree ops to flush regardless of time (takes precedence over the maxtime pref)
 pref("html5.opqueue.maxlength", 4500); // most top sites stay under this value
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -219,17 +219,16 @@ NS_IMPL_ISUPPORTS1(nsNPAPIPlugin, nsIPlu
 
 nsNPAPIPlugin::nsNPAPIPlugin(NPPluginFuncs* callbacks, 
                              PluginLibrary* aLibrary)
 {
   memset((void*) &mPluginFuncs, 0, sizeof(mPluginFuncs));
 
   mPluginFuncs.size = sizeof(mPluginFuncs);
   mLibrary = nsnull;
-  mIsDefaultPlugin = PR_FALSE;
 
 #if defined(XP_WIN) || defined(XP_OS2)
   // On Windows and OS/2 we need to keep a direct reference to
   // the plugin's function struct, we can't just copy it. See
   // Mozilla bug 85334.
 
   NPError gepError;
   nsresult gepResult = aLibrary->NP_GetEntryPoints(&mPluginFuncs, &gepError);
@@ -303,28 +302,16 @@ nsNPAPIPlugin::SetPluginRefNum(short aRe
 void
 nsNPAPIPlugin::PluginCrashed()
 {
   nsRefPtr<nsPluginHost> host = dont_AddRef(nsPluginHost::GetInst());
   host->PluginCrashed(this);
 }
 #endif
 
-void
-nsNPAPIPlugin::SetIsDefaultPlugin()
-{
-  mIsDefaultPlugin = PR_TRUE;
-}
-
-PRBool
-nsNPAPIPlugin::IsDefaultPlugin()
-{
-  return mIsDefaultPlugin;
-}
-
 namespace {
 
 #ifdef MOZ_IPC
 
 inline PRBool
 OOPPluginsEnabled(const char* aFilePath)
 {
   if (PR_GetEnv("MOZ_DISABLE_OOP_PLUGINS")) {
@@ -619,17 +606,18 @@ nsNPAPIPlugin::CreatePlugin(const char* 
 NS_METHOD
 nsNPAPIPlugin::CreatePluginInstance(nsIPluginInstance **aResult)
 {
   if (!aResult)
     return NS_ERROR_NULL_POINTER;
 
   *aResult = NULL;
 
-  nsRefPtr<nsNPAPIPluginInstance> inst = new nsNPAPIPluginInstance(this, &mPluginFuncs, mLibrary);
+  nsRefPtr<nsNPAPIPluginInstance> inst =
+    new nsNPAPIPluginInstance(&mPluginFuncs, mLibrary);
   if (!inst)
     return NS_ERROR_OUT_OF_MEMORY;
 
   NS_ADDREF(inst);
   *aResult = static_cast<nsIPluginInstance*>(inst);
   return NS_OK;
 }
 
@@ -2123,17 +2111,17 @@ NPError NP_CALLBACK
     *(NPObject **)result = _getwindowobject(npp);
 
     return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
   }
 
   case NPNVPluginElementNPObject: {
     *(NPObject **)result = _getpluginelement(npp);
 
-    return NPERR_NO_ERROR;
+    return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
   }
 
   case NPNVSupportsWindowless: {
 #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2))
     *(NPBool*)result = PR_TRUE;
 #else
     *(NPBool*)result = PR_FALSE;
 #endif
--- a/modules/plugin/base/src/nsNPAPIPlugin.h
+++ b/modules/plugin/base/src/nsNPAPIPlugin.h
@@ -92,33 +92,28 @@ public:
 #endif
 
 #ifdef MOZ_IPC
   // The IPC mechanism notifies the nsNPAPIPlugin if the plugin crashes and is
   // no longer usable.
   void PluginCrashed();
 #endif
 
-  void SetIsDefaultPlugin();
-  PRBool IsDefaultPlugin();
-
 protected:
   // Ensures that the static browser functions are properly initialized
   static void CheckClassInitialized();
 
 #ifdef XP_MACOSX
   short mPluginRefNum;
 #endif
 
   // The plugin-side callbacks that the browser calls. One set of
   // plugin callbacks for each plugin.
   NPPluginFuncs mPluginFuncs;
   PluginLibrary* mLibrary;
-
-  PRBool mIsDefaultPlugin;
 };
 
 namespace mozilla {
 namespace plugins {
 namespace parent {
 
 NPObject* NP_CALLBACK
 _getwindowobject(NPP npp);
--- a/modules/plugin/base/src/nsNPAPIPluginInstance.cpp
+++ b/modules/plugin/base/src/nsNPAPIPluginInstance.cpp
@@ -872,18 +872,17 @@ nsInstanceStream::nsInstanceStream()
 }
 
 nsInstanceStream::~nsInstanceStream()
 {
 }
 
 NS_IMPL_ISUPPORTS1(nsNPAPIPluginInstance, nsIPluginInstance)
 
-nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin,
-                                             NPPluginFuncs* callbacks,
+nsNPAPIPluginInstance::nsNPAPIPluginInstance(NPPluginFuncs* callbacks,
                                              PluginLibrary* aLibrary)
   : mCallbacks(callbacks),
 #ifdef XP_MACOSX
 #ifdef NP_NO_QUICKDRAW
     mDrawingModel(NPDrawingModelCoreGraphics),
 #else
     mDrawingModel(NPDrawingModelQuickDraw),
 #endif
@@ -894,21 +893,19 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
     mRunning(PR_FALSE),
     mCached(PR_FALSE),
     mWantsAllNetworkStreams(PR_FALSE),
     mInPluginInitCall(PR_FALSE),
     mLibrary(aLibrary),
     mStreams(nsnull),
     mMIMEType(nsnull),
     mOwner(nsnull),
-    mCurrentPluginEvent(nsnull),
-    mPlugin(plugin)
+    mCurrentPluginEvent(nsnull)
 {
-  NS_ASSERTION(mCallbacks != nsnull, "null callbacks");
-  NS_ASSERTION(mPlugin != nsnull, "null plugin");
+  NS_ASSERTION(mCallbacks != NULL, "null callbacks");
 
   // Initialize the NPP structure.
 
   mNPP.pdata = NULL;
   mNPP.ndata = this;
 
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
 }
@@ -1789,40 +1786,16 @@ nsNPAPIPluginInstance::ConvertPoint(doub
                                     double *destX, double *destY, NPCoordinateSpace destSpace)
 {
   if (mOwner)
     return mOwner->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace);
 
   return PR_FALSE;
 }
 
-nsNPAPIPlugin*
-nsNPAPIPluginInstance::Plugin()
-{
-  return mPlugin;
-}
-
-void
-nsNPAPIPluginInstance::SetURI(nsIURI* uri)
-{
-  mURI = uri;
-}
-
-nsIURI*
-nsNPAPIPluginInstance::GetURI()
-{
-  return mURI.get();
-}
-
-nsTArray< nsRefPtr<nsIStreamListener> >*
-nsNPAPIPluginInstance::StreamListeners()
-{
-  return &mStreamListeners;
-}
-
 nsresult
 nsNPAPIPluginInstance::GetDOMElement(nsIDOMElement* *result)
 {
   if (!mOwner) {
     *result = nsnull;
     return NS_ERROR_FAILURE;
   }
 
--- a/modules/plugin/base/src/nsNPAPIPluginInstance.h
+++ b/modules/plugin/base/src/nsNPAPIPluginInstance.h
@@ -44,19 +44,16 @@
 #include "nsTArray.h"
 #include "nsIPlugin.h"
 #include "nsIPluginInstance.h"
 #include "nsIPluginTagInfo.h"
 #include "nsPIDOMWindow.h"
 #include "nsIPluginInstanceOwner.h"
 #include "nsITimer.h"
 #include "mozilla/TimeStamp.h"
-#include "nsPluginTags.h"
-#include "nsIStreamListener.h"
-#include "nsIURI.h"
 
 #include "npfunctions.h"
 #include "mozilla/PluginLibrary.h"
 
 class nsNPAPIPluginStreamListener;
 class nsPIDOMWindow;
 
 struct nsInstanceStream
@@ -104,17 +101,17 @@ public:
   void SetEventModel(NPEventModel aModel);
 #endif
 
   nsresult NewNotifyStream(nsIPluginStreamListener** listener, 
                            void* notifyData, 
                            PRBool aCallNotify,
                            const char * aURL);
 
-  nsNPAPIPluginInstance(nsNPAPIPlugin* plugin, NPPluginFuncs* callbacks, PluginLibrary* aLibrary);
+  nsNPAPIPluginInstance(NPPluginFuncs* callbacks, PluginLibrary* aLibrary);
 
   // Use Release() to destroy this
   virtual ~nsNPAPIPluginInstance();
 
   // returns the state of mStarted
   PRBool IsRunning();
 
   // return is only valid when the plugin is not running
@@ -129,21 +126,16 @@ public:
 
   nsresult GetDOMElement(nsIDOMElement* *result);
 
   nsNPAPITimer* TimerWithID(uint32_t id, PRUint32* index);
   uint32_t      ScheduleTimer(uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
   void          UnscheduleTimer(uint32_t timerID);
   NPError       PopUpContextMenu(NPMenu* menu);
   NPBool        ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
-
-  nsNPAPIPlugin* Plugin();
-  void SetURI(nsIURI* uri);
-  nsIURI* GetURI();
-  nsTArray< nsRefPtr<nsIStreamListener> > *StreamListeners();
 protected:
   nsresult InitializePlugin();
 
   nsresult GetTagType(nsPluginTagType *result);
   nsresult GetAttributes(PRUint16& n, const char*const*& names,
                          const char*const*& values);
   nsresult GetParameters(PRUint16& n, const char*const*& names,
                          const char*const*& values);
@@ -189,15 +181,11 @@ private:
   nsTArray<nsNPAPITimer*> mTimers;
 
   // non-null during a HandleEvent call
   void* mCurrentPluginEvent;
 
   // Timestamp for the last time this plugin was stopped.
   // This is only valid when the plugin is actually stopped!
   mozilla::TimeStamp mStopTime;
-
-  nsNPAPIPlugin* mPlugin;
-  nsCOMPtr<nsIURI> mURI;
-  nsTArray< nsRefPtr<nsIStreamListener> > mStreamListeners;
 };
 
 #endif // nsNPAPIPluginInstance_h_
--- a/modules/plugin/base/src/nsPluginHost.cpp
+++ b/modules/plugin/base/src/nsPluginHost.cpp
@@ -1003,35 +1003,39 @@ nsresult nsPluginStreamListenerPeer::Ini
 nsresult
 nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
 {
   nsresult rv = NS_OK;
 
   PRBool useExistingCacheFile = PR_FALSE;
 
   nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
-  nsTArray< nsRefPtr<nsNPAPIPluginInstance> > *instances = pluginHost->InstanceArray();
-  for (PRUint32 i = 0; i < instances->Length(); i++) {
-    nsNPAPIPluginInstance *instance = (*instances)[i];
-    nsTArray< nsRefPtr<nsIStreamListener> > *streamListeners = instance->StreamListeners();
-    // most recent streams are at the end of list
-    PRInt32 cnt = streamListeners->Length();
-    while (--cnt >= 0) {
-      nsPluginStreamListenerPeer *lp = static_cast<nsPluginStreamListenerPeer*>(streamListeners->ElementAt(cnt).get());
-      if (lp && lp->mLocalCachedFile && lp->mPluginStreamInfo) {
-        useExistingCacheFile = lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo);
-        if (useExistingCacheFile) {
-          mLocalCachedFile = lp->mLocalCachedFile;
-          NS_ADDREF(mLocalCachedFile);
-          break;
+  nsTArray< nsAutoPtr<nsPluginInstanceTag> > *instanceTags = pluginHost->InstanceTagArray();
+  for (PRUint32 i = 0; i < instanceTags->Length(); i++) {
+    nsPluginInstanceTag *instanceTag = (*instanceTags)[i];
+    if (instanceTag->mStreams) {
+      // most recent streams are at the end of list
+      PRInt32 cnt;
+      instanceTag->mStreams->Count((PRUint32*)&cnt);
+      while (--cnt >= 0) {
+        nsPluginStreamListenerPeer *lp =
+          reinterpret_cast<nsPluginStreamListenerPeer*>(instanceTag->mStreams->ElementAt(cnt));
+        if (lp && lp->mLocalCachedFile && lp->mPluginStreamInfo) {
+          useExistingCacheFile = lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo);
+          if (useExistingCacheFile) {
+            mLocalCachedFile = lp->mLocalCachedFile;
+            NS_ADDREF(mLocalCachedFile);
+            break;
+          }
+          NS_RELEASE(lp);
         }
       }
+      if (useExistingCacheFile)
+        break;
     }
-    if (useExistingCacheFile)
-      break;
   }
 
   if (!useExistingCacheFile) {
     nsCOMPtr<nsIFile> pluginTmp;
     rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
     if (NS_FAILED(rv)) {
       return rv;
     }
@@ -1072,18 +1076,26 @@ nsPluginStreamListenerPeer::SetupPluginC
     // add one extra refcnt, we can use NS_RELEASE2(mLocalCachedFile...) in dtor
     // to remove this file when refcnt == 1
     NS_ADDREF(mLocalCachedFile);
   }
 
   // add this listenerPeer to list of stream peers for this instance
   // it'll delay release of listenerPeer until nsPluginInstanceTag::~nsPluginInstanceTag
   // and the temp file is going to stay alive until then
-  nsNPAPIPluginInstance* instance = static_cast<nsNPAPIPluginInstance*>(mInstance);
-  instance->StreamListeners()->AppendElement(static_cast<nsIStreamListener*>(this));
+  nsPluginInstanceTag *instanceTag = pluginHost->FindInstanceTag(mInstance);
+  if (instanceTag) {
+    if (!instanceTag->mStreams &&
+        (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(instanceTag->mStreams))))) {
+      return rv;
+    }
+
+    nsISupports* supports = static_cast<nsISupports*>((static_cast<nsIStreamListener*>(this)));
+    instanceTag->mStreams->AppendElement(supports);
+  }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
                                            nsISupports* aContext)
 {
@@ -1756,29 +1768,29 @@ PRBool nsPluginHost::IsRunningPlugin(nsP
 {
   if (!plugin)
     return PR_FALSE;
 
   if (!plugin->mLibrary)
     return PR_FALSE;
 
   for (int i = 0; i < plugin->mVariants; i++) {
-    nsNPAPIPluginInstance *instance = FindInstance(plugin->mMimeTypeArray[i]);
-    if (instance && instance->IsRunning())
+    nsPluginInstanceTag *instanceTag = FindInstanceTag(plugin->mMimeTypeArray[i]);
+    if (instanceTag && instanceTag->mInstance->IsRunning())
       return PR_TRUE;
   }
 
   return PR_FALSE;
 }
 
 nsresult nsPluginHost::ReloadPlugins(PRBool reloadPages)
 {
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
-  reloadPages, mInstances.Length()));
+  reloadPages, mInstanceTags.Length()));
 
   nsresult rv = NS_OK;
 
   // this will create the initial plugin list out of cache
   // if it was not created yet
   if (!mPluginsLoaded)
     return LoadPlugins();
 
@@ -1849,17 +1861,17 @@ nsresult nsPluginHost::ReloadPlugins(PRB
       c > 0) {
     nsCOMPtr<nsIRunnable> ev = new nsPluginDocReframeEvent(instsToReload);
     if (ev)
       NS_DispatchToCurrentThread(ev);
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::ReloadPlugins End active_instance_count=%d\n",
-  mInstances.Length()));
+  mInstanceTags.Length()));
 
   return rv;
 }
 
 #define NS_RETURN_UASTRING_SIZE 128
 
 nsresult nsPluginHost::UserAgent(const char **retstring)
 {
@@ -2216,18 +2228,18 @@ void nsPluginHost::UnloadUnusedLibraries
       PostPluginUnloadEvent(library);
   }
   mUnusedLibraries.Clear();
 }
 
 void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
 {
   PRBool hasInstance = PR_FALSE;
-  for (PRUint32 i = 0; i < mInstances.Length(); i++) {
-    if (TagForPlugin(mInstances[i]->Plugin()) == aPluginTag) {
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    if (mInstanceTags[i]->mPluginTag == aPluginTag) {
       hasInstance = PR_TRUE;
       break;
     }
   }
 
   if (!hasInstance) {
     nsresult rv;
     nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
@@ -2564,17 +2576,17 @@ NS_IMETHODIMP nsPluginHost::InstantiateF
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::InstantiateFullPagePlugin End mime=%s, rv=%d, owner=%p, url=%s\n",
   aMimeType, rv, aOwner, urlSpec.get()));
 
   return rv;
 }
 
 nsPluginTag*
-nsPluginHost::TagForPlugin(nsNPAPIPlugin* aPlugin)
+nsPluginHost::FindTagForPlugin(nsIPlugin* aPlugin)
 {
   nsPluginTag* pluginTag;
   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
     if (pluginTag->mEntryPoint == aPlugin) {
       return pluginTag;
     }
   }
   return nsnull;
@@ -2584,21 +2596,23 @@ nsresult nsPluginHost::FindStoppedPlugin
                                                nsIPluginInstanceOwner *aOwner)
 {
   nsCAutoString url;
   if (!aURL)
     return NS_ERROR_FAILURE;
 
   aURL->GetAsciiSpec(url);
 
-  nsNPAPIPluginInstance *instance = FindStoppedInstance(url.get());
-  if (instance && !instance->IsRunning()) {
+  nsPluginInstanceTag *instanceTag = FindStoppedInstanceTag(url.get());
+
+  if (instanceTag && !instanceTag->mInstance->IsRunning()) {
     NPWindow* window = nsnull;
     aOwner->GetWindow(window);
 
+    nsIPluginInstance* instance = static_cast<nsIPluginInstance*>(instanceTag->mInstance);
     aOwner->SetInstance(instance);
     instance->SetOwner(aOwner);
 
     instance->Start();
     aOwner->CreateWidget();
 
     // If we've got a native window, the let the plugin know about it.
     if (window->window) {
@@ -2606,16 +2620,44 @@ nsresult nsPluginHost::FindStoppedPlugin
       ((nsPluginNativeWindow*)window)->CallSetWindow(inst);
     }
 
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
+nsresult nsPluginHost::AddInstanceToActiveList(nsCOMPtr<nsIPlugin> aPlugin,
+                                               nsIPluginInstance* aInstance,
+                                               nsIURI* aURL,
+                                               PRBool aDefaultPlugin)
+{
+  nsCAutoString url;
+  // It's OK to not have a URL here, as is the case with the dummy
+  // Java plugin. In that case simply use an empty string...
+  if (aURL)
+    aURL->GetSpec(url);
+
+  // Let's find the corresponding plugin tag by matching nsIPlugin pointer.
+  // It is going to be used later when we decide whether or not we should delay
+  // unloading NPAPI dll from memory.
+  nsPluginTag * pluginTag = nsnull;
+  if (aPlugin) {
+    pluginTag = FindTagForPlugin(aPlugin);
+    NS_ASSERTION(pluginTag, "Plugin tag not found");
+  }
+
+  nsPluginInstanceTag *instanceTag = new nsPluginInstanceTag(pluginTag, aInstance, url.get(), aDefaultPlugin);
+  if (!instanceTag)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  mInstanceTags.AppendElement(instanceTag);
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsPluginHost::SetUpPluginInstance(const char *aMimeType,
                                                 nsIURI *aURL,
                                                 nsIPluginInstanceOwner *aOwner)
 {
   nsresult rv = NS_OK;
 
   rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
 
@@ -2725,31 +2767,30 @@ nsPluginHost::TrySetUpPluginInstance(con
       firstJavaPlugin = TRUE;
     }
 #endif
   }
 
   if (NS_FAILED(result))
     return result;
 
-  static_cast<nsNPAPIPluginInstance*>(instance.get())->SetURI(aURL);
-
   // it is adreffed here
   aOwner->SetInstance(instance);
 
   // this should not addref the instance or owner
   // except in some cases not Java, see bug 140931
   // our COM pointer will free the peer
   result = instance->Initialize(aOwner, mimetype);
   if (NS_FAILED(result)) {
     aOwner->SetInstance(nsnull);
     return result;
   }
 
-  mInstances.AppendElement(static_cast<nsNPAPIPluginInstance*>(instance.get()));
+  // instance and peer will be addreffed here
+  result = AddInstanceToActiveList(plugin, instance, aURL, PR_FALSE);
 
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec2;
   if (aURL)
     aURL->GetSpec(urlSpec2);
 
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
         ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
@@ -2781,19 +2822,16 @@ nsPluginHost::SetUpDefaultPluginInstance
   GetPlugin("*", getter_AddRefs(plugin));
 
   nsresult result = NS_ERROR_OUT_OF_MEMORY;
   if (plugin)
     result = plugin->CreatePluginInstance(getter_AddRefs(instance));
   if (NS_FAILED(result))
     return result;
 
-  static_cast<nsNPAPIPlugin*>(plugin.get())->SetIsDefaultPlugin();
-  static_cast<nsNPAPIPluginInstance*>(instance.get())->SetURI(aURL);
-
   // it is adreffed here
   aOwner->SetInstance(instance);
 
   // if we don't have a mimetype, check by file extension
   nsXPIDLCString mt;
   if (!mimetype || !*mimetype) {
     nsresult res = NS_OK;
     nsCOMPtr<nsIMIMEService> ms (do_GetService(NS_MIMESERVICE_CONTRACTID, &res));
@@ -2807,17 +2845,17 @@ nsPluginHost::SetUpDefaultPluginInstance
   // this should not addref the instance or owner
   result = instance->Initialize(aOwner, mimetype);
   if (NS_FAILED(result)) {
     aOwner->SetInstance(nsnull);
     return result;
   }
 
   // instance will be addreffed here
-  mInstances.AppendElement(static_cast<nsNPAPIPluginInstance*>(instance.get()));
+  result = AddInstanceToActiveList(plugin, instance, aURL, PR_TRUE);
 
   return result;
 }
 
 NS_IMETHODIMP
 nsPluginHost::IsPluginEnabledForType(const char* aMimeType)
 {
   // Pass PR_FALSE as the second arg so we can return NS_ERROR_PLUGIN_DISABLED
@@ -4498,74 +4536,75 @@ nsPluginHost::StopPluginInstance(nsIPlug
     return NS_OK;
   }
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
 
   aInstance->Stop();
 
-  nsNPAPIPluginInstance* instance = static_cast<nsNPAPIPluginInstance*>(aInstance);
-
-  // if the plugin does not want to be 'cached' just remove it
-  PRBool doCache = PR_TRUE;
-  aInstance->ShouldCache(&doCache);
-  if (doCache) {
-    // try to get the max cached plugins from a pref or use default
-    PRUint32 cachedPluginLimit;
-    nsresult rv = NS_ERROR_FAILURE;
-    if (mPrefService)
-      rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&cachedPluginLimit);
-    if (NS_FAILED(rv))
-      cachedPluginLimit = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
-    
-    if (StoppedInstanceCount() >= cachedPluginLimit) {
-      nsNPAPIPluginInstance *oldestInstance = FindOldestStoppedInstance();
-      if (oldestInstance) {
-        nsPluginTag* pluginTag = TagForPlugin(oldestInstance->Plugin());
-        mInstances.RemoveElement(oldestInstance);
-        OnPluginInstanceDestroyed(pluginTag);
+  nsPluginInstanceTag * instanceTag = FindInstanceTag(aInstance);
+  if (instanceTag) {
+    // if the plugin does not want to be 'cached' just remove it
+    PRBool doCache = PR_TRUE;
+    aInstance->ShouldCache(&doCache);
+    if (doCache) {
+      // try to get the max cached plugins from a pref or use default
+      PRUint32 cachedPluginLimit;
+      nsresult rv = NS_ERROR_FAILURE;
+      if (mPrefService)
+        rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&cachedPluginLimit);
+      if (NS_FAILED(rv))
+        cachedPluginLimit = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
+      
+      if (StoppedInstanceTagCount() >= cachedPluginLimit) {
+        nsPluginInstanceTag * oldestInstanceTag = FindOldestStoppedInstanceTag();
+        if (oldestInstanceTag) {
+          nsPluginTag* pluginTag = oldestInstanceTag->mPluginTag;
+          mInstanceTags.RemoveElement(oldestInstanceTag);
+          OnPluginInstanceDestroyed(pluginTag);
+        }
       }
+    } else {
+      nsPluginTag* pluginTag = instanceTag->mPluginTag;
+      mInstanceTags.RemoveElement(instanceTag);
+      OnPluginInstanceDestroyed(pluginTag);
     }
-  } else {
-    nsPluginTag* pluginTag = TagForPlugin(instance->Plugin());
-    mInstances.RemoveElement(instance);
-    OnPluginInstanceDestroyed(pluginTag);
   }
 
   return NS_OK;
 }
 
-nsNPAPIPluginInstance*
-nsPluginHost::FindOldestStoppedInstance()
+nsPluginInstanceTag*
+nsPluginHost::FindOldestStoppedInstanceTag()
 {
-  nsNPAPIPluginInstance *oldestInstance = nsnull;
+  nsPluginInstanceTag *oldestInstanceTag = nsnull;
   TimeStamp oldestTime = TimeStamp::Now();
-  for (PRUint32 i = 0; i < mInstances.Length(); i++) {
-    nsNPAPIPluginInstance *instance = mInstances[i];
-    if (instance->IsRunning())
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (instanceTag->mInstance->IsRunning())
       continue;
 
-    TimeStamp time = instance->LastStopTime();
+    TimeStamp time = instanceTag->mInstance->LastStopTime();
     if (time < oldestTime) {
       oldestTime = time;
-      oldestInstance = instance;
+      oldestInstanceTag = instanceTag;
     }
   }
 
-  return oldestInstance;
+  return oldestInstanceTag;
 }
 
 PRUint32
-nsPluginHost::StoppedInstanceCount()
+nsPluginHost::StoppedInstanceTagCount()
 {
   PRUint32 stoppedCount = 0;
-  for (PRUint32 i = 0; i < mInstances.Length(); i++) {
-    nsNPAPIPluginInstance *instance = mInstances[i];
-    if (!instance->IsRunning())
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (!instanceTag->mInstance->IsRunning())
       stoppedCount++;
   }
   return stoppedCount;
 }
 
 nsresult nsPluginHost::NewEmbeddedPluginStreamListener(nsIURI* aURL,
                                                        nsIPluginInstanceOwner *aOwner,
                                                        nsIPluginInstance* aInstance,
@@ -4643,36 +4682,41 @@ nsresult nsPluginHost::NewFullPagePlugin
   nsresult rv;
 
   rv = listener->InitializeFullPage(aInstance);
 
   aStreamListener = listener;
   NS_ADDREF(listener);
 
   // add peer to list of stream peers for this instance
-  nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aInstance);
-  instance->StreamListeners()->AppendElement(aStreamListener);
+  nsPluginInstanceTag * p = FindInstanceTag(aInstance);
+  if (p) {
+    if (!p->mStreams && (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(p->mStreams)))))
+      return rv;
+    p->mStreams->AppendElement(aStreamListener);
+  }
 
   return rv;
 }
 
 NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
                                     const char *aTopic,
                                     const PRUnichar *someData)
 {
   if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
     OnShutdown();
     Destroy();
     UnloadUnusedLibraries();
     sInst->Release();
   }
   if (!nsCRT::strcmp(NS_PRIVATE_BROWSING_SWITCH_TOPIC, aTopic)) {
     // inform all active plugins of changed private mode state
-    for (PRUint32 i = 0; i < mInstances.Length(); i++) {
-      mInstances[i]->PrivateModeStateChanged();
+    for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+      nsNPAPIPluginInstance* pi = static_cast<nsNPAPIPluginInstance*>(mInstanceTags[i]->mInstance);
+      pi->PrivateModeStateChanged();
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPluginHost::HandleBadPlugin(PRLibrary* aLibrary, nsIPluginInstance *aInstance)
 {
@@ -4723,22 +4767,26 @@ nsPluginHost::HandleBadPlugin(PRLibrary*
       return rv;
 
     if (NS_FAILED(rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginCheckboxMessage").get(),
                                  getter_Copies(checkboxMessage))))
       return rv;
 
     // add plugin name to the message
     nsCString pluginname;
-    nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aInstance);
-    nsPluginTag *tag = TagForPlugin(instance->Plugin());
-    if (!tag->mName.IsEmpty())
-      pluginname = tag->mName;
-    else
-      pluginname = tag->mFileName;
+    nsPluginInstanceTag * p = FindInstanceTag(aInstance);
+    if (p) {
+      nsPluginTag * tag = p->mPluginTag;
+      if (tag) {
+        if (!tag->mName.IsEmpty())
+          pluginname = tag->mName;
+        else
+          pluginname = tag->mFileName;
+      }
+    }
 
     NS_ConvertUTF8toUTF16 msg(pluginname);
     msg.AppendLiteral("\n\n");
     msg.Append(message);
 
     PRInt32 buttonPressed;
     PRBool checkboxState = PR_FALSE;
     rv = prompt->ConfirmEx(title, msg.get(),
@@ -5045,36 +5093,38 @@ nsPluginHost::InstantiateDummyJavaPlugin
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPluginHost::GetPluginName(nsIPluginInstance *aPluginInstance,
                             const char** aPluginName)
 {
-  nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aPluginInstance);
-  if (!instance)
+  nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance);
+  if (!instanceTag || !instanceTag->mPluginTag)
     return NS_ERROR_FAILURE;
 
-  *aPluginName = TagForPlugin(instance->Plugin())->mName.get();
+  *aPluginName = instanceTag->mPluginTag->mName.get();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPluginHost::GetPluginTagForInstance(nsIPluginInstance *aPluginInstance,
                                       nsIPluginTag **aPluginTag)
 {
   NS_ENSURE_ARG_POINTER(aPluginInstance);
   NS_ENSURE_ARG_POINTER(aPluginTag);
 
-  nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aPluginInstance);
-  *aPluginTag = TagForPlugin(instance->Plugin());
+  nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance);
+
+  NS_ENSURE_TRUE(instanceTag && instanceTag->mPluginTag, NS_ERROR_FAILURE);
+  
+  *aPluginTag = instanceTag->mPluginTag;
   NS_ADDREF(*aPluginTag);
-
   return NS_OK;
 }
 
 nsresult nsPluginHost::AddUnusedLibrary(PRLibrary * aLibrary)
 {
   if (!mUnusedLibraries.Contains(aLibrary)) // don't add duplicates
     mUnusedLibraries.AppendElement(aLibrary);
 
@@ -5150,96 +5200,106 @@ NS_IMETHODIMP nsPluginHost::Notify(nsITi
 #endif
   return NS_ERROR_FAILURE;
 }
 
 #ifdef MOZ_IPC
 void
 nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin)
 {
-  nsPluginTag* pluginTag = TagForPlugin(aPlugin);
+  nsPluginTag* pluginTag = FindTagForPlugin(aPlugin);
   if (!pluginTag) {
     NS_WARNING("nsPluginTag not found in nsPluginHost::PluginCrashed");
     return;
   }
 
   // Invalidate each nsPluginInstanceTag for the crashed plugin
 
-  for (PRUint32 i = mInstances.Length(); i > 0; i--) {
-    nsNPAPIPluginInstance* instance = mInstances[i - 1];
-    if (TagForPlugin(instance->Plugin()) == pluginTag) {
+  for (PRUint32 i = mInstanceTags.Length(); i > 0; i--) {
+    nsPluginInstanceTag* instanceTag = mInstanceTags[i - 1];
+    if (instanceTag->mPluginTag == pluginTag) {
       // notify the content node (nsIObjectLoadingContent) that the plugin has crashed
       nsCOMPtr<nsIDOMElement> domElement;
-      instance->GetDOMElement(getter_AddRefs(domElement));
+      instanceTag->mInstance->GetDOMElement(getter_AddRefs(domElement));
       nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
       if (objectContent) {
         objectContent->PluginCrashed();
       }
-
-      instance->Stop();
-
-      nsPluginTag* pluginTag = TagForPlugin(instance->Plugin());
-      mInstances.RemoveElement(instance);
+      
+      instanceTag->mInstance->Stop();
+
+      nsPluginTag* pluginTag = instanceTag->mPluginTag;
+      mInstanceTags.RemoveElement(instanceTag);
       OnPluginInstanceDestroyed(pluginTag);
     }
   }
 
   // Only after all instances have been invalidated is it safe to null
   // out nsPluginTag.mEntryPoint. The next time we try to create an
   // instance of this plugin we reload it (launch a new plugin process).
 
   pluginTag->mEntryPoint = nsnull;
 }
 #endif
 
-nsNPAPIPluginInstance*
-nsPluginHost::FindInstance(const char *mimetype)
+nsPluginInstanceTag*
+nsPluginHost::FindInstanceTag(nsIPluginInstance *instance)
+{
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (instanceTag->mInstance == instance)
+      return instanceTag;
+  }
+  return nsnull;
+}
+
+nsPluginInstanceTag*
+nsPluginHost::FindInstanceTag(const char *mimetype)
 {
   PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
   
-  for (PRUint32 i = 0; i < mInstances.Length(); i++) {
-    nsNPAPIPluginInstance* instance = mInstances[i];
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag* instanceTag = mInstanceTags[i];
     // give it some special treatment for the default plugin first
     // because we cannot tell the default plugin by asking instance for a mime type
-    if (defaultplugin && instance->Plugin()->IsDefaultPlugin())
-      return instance;
+    if (defaultplugin && instanceTag->mDefaultPlugin)
+      return instanceTag;
+    
+    if (!instanceTag->mInstance)
+      continue;
     
     const char* mt;
-    nsresult rv = instance->GetMIMEType(&mt);
+    nsresult rv = instanceTag->mInstance->GetMIMEType(&mt);
     if (NS_FAILED(rv))
       continue;
-
+    
     if (PL_strcasecmp(mt, mimetype) == 0)
-      return instance;
+      return instanceTag;
   }
   return nsnull;
 }
 
-nsNPAPIPluginInstance*
-nsPluginHost::FindStoppedInstance(const char * url)
+nsPluginInstanceTag*
+nsPluginHost::FindStoppedInstanceTag(const char * url)
 {
-  for (PRUint32 i = 0; i < mInstances.Length(); i++) {
-    nsNPAPIPluginInstance *instance = mInstances[i];
-    nsIURI *uri = instance->GetURI();
-    if (!uri)
-      continue;
-    nsCAutoString spec;
-    uri->GetSpec(spec);
-    if (!PL_strcmp(url, spec.get()) && !instance->IsRunning())
-      return instance;
+  for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i];
+    if (!PL_strcmp(url, instanceTag->mURL) && !instanceTag->mInstance->IsRunning())
+      return instanceTag;
   }
   return nsnull;
 }
 
 void 
 nsPluginHost::StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag)
 {
-  for (PRInt32 i = mInstances.Length(); i > 0; i--) {
-    nsNPAPIPluginInstance *instance = mInstances[i - 1];
-    if (instance->IsRunning() && (!aPluginTag || aPluginTag == TagForPlugin(instance->Plugin()))) {
+  for (PRInt32 i = mInstanceTags.Length(); i > 0; i--) {
+    nsPluginInstanceTag *instanceTag = mInstanceTags[i - 1];
+    nsNPAPIPluginInstance* instance = instanceTag->mInstance;
+    if (instance->IsRunning() && (!aPluginTag || aPluginTag == instanceTag->mPluginTag)) {
       instance->SetWindow(nsnull);
       instance->Stop();
 
       // If we've been passed an array to return, lets collect all our documents,
       // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
       // to kickstart our instances.
       if (aReloadDocs) {
         nsCOMPtr<nsIPluginInstanceOwner> owner;
@@ -5247,27 +5307,27 @@ nsPluginHost::StopRunningInstances(nsISu
         if (owner) {
           nsCOMPtr<nsIDocument> doc;
           owner->GetDocument(getter_AddRefs(doc));
           if (doc && aReloadDocs->IndexOf(doc) == -1)  // don't allow for duplicates
             aReloadDocs->AppendElement(doc);
         }
       }
 
-      nsPluginTag* pluginTag = TagForPlugin(instance->Plugin());
-      mInstances.RemoveElement(instance);
+      nsPluginTag* pluginTag = instanceTag->mPluginTag;
+      mInstanceTags.RemoveElement(instanceTag);
       OnPluginInstanceDestroyed(pluginTag);
     }
   }
 }
 
-nsTArray< nsRefPtr<nsNPAPIPluginInstance> >*
-nsPluginHost::InstanceArray()
+nsTArray< nsAutoPtr<nsPluginInstanceTag> >*
+nsPluginHost::InstanceTagArray()
 {
-  return &mInstances;
+  return &mInstanceTags;
 }
 
 nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
                                                        nsISupports* aContext)
 {
   if (!mInstance)
     return NS_ERROR_FAILURE;
 
--- a/modules/plugin/base/src/nsPluginHost.h
+++ b/modules/plugin/base/src/nsPluginHost.h
@@ -158,26 +158,26 @@ public:
 
   void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible);
   void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame);
 
 #ifdef MOZ_IPC
   void PluginCrashed(nsNPAPIPlugin* plugin);
 #endif
 
-  nsNPAPIPluginInstance *FindInstance(const char *mimetype);
-  nsNPAPIPluginInstance *FindStoppedInstance(const char * url);
-  nsNPAPIPluginInstance *FindOldestStoppedInstance();
-  PRUint32 StoppedInstanceCount();
+  nsPluginInstanceTag *FindInstanceTag(nsIPluginInstance *instance);
+  nsPluginInstanceTag *FindInstanceTag(const char *mimetype);
+  nsPluginInstanceTag *FindStoppedInstanceTag(const char * url);
+  nsPluginInstanceTag *FindOldestStoppedInstanceTag();
+  PRUint32 StoppedInstanceTagCount();
 
   void StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag);
 
-  nsTArray< nsRefPtr<nsNPAPIPluginInstance> > *InstanceArray();
+  nsTArray< nsAutoPtr<nsPluginInstanceTag> > *InstanceTagArray();
 
-  nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin);
 private:
   nsresult
   TrySetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner);
 
   nsresult
   NewEmbeddedPluginStreamListener(nsIURI* aURL, nsIPluginInstanceOwner *aOwner,
                                   nsIPluginInstance* aInstance,
                                   nsIStreamListener** aListener);
@@ -191,23 +191,32 @@ private:
   // Return an nsPluginTag for this type, if any.  If aCheckEnabled is
   // true, only enabled plugins will be returned.
   nsPluginTag*
   FindPluginForType(const char* aMimeType, PRBool aCheckEnabled);
 
   nsPluginTag*
   FindPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
 
+  // Return the tag for |plugin| if found, nsnull if not.
+  nsPluginTag*
+  FindTagForPlugin(nsIPlugin* aPlugin);
+
   nsresult
   FindStoppedPluginForURL(nsIURI* aURL, nsIPluginInstanceOwner *aOwner);
 
   nsresult
   SetUpDefaultPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner);
 
   nsresult
+  AddInstanceToActiveList(nsCOMPtr<nsIPlugin> aPlugin,
+                          nsIPluginInstance* aInstance,
+                          nsIURI* aURL, PRBool aDefaultPlugin);
+
+  nsresult
   FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsChanged);
 
   nsresult
   ScanPluginsDirectory(nsIFile * pluginsDir, 
                        nsIComponentManager * compManager, 
                        PRBool aCreatePluginList,
                        PRBool * aPluginsChanged,
                        PRBool checkForUnwantedPlugins = PR_FALSE);
@@ -259,17 +268,17 @@ private:
   PRPackedBool mAllowAlienStarHandler;
 
   // set by pref plugin.default_plugin_disabled
   PRPackedBool mDefaultPluginDisabled;
 
   // set by pref plugin.disable
   PRPackedBool mPluginsDisabled;
 
-  nsTArray< nsRefPtr<nsNPAPIPluginInstance> > mInstances;
+  nsTArray< nsAutoPtr<nsPluginInstanceTag> > mInstanceTags;
 
   nsTArray<PRLibrary*> mUnusedLibraries;
 
   nsCOMPtr<nsIFile> mPluginRegFile;
   nsCOMPtr<nsIPrefBranch> mPrefService;
 #ifdef XP_WIN
   nsRefPtr<nsPluginDirServiceProvider> mPrivateDirServiceProvider;
 #endif
--- a/modules/plugin/base/src/nsPluginTags.cpp
+++ b/modules/plugin/base/src/nsPluginTags.cpp
@@ -554,8 +554,41 @@ void nsPluginTag::TryUnloadPlugin()
   mLibrary = nsnull;
   
   // Remove mime types added to the category manager
   // only if we were made 'active' by setting the host
   if (mPluginHost) {
     RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
   }
 }
+
+/* nsPluginInstanceTag */
+
+nsPluginInstanceTag::nsPluginInstanceTag(nsPluginTag* aPluginTag,
+                                         nsIPluginInstance* aInstance,
+                                         const char * url,
+                                         PRBool aDefaultPlugin)
+{
+  NS_ASSERTION(aInstance, "Must have a valid plugin instance when creating an nsPluginInstanceTag");
+  NS_ADDREF(aInstance);
+  mInstance = static_cast<nsNPAPIPluginInstance*>(aInstance);
+
+  mPluginTag = aPluginTag;
+  
+  mURL = PL_strdup(url);
+
+  mDefaultPlugin = aDefaultPlugin;
+}
+
+nsPluginInstanceTag::~nsPluginInstanceTag()
+{
+  mPluginTag = nsnull;
+
+  nsCOMPtr<nsIPluginInstanceOwner> owner;
+  mInstance->GetOwner(getter_AddRefs(owner));
+  if (owner)
+    owner->SetInstance(nsnull);
+  mInstance->InvalidateOwner();
+
+  NS_RELEASE(mInstance);
+
+  PL_strfree(mURL);
+}
--- a/modules/plugin/base/src/nsPluginTags.h
+++ b/modules/plugin/base/src/nsPluginTags.h
@@ -40,17 +40,18 @@
 #define nsPluginTags_h_
 
 #include "nscore.h"
 #include "prtypes.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIPluginTag.h"
 #include "nsIPlugin.h"
-#include "nsString.h"
+#include "nsNPAPIPluginInstance.h"
+#include "nsISupportsArray.h"
 
 class nsPluginHost;
 struct PRLibrary;
 struct nsPluginInfo;
 
 // Remember that flags are written out to pluginreg.dat, be careful
 // changing their meaning.
 #define NS_PLUGIN_FLAG_ENABLED      0x0001    // is this plugin enabled?
@@ -117,9 +118,25 @@ public:
   nsCString     mVersion;  // UTF-8
   PRInt64       mLastModifiedTime;
 private:
   PRUint32      mFlags;
   
   nsresult EnsureMembersAreUTF8();
 };
 
+struct nsPluginInstanceTag
+{
+  char*                  mURL;
+  nsRefPtr<nsPluginTag>  mPluginTag;
+  nsNPAPIPluginInstance* mInstance; // this must always be valid
+  PRBool                 mDefaultPlugin;
+  // Array holding all opened stream listeners for this entry
+  nsCOMPtr <nsISupportsArray> mStreams; 
+  
+  nsPluginInstanceTag(nsPluginTag* aPluginTag,
+                      nsIPluginInstance* aInstance, 
+                      const char * url,
+                      PRBool aDefaultPlugin);
+  ~nsPluginInstanceTag();
+};
+
 #endif // nsPluginTags_h_
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/mochitest/test_GCrace.html
@@ -0,0 +1,59 @@
+<head>
+  <title>GC race with actors on the parent</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" />
+<body onload="setTimeout(checkGCRace, 1000)">
+  <p id="display"></p>
+
+  <embed id="p" type="application/x-test" wmode="window"></embed>
+
+  <script class="testbody" type="application/javascript">
+    SimpleTest.waitForExplicitFinish();
+
+    var nested = false;
+
+    function cb(f) {
+      ok(!nested, "Callback shouldn't occur in a nested stack frame");
+      try {
+        f(35);
+        ok(true, "Callback was called, no crash");
+      }
+      catch (e) {
+        ok(false, "Exception calling callback object: " + e);
+      }
+      SimpleTest.executeSoon(removePlugin);
+    }
+
+    function removePlugin() {
+      var p = document.getElementById('p');
+      p.parentNode.removeChild(p);
+      p = null;
+      netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+      Components.utils.forceGC();
+      SimpleTest.finish();
+    }
+
+    function checkGCRace() {
+      nested = true;
+
+      // The plugin will hand back a function and immediately sleep.
+      // We will lose our only reference to the function and force GC, followed
+      // by calling us with that function object again. We should be able to
+      // call the function and not crash.
+      var p = document.getElementById('p');
+      var f = p.checkGCRace(cb);
+      f = null;  // 'f' should be collected next GC
+
+      nested = false;
+
+      setTimeout(function() {
+        netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+        Components.utils.forceGC();
+      }, 2000);
+    }
+  </script>
--- a/modules/plugin/test/testplugin/nptest.cpp
+++ b/modules/plugin/test/testplugin/nptest.cpp
@@ -41,16 +41,17 @@
 #include <stdio.h>
 #include <iostream>
 #include <string>
 #include <sstream>
 
 #ifdef XP_WIN
 #include <process.h>
 #include <float.h>
+#include <windows.h>
 #define getpid _getpid
 #else
 #include <unistd.h>
 #include <pthread.h>
 #endif
 
  using namespace std;
 
@@ -139,16 +140,17 @@ static bool crashPlugin(NPObject* npobj,
 static bool crashOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool checkObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 
 static const NPUTF8* sPluginMethodIdentifierNames[] = {
   "npnEvaluateTest",
   "npnInvokeTest",
   "npnInvokeDefaultTest",
   "setUndefinedValueTest",
   "identifierToStringTest",
   "timerTest",
@@ -176,16 +178,17 @@ static const NPUTF8* sPluginMethodIdenti
   "crashOnDestroy",
   "getObjectValue",
   "checkObjectValue",
   "enableFPExceptions",
   "setCookie",
   "getCookie",
   "getAuthInfo",
   "asyncCallbackTest",
+  "checkGCRace",
 };
 static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
 static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = {
   npnEvaluateTest,
   npnInvokeTest,
   npnInvokeDefaultTest,
   setUndefinedValueTest,
   identifierToStringTest,
@@ -214,16 +217,17 @@ static const ScriptableFunction sPluginM
   crashOnDestroy,
   getObjectValue,
   checkObjectValue,
   enableFPExceptions,
   setCookie,
   getCookie,
   getAuthInfo,
   asyncCallbackTest,
+  checkGCRace,
 };
 
 struct URLNotifyData
 {
   const char* cookie;
   NPObject* callback;
   uint32_t size;
   char* data;
@@ -2445,8 +2449,106 @@ asyncCallbackTest(NPObject* npobj, const
   id->asyncTestScriptCallback = argstr->UTF8Characters;
   
   id->asyncTestPhase = 0;
   id->asyncCallbackResult = true;
   NPN_PluginThreadAsyncCall(npp, asyncCallback, (void*)npobj);
   
   return true;
 }
+
+static bool
+GCRaceInvoke(NPObject*, NPIdentifier, const NPVariant*, uint32_t, NPVariant*)
+{
+  return false;
+}
+
+static bool
+GCRaceInvokeDefault(NPObject* o, const NPVariant* args, uint32_t argCount,
+		    NPVariant* result)
+{
+  if (1 != argCount || !NPVARIANT_IS_INT32(args[0]) ||
+      35 != NPVARIANT_TO_INT32(args[0]))
+    return false;
+
+  return true;
+}
+
+static const NPClass kGCRaceClass = {
+  NP_CLASS_STRUCT_VERSION,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  GCRaceInvoke,
+  GCRaceInvokeDefault,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+struct GCRaceData
+{
+  GCRaceData(NPP npp, NPObject* callback, NPObject* localFunc)
+    : npp_(npp)
+    , callback_(callback)
+    , localFunc_(localFunc)
+  {
+    NPN_RetainObject(callback_);
+    NPN_RetainObject(localFunc_);
+  }
+
+  ~GCRaceData()
+  {
+    NPN_ReleaseObject(callback_);
+    NPN_ReleaseObject(localFunc_);
+  }
+
+  NPP npp_;
+  NPObject* callback_;
+  NPObject* localFunc_;
+};
+
+static void
+FinishGCRace(void* closure)
+{
+  GCRaceData* rd = static_cast<GCRaceData*>(closure);
+
+#ifdef XP_WIN
+  Sleep(5000);
+#else
+  sleep(5);
+#endif
+
+  NPVariant arg;
+  OBJECT_TO_NPVARIANT(rd->localFunc_, arg);
+
+  NPVariant result;
+  bool ok = NPN_InvokeDefault(rd->npp_, rd->callback_, &arg, 1, &result);
+  if (!ok)
+    return;
+
+  NPN_ReleaseVariantValue(&result);
+  delete rd;
+}
+
+bool
+checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount,
+	    NPVariant* result)
+{
+  if (1 != argCount || !NPVARIANT_IS_OBJECT(args[0]))
+    return false;
+
+  NPP npp = static_cast<TestNPObject*>(npobj)->npp;
+  
+  NPObject* localFunc =
+    NPN_CreateObject(npp, const_cast<NPClass*>(&kGCRaceClass));
+
+  GCRaceData* rd =
+    new GCRaceData(npp, NPVARIANT_TO_OBJECT(args[0]), localFunc);
+  NPN_PluginThreadAsyncCall(npp, FinishGCRace, rd);
+
+  OBJECT_TO_NPVARIANT(localFunc, *result);
+  return true;
+}
deleted file mode 100644
deleted file mode 100644
--- a/netwerk/streamconv/converters/nsBinHexDecoder.cpp
+++ b/netwerk/streamconv/converters/nsBinHexDecoder.cpp
@@ -199,17 +199,17 @@ nsresult nsBinHexDecoder::ProcessNextSta
   {
     case BINHEX_STATE_START:
       mState = BINHEX_STATE_FNAME;
       mCount = 0;
 
       // c & 63 returns the length of mName. So if we need the length, that's how
       // you can figure it out....
       mName.SetLength(c & 63);
-      if (mName.Length() != c & 63) {
+      if (mName.Length() != (c & 63)) {
         /* XXX ProcessNextState/ProcessNextChunk aren't rv checked */
         mState = BINHEX_STATE_DONE;
       }
       break;
 
     case BINHEX_STATE_FNAME:
       mName.BeginWriting()[mCount] = c;
 
--- a/parser/htmlparser/src/nsViewSourceHTML.cpp
+++ b/parser/htmlparser/src/nsViewSourceHTML.cpp
@@ -89,16 +89,17 @@ Stopwatch vsTimer;
 //  static const char* gDumpFileName = "\\temp\\viewsource.html";
 #endif // DUMP_TO_FILE
 
 // bug 22022 - these are used to toggle 'Wrap Long Lines' on the viewsource
 // window by selectively setting/unsetting the following class defined in
 // viewsource.css; the setting is remembered between invocations using a pref.
 static const char kBodyId[] = "viewsource";
 static const char kBodyClassWrap[] = "wrap";
+static const char kBodyTabSize[] = "-moz-tab-size: ";
 
 NS_IMPL_ISUPPORTS1(CViewSourceHTML, nsIDTD)
 
 /********************************************
  ********************************************/
 
 enum {
   kStartTag = 0,
@@ -192,25 +193,29 @@ static const char* const kDumpFileAfterT
  *  @update  gess 4/9/98
  *  @param
  *  @return
  */
 CViewSourceHTML::CViewSourceHTML()
 {
   mSyntaxHighlight = PR_FALSE;
   mWrapLongLines = PR_FALSE;
+  mTabSize = -1;
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefBranch) {
     PRBool temp;
     nsresult rv;
     rv = prefBranch->GetBoolPref("view_source.syntax_highlight", &temp);
     mSyntaxHighlight = NS_SUCCEEDED(rv) ? temp : PR_TRUE;
 
     rv = prefBranch->GetBoolPref("view_source.wrap_long_lines", &temp);
     mWrapLongLines = NS_SUCCEEDED(rv) ? temp : PR_FALSE;
+
+    rv = prefBranch->GetIntPref("view_source.tab_size", &temp);
+    mTabSize = NS_SUCCEEDED(rv) ? temp : -1;
   }
 
   mSink = 0;
   mLineNumber = 1;
   mTokenizer = 0;
   mDocType=eHTML_Quirks;
   mHasOpenRoot=PR_FALSE;
   mHasOpenBody=PR_FALSE;
@@ -397,16 +402,23 @@ NS_IMETHODIMP CViewSourceHTML::BuildMode
                         NS_LITERAL_STRING("id"),
                         NS_ConvertASCIItoUTF16(kBodyId));
 
           if (mWrapLongLines) {
             AddAttrToNode(bodyNode, theAllocator,
                           NS_LITERAL_STRING("class"),
                           NS_ConvertASCIItoUTF16(kBodyClassWrap));
           }
+          if (mTabSize >= 0) {
+            nsAutoString styleValue = NS_ConvertASCIItoUTF16(kBodyTabSize);
+            styleValue.AppendInt(mTabSize);
+            AddAttrToNode(bodyNode, theAllocator,
+                          NS_LITERAL_STRING("style"),
+                          styleValue);
+          }
           result = mSink->OpenContainer(bodyNode);
           if(NS_SUCCEEDED(result)) mHasOpenBody=PR_TRUE;
         }
         IF_FREE(bodyToken, theAllocator);
 
         if (NS_SUCCEEDED(result)) {
           CStartToken* preToken =
             static_cast<CStartToken*>
--- a/parser/htmlparser/src/nsViewSourceHTML.h
+++ b/parser/htmlparser/src/nsViewSourceHTML.h
@@ -136,16 +136,17 @@ private:
 
 protected:
 
     nsCString           mCharset;
     nsIHTMLContentSink* mSink;
     PRInt32             mLineNumber;
     nsITokenizer*       mTokenizer; // weak
 
+    PRInt32             mTabSize;
     PRPackedBool        mSyntaxHighlight;
     PRPackedBool        mWrapLongLines;
     PRPackedBool        mHasOpenRoot;
     PRPackedBool        mHasOpenBody;
 
     nsDTDMode           mDTDMode;
     eParserCommands     mParserCommand;   //tells us to viewcontent/viewsource/viewerrors...
     eParserDocType      mDocType;
--- a/security/manager/ssl/src/nsSmartCardEvent.cpp
+++ b/security/manager/ssl/src/nsSmartCardEvent.cpp
@@ -103,26 +103,22 @@ NS_IMETHODIMP nsSmartCardEvent::Duplicat
 NS_IMETHODIMP nsSmartCardEvent::SetTarget(nsIDOMEventTarget *aTarget)
 {
   NS_ASSERTION(mPrivate, "SmartCardEvent called without Init");
   return mPrivate->SetTarget(aTarget);
 }
 
 NS_IMETHODIMP_(PRBool ) nsSmartCardEvent::IsDispatchStopped()
 {
-  PRBool  isDispatchPrevented = nsnull;
-  PRBool * aIsDispatchPrevented = &isDispatchPrevented;
   NS_ASSERTION(mPrivate, "SmartCardEvent called without Init");
   return mPrivate->IsDispatchStopped();
 }
 
 NS_IMETHODIMP_(nsEvent*) nsSmartCardEvent::GetInternalNSEvent()
 {
-  nsEvent* nSEvent = nsnull;
-  nsEvent** aNSEvent = &nSEvent;
   NS_ASSERTION(mPrivate, "SmartCardEvent called without Init");
   return mPrivate->GetInternalNSEvent();
 }
 
 NS_IMETHODIMP nsSmartCardEvent::SetTrusted(PRBool aResult)
 {
   NS_ASSERTION(mPrivate, "SmartCardEvent called without Init");
   return mPrivate->SetTrusted(aResult);
--- a/storage/src/Variant_inl.h
+++ b/storage/src/Variant_inl.h
@@ -246,10 +246,17 @@ Variant_base::GetAsStringWithSize(PRUint
 inline
 NS_IMETHODIMP
 Variant_base::GetAsWStringWithSize(PRUint32 *,
                                    PRUnichar **)
 {
   return NS_ERROR_CANNOT_CONVERT_DATA;
 }
 
+inline
+NS_IMETHODIMP
+Variant_base::GetAsJSVal(jsval *)
+{
+  return NS_ERROR_CANNOT_CONVERT_DATA;
+}
+
 } // namespace storage
 } // namespace mozilla
--- a/testing/mochitest/server.js
+++ b/testing/mochitest/server.js
@@ -200,16 +200,29 @@ function createMochitestServer(serverBas
   server.registerPathHandler("/server/shutdown", serverShutdown);
   server.registerContentType("sjs", "sjs"); // .sjs == CGI-like functionality
   server.registerContentType("jar", "application/x-jar");
   server.registerContentType("ogg", "application/ogg");
   server.registerContentType("ogv", "video/ogg");
   server.registerContentType("oga", "audio/ogg");
   server.setIndexHandler(defaultDirHandler);
 
+  var serverRoot =
+    {
+      getFile: function getFile(path)
+      {
+        var file = serverBasePath.clone().QueryInterface(Ci.nsILocalFile);
+        file.appendRelativePath(path);
+        return file;
+      },
+      QueryInterface: function(aIID) { return this; }
+    };
+
+  server.setObjectState("SERVER_ROOT", serverRoot);
+
   processLocations(server);
 
   return server;
 }
 
 /**
  * Notifies the HTTP server about all the locations at which it might receive
  * requests, so that it can properly respond to requests on any of the hosts it
--- a/testing/mochitest/ssltunnel/ssltunnel.cpp
+++ b/testing/mochitest/ssltunnel/ssltunnel.cpp
@@ -412,17 +412,20 @@ void HandleConnection(void* data)
   bool client_error = false;
   bool connect_accepted = !do_http_proxy;
   bool ssl_updated = !do_http_proxy;
   bool expect_request_start = do_http_proxy;
   string certificateToUse;
   client_auth_option clientAuth;
   string fullHost;
 
-  printf("SSLTUNNEL(%p): incoming connection csock(0)=%p, ssock(1)=%p\n", data, ci->client_sock, (PRFileDesc*)other_sock);
+  printf("SSLTUNNEL(%p): incoming connection csock(0)=%p, ssock(1)=%p\n",
+         static_cast<void*>(data),
+         static_cast<void*>(ci->client_sock),
+         static_cast<void*>(other_sock));
   if (other_sock) 
   {
     PRInt32 numberOfSockets = 1;
 
     relayBuffer buffers[2];
 
     if (!do_http_proxy)
     {
@@ -440,61 +443,69 @@ void HandleConnection(void* data)
       {other_sock, PR_POLL_READ, 0}
     };
     PRBool socketErrorState[2] = {PR_FALSE, PR_FALSE};
 
     while (!((client_error||client_done) && buffers[0].empty() && buffers[1].empty()))
     {
       sockets[0].in_flags |= PR_POLL_EXCEPT;
       sockets[1].in_flags |= PR_POLL_EXCEPT;
-      printf("SSLTUNNEL(%p): polling flags csock(0)=%c%c, ssock(1)=%c%c\n", data, 
-		sockets[0].in_flags & PR_POLL_READ  ? 'R' : '-', 
-		sockets[0].in_flags & PR_POLL_WRITE ? 'W' : '-',
-		sockets[1].in_flags & PR_POLL_READ  ? 'R' : '-', 
-		sockets[1].in_flags & PR_POLL_WRITE ? 'W' : '-');
+      printf("SSLTUNNEL(%p): polling flags csock(0)=%c%c, ssock(1)=%c%c\n",
+             static_cast<void*>(data),
+             sockets[0].in_flags & PR_POLL_READ  ? 'R' : '-',
+             sockets[0].in_flags & PR_POLL_WRITE ? 'W' : '-',
+             sockets[1].in_flags & PR_POLL_READ  ? 'R' : '-',
+             sockets[1].in_flags & PR_POLL_WRITE ? 'W' : '-');
       PRInt32 pollStatus = PR_Poll(sockets, numberOfSockets, PR_MillisecondsToInterval(1000));
       if (pollStatus < 0)
       {
-        printf("SSLTUNNEL(%p): pollStatus=%d, exiting\n", data, pollStatus);
+        printf("SSLTUNNEL(%p): pollStatus=%d, exiting\n",
+               static_cast<void*>(data), pollStatus);
         client_error = true;
         break;
       }
 
       if (pollStatus == 0)
       {
         // timeout
-        printf("SSLTUNNEL(%p): poll timeout, looping\n", data);
+        printf("SSLTUNNEL(%p): poll timeout, looping\n",
+               static_cast<void*>(data));
         continue;
       }
 
       for (PRInt32 s = 0; s < numberOfSockets; ++s)
       {
         PRInt32 s2 = s == 1 ? 0 : 1;
         PRInt16 out_flags = sockets[s].out_flags;
         PRInt16 &in_flags = sockets[s].in_flags;
         PRInt16 &in_flags2 = sockets[s2].in_flags;
         sockets[s].out_flags = 0;
 
-        printf("SSLTUNNEL(%p): %csock(%d)=%p out_flags=%d", data, s==0?'c':'s', s, sockets[s].fd, out_flags);
+        printf("SSLTUNNEL(%p): %csock(%d)=%p out_flags=%d",
+               static_cast<void*>(data),
+               s == 0 ? 'c' : 's',
+               s,
+               static_cast<void*>(sockets[s].fd),
+               out_flags);
         if (out_flags & (PR_POLL_EXCEPT | PR_POLL_ERR | PR_POLL_HUP))
         {
           printf(" :exception\n");
           client_error = true;
           socketErrorState[s] = PR_TRUE;
           // We got a fatal error state on the socket. Clear the output buffer
           // for this socket to break the main loop, we will never more be able
           // to send those data anyway.
           buffers[s2].bufferhead = buffers[s2].buffertail = buffers[s2].buffer;
           continue;
         } // PR_POLL_EXCEPT, PR_POLL_ERR, PR_POLL_HUP handling
 
         if (out_flags & PR_POLL_READ && !buffers[s].free())
         {
            printf(" no place in read buffer but got read flag, dropping it now!");
-	   in_flags &= ~PR_POLL_READ;
+           in_flags &= ~PR_POLL_READ;
         }
 
         if (out_flags & PR_POLL_READ && buffers[s].free())
         {
           printf(" :reading");
           PRInt32 bytesRead = PR_Recv(sockets[s].fd, buffers[s].buffertail, 
               buffers[s].free(), 0, PR_INTERVAL_NO_TIMEOUT);
 
@@ -645,17 +656,20 @@ void HandleConnection(void* data)
         } // PR_POLL_WRITE handling
         printf("\n"); // end the log
       } // for...
     } // while, poll
   }
   else
     client_error = true;
 
-  printf("SSLTUNNEL(%p): exiting root function for csock=%p, ssock=%p\n", data, ci->client_sock, (PRFileDesc*)other_sock);
+  printf("SSLTUNNEL(%p): exiting root function for csock=%p, ssock=%p\n",
+         static_cast<void*>(data),
+         static_cast<void*>(ci->client_sock),
+         static_cast<void*>(other_sock));
   if (!client_error)
     PR_Shutdown(ci->client_sock, PR_SHUTDOWN_SEND);
   PR_Close(ci->client_sock);
 
   delete ci;
 }
 
 /*
--- a/toolkit/components/exthelper/extApplication.js
+++ b/toolkit/components/exthelper/extApplication.js
@@ -135,17 +135,17 @@ Events.prototype = {
     function hasFilter(element) {
       return (element.event != aEvent) || (element.listener != aListener);
     }
 
     this._listeners = this._listeners.filter(hasFilter);
   },
 
   dispatch : function evts_dispatch(aEvent, aEventItem) {
-    eventItem = new EventItem(aEvent, aEventItem);
+    var eventItem = new EventItem(aEvent, aEventItem);
 
     this._listeners.forEach(function(key){
       if (key.event == aEvent) {
         key.listener.handleEvent ?
           key.listener.handleEvent(eventItem) :
           key.listener(eventItem);
       }
     });
--- a/toolkit/content/plugins.css
+++ b/toolkit/content/plugins.css
@@ -106,18 +106,14 @@ td + td {
 }
 
 td {
   text-align: start;
   border-top: 1px dotted ThreeDShadow;
 }
 
 th.type, th.suff {
-  width: 20%;
+  width: 25%;
 }
 
 th.desc {
   width: 50%;
 }
-
-th.enabled {
-  width: 10%;
-}
--- a/toolkit/content/plugins.html
+++ b/toolkit/content/plugins.html
@@ -124,40 +124,31 @@
       document.write(plugin.description);
       document.writeln("<\/dd><\/dl>");
 
       document.writeln("<table border=\"1\" class=\"contenttable\">");
       document.writeln("<thead>");
       document.writeln("<tr><th class=\"type\">" + pluginsbundle.GetStringFromName("mimetype_label") + "<\/th>");
       document.writeln("<th class=\"desc\">" + pluginsbundle.GetStringFromName("description_label") + "<\/th>");
       document.writeln("<th class=\"suff\">" + pluginsbundle.GetStringFromName("suffixes_label") + "<\/th>");
-      document.writeln("<th class=\"enabled\">" + pluginsbundle.GetStringFromName("enabled_label") + "<\/th><\/tr>");
-      document.writeln("<\/thead>");
+      document.writeln("<\/tr><\/thead>");
       document.writeln("<tbody>");
 
       var numTypes = plugin.length;
       var mimetype;
-      var enabled;
-      var enabledPlugin;
       for (var j = 0; j < numTypes; j++)
       {
         mimetype = plugin[j];
 
         if (mimetype)
         {
-          enabled = pluginsbundle.GetStringFromName("no_label");
-          enabledPlugin = mimetype.enabledPlugin;
-          if (enabledPlugin && (enabledPlugin.filename == plugin.filename))
-            enabled = pluginsbundle.GetStringFromName("yes_label");
-
           document.writeln("<tr>");
           document.writeln("<td>" + mimetype.type + "<\/td>");
           document.writeln("<td>" + mimetype.description + "<\/td>");
           document.writeln("<td>" + mimetype.suffixes + "<\/td>");
-          document.writeln("<td>" + enabled + "<\/td>");
           document.writeln("<\/tr>");
         }
       }
 
       document.write("<\/tbody>");
       document.write("<\/table>");
     }
   }
--- a/toolkit/content/widgets/toolbarbutton.xml
+++ b/toolkit/content/widgets/toolbarbutton.xml
@@ -8,50 +8,50 @@
   <binding id="toolbarbutton" display="xul:button"
            extends="chrome://global/content/bindings/button.xml#button-base">
     <resources>
       <stylesheet src="chrome://global/skin/toolbarbutton.css"/>
     </resources>
     
     <content>
       <children includes="observes|template|menupopup|panel|tooltip"/>
-      <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,toolbarmode,buttonstyle,label"/>
+      <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
       <xul:label class="toolbarbutton-text" crop="right" flex="1"
-                 xbl:inherits="value=label,accesskey,crop,toolbarmode,buttonstyle"/>
+                 xbl:inherits="value=label,accesskey,crop"/>
     </content>
     
     <implementation implements="nsIAccessibleProvider">
       <property name="accessibleType" readonly="true">
         <getter>
           return Components.interfaces.nsIAccessibleProvider.XULToolbarButton;
         </getter>
       </property>
     </implementation>
   </binding>
 
   <binding id="menu" display="xul:menu" 
            extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
     <content>
       <children includes="observes|template|menupopup|panel|tooltip"/>
-      <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,toolbarmode,buttonstyle,label,type"/>
+      <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label,type"/>
       <xul:label class="toolbarbutton-text" crop="right" flex="1"
-                 xbl:inherits="value=label,accesskey,crop,dragover-top,toolbarmode,buttonstyle"/>
+                 xbl:inherits="value=label,accesskey,crop,dragover-top"/>
       <xul:dropmarker type="menu" class="toolbarbutton-menu-dropmarker" xbl:inherits="disabled,label"/>
     </content>
   </binding>
   
   <binding id="menu-vertical" display="xul:menu"
            extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
     <content>
       <children includes="observes|template|menupopup|panel|tooltip"/>
       <xul:hbox flex="1" align="center">
         <xul:vbox flex="1" align="center">
-          <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,toolbarmode,buttonstyle,label"/>
+          <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
           <xul:label class="toolbarbutton-text" crop="right" flex="1"
-                    xbl:inherits="value=label,accesskey,crop,dragover-top,toolbarmode,buttonstyle"/>
+                    xbl:inherits="value=label,accesskey,crop,dragover-top"/>
         </xul:vbox>
         <xul:dropmarker type="menu" class="toolbarbutton-menu-dropmarker" xbl:inherits="disabled,label"/>
       </xul:hbox>
     </content>
   </binding>
   
   <binding id="menu-button" display="xul:menu" 
            extends="chrome://global/content/bindings/button.xml#menu-button-base">
@@ -59,19 +59,19 @@
       <stylesheet src="chrome://global/skin/toolbarbutton.css"/>
     </resources>
 
     <content>
       <children includes="observes|template|menupopup|panel|tooltip"/>
       <xul:toolbarbutton class="box-inherit toolbarbutton-menubutton-button"
                          anonid="button" flex="1" allowevents="true"
                          xbl:inherits="disabled,crop,image,label,accesskey,command,
-                                       align,dir,pack,orient,toolbarmode,buttonstyle"/>
+                                       align,dir,pack,orient"/>
       <xul:dropmarker type="menu-button" class="toolbarbutton-menubutton-dropmarker"
-                      xbl:inherits="align,dir,pack,orient,disabled,toolbarmode,buttonstyle,label"/>
+                      xbl:inherits="align,dir,pack,orient,disabled,label"/>
     </content>
   </binding>
 
   <binding id="toolbarbutton-image"
            extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
     <content>
       <xul:image class="toolbarbutton-icon" xbl:inherits="src=image"/>
     </content>
deleted file mode 100644
--- a/toolkit/themes/gnomestripe/global/toolbarbutton.css
+++ b/toolkit/themes/gnomestripe/global/toolbarbutton.css
@@ -68,18 +68,17 @@ toolbarbutton:-moz-lwtheme {
   margin: 0 !important;
   text-align: center;
 }
 
 toolbarbutton.tabbable {
   -moz-user-focus: normal !important;
 }
 
-toolbarbutton:hover,
-toolbarbutton[buttonover="true"] {
+toolbarbutton:hover {
   border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;
   color: -moz-buttonhovertext;
 }
 
 toolbarbutton:hover:active,
 toolbarbutton[open="true"] {
   border-color: ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow;
   padding-top: 4px;
@@ -106,17 +105,17 @@ toolbarbutton[checked="true"] {
   padding-bottom: 2px !important;
   -moz-padding-start: 4px !important;
   -moz-padding-end: 2px !important;
   background-image: url("chrome://global/skin/toolbar/Lighten.png");
   color: ButtonText !important;
 }
 
 toolbarbutton[checked="true"]:hover,
-toolbarbutton[checked="true"]:hover:active { 
+toolbarbutton[checked="true"]:hover:active {
   color: -moz-buttonhovertext !important;
   background-color: -moz-buttonhoverface !important;
 }
 
 toolbarbutton:-moz-lwtheme:not(:hover):not([checked="true"]):not([open="true"]):not([disabled="true"]) {
   color: inherit;
   text-shadow: inherit;
 }
--- a/toolkit/themes/pinstripe/global/tabbox.css
+++ b/toolkit/themes/pinstripe/global/tabbox.css
@@ -9,17 +9,17 @@
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 tabbox {
   margin: 0 5px;
 }
 
 tabpanels {
-  -moz-appearance: tabpanels; 
+  -moz-appearance: tabpanels;
   padding: 33px 15px 15px;
 }
 
 tabs {
   -moz-box-align: center;
   font: menu;
 }
 
--- a/toolkit/themes/pinstripe/global/toolbarbutton.css
+++ b/toolkit/themes/pinstripe/global/toolbarbutton.css
@@ -50,50 +50,43 @@ toolbarbutton {
   text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4);
 }
 
 toolbarbutton:not([disabled="true"]):active:hover {
   text-shadow: none;
 }
 
 .toolbarbutton-icon {
-	padding: 1px 0px 1px 0px;
+  padding: 1px 0;
 }
 
 .toolbarbutton-text {
   margin: 0px;
   padding: 0px;
   text-align: center;
   vertical-align: middle;
 }
 
-toolbarbutton:hover:active[buttonstyle="text"],
-toolbarbutton[open="true"][buttonstyle="text"] {
-  color: #2c498c;
-}
-
-
-
 toolbarbutton[disabled="true"],
 toolbarbutton[disabled="true"]:hover,
 toolbarbutton[disabled="true"]:hover:active,
 toolbarbutton[disabled="true"][open="true"] {
   color: -moz-mac-disabledtoolbartext !important;
 }
 
 /* ..... checked state ..... */
 
 toolbarbutton[checked="true"] {
     background-color: #DDDDDD;
     background-image: none;
     border-right: 1px solid #b9b9b9;
     border-left: 1px solid #b9b9b9;
     color: ButtonText !important;
 }
-    
+
 /* ::::: toolbarbutton menu ::::: */
 
 .toolbarbutton-menu-dropmarker {
   -moz-appearance: none !important;
   border: none !important;
   background-color: transparent !important;
   list-style-image: url("chrome://global/skin/arrow/arrow-dn.png");
   padding: 0 0 0 2px;
@@ -123,17 +116,16 @@ toolbarbutton[type="menu-button"][disabl
 }
 
 .toolbarbutton-menubutton-button {
   -moz-box-align: center;
   -moz-box-pack: center;
   -moz-box-orient: vertical;
 }
 
-
 /* .......... dropmarker .......... */
 
 .toolbarbutton-menubutton-dropmarker {
   -moz-appearance: none !important;
   border: none !important;
   background-color: transparent !important;
   list-style-image: url("chrome://global/skin/arrow/arrow-dn.png");
   width: auto;
@@ -143,9 +135,8 @@ toolbarbutton[type="menu-button"][disabl
 .toolbarbutton-menubutton-dropmarker[disabled="true"] {
   list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.png") !important;
   padding: 0 !important;
 }
 
 toolbarbutton.tabbable {
   -moz-user-focus: normal !important;
 }
-
--- a/toolkit/themes/pinstripe/help/help.css
+++ b/toolkit/themes/pinstripe/help/help.css
@@ -87,52 +87,48 @@
 #help-print-button:not([disabled="true"]):hover { -moz-image-region: rect(24px 96px 48px 72px); }
 #help-print-button[disabled="true"] { -moz-image-region: rect(48px 96px 72px 72px); }
 #help-print-button:not([disabled="true"]):hover:active { -moz-image-region: rect(72px 96px 96px 72px); }
 
 /* Style the back/forward dropmarks to connect them to the buttons */
 
 /* Style the back dropmark */
 
-#help-back-button .toolbarbutton-menubutton-dropmarker {
+#help-back-button > .toolbarbutton-menubutton-dropmarker {
   margin-top: 3px;
   list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png");
   -moz-image-region: rect(0px, 14px, 24px, 0px);
 }
 
-#help-back-button:hover .toolbarbutton-menubutton-dropmarker, 
-#help-back-button[buttonover="true"] > .toolbarbutton-menubutton-dropmarker {
+#help-back-button:hover > .toolbarbutton-menubutton-dropmarker {
   -moz-image-region: rect(24px, 14px, 48px, 0px);
 }
 
-#help-back-button[disabled="true"] .toolbarbutton-menubutton-dropmarker {
+#help-back-button[disabled="true"] > .toolbarbutton-menubutton-dropmarker {
   list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png") !important;
   -moz-image-region: rect(48px, 14px, 72px, 0px) !important;
 }
 
-#help-back-button:hover:active .toolbarbutton-menubutton-dropmarker, 
-#help-back-button[buttondown="true"] > .toolbarbutton-menubutton-dropmarker {
+#help-back-button:hover:active > .toolbarbutton-menubutton-dropmarker {
   -moz-image-region: rect(72px, 14px, 96px, 0px);
 }
 
 /* Style the forward dropmark */
 
-#help-forward-button .toolbarbutton-menubutton-dropmarker {
+#help-forward-button > .toolbarbutton-menubutton-dropmarker {
   margin-top: 3px;
   list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png");
   -moz-image-region: rect(0px, 14px, 24px, 0px);
 }
-#help-forward-button:hover .toolbarbutton-menubutton-dropmarker, 
-#help-forward-button[buttonover="true"] > .toolbarbutton-menubutton-dropmarker {
+#help-forward-button:hover > .toolbarbutton-menubutton-dropmarker {
   -moz-image-region: rect(24px, 14px, 48px, 0px);
 }
-#help-forward-button[disabled="true"] .toolbarbutton-menubutton-dropmarker {
+#help-forward-button[disabled="true"] > .toolbarbutton-menubutton-dropmarker {
   list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png") !important;
   -moz-image-region: rect(48px, 14px, 72px, 0px) !important;
 }
-#help-forward-button:hover:active .toolbarbutton-menubutton-dropmarker, 
-#help-forward-button[buttondown="true"] > .toolbarbutton-menubutton-dropmarker {
+#help-forward-button:hover:active > .toolbarbutton-menubutton-dropmarker {
   -moz-image-region: rect(72px, 14px, 96px, 0px);
 }
 
 #helpsidebar-splitter {
   border-right: 1px solid #bebebe;
 }
--- a/toolkit/themes/winstripe/global/button.css
+++ b/toolkit/themes/winstripe/global/button.css
@@ -175,12 +175,10 @@ button[type="disclosure"] {
   padding: 0px !important;
   -moz-appearance: none;
   list-style-image: url("chrome://global/skin/tree/twisty-clsd.png");
   min-width: 0px !important;
   background-color: transparent;
 }
 
 button[type="disclosure"][open="true"] {
-  list-style-image: url("chrome://global/skin/tree/twisty-open.png"); 
+  list-style-image: url("chrome://global/skin/tree/twisty-open.png");
 }
-
-
--- a/toolkit/themes/winstripe/global/global.css
+++ b/toolkit/themes/winstripe/global/global.css
@@ -216,34 +216,34 @@ sidebarheader:-moz-lwtheme {
 }
 
 .inset {
   border: 1px solid ThreeDShadow;
   border-right-color: ThreeDHighlight;
   border-bottom-color: ThreeDHighlight;
   margin: 0 5px 5px;
 }
-  
+
 .outset {
   border: 1px solid ThreeDShadow;
   border-left-color: ThreeDHighlight;
   border-top-color: ThreeDHighlight;
 }
 
 /* separators */
 separator:not([orient="vertical"]) {
   height: 1.5em;
 }
 separator[orient="vertical"] {
   width: 1.5em;
 }
 
 separator.thin:not([orient="vertical"]) {
   height: 0.5em;
-}  
+}
 separator.thin[orient="vertical"] {
   width: 0.5em;
 }
 
 separator.groove:not([orient="vertical"]) {
   border-top: 1px solid ThreeDShadow;
   border-bottom: 1px solid ThreeDHighlight;
   height: 0;
@@ -256,17 +256,17 @@ separator.groove[orient="vertical"] {
   width: 0;
   margin-left: 0.4em;
   margin-right: 0.4em;
 }
 
 .small-margin {
   margin: 1px 2px;
 }
-    
+
 .plain {
   -moz-appearance: none;
   margin: 0 !important;
   border: none;
   padding: 0;
 }
 
 description,
@@ -320,17 +320,17 @@ label[disabled="true"]:-moz-system-metri
 }
 
 .text-link {
   color: -moz-nativehyperlinktext;
   text-decoration: underline;
   border: 1px solid transparent;
   cursor: pointer;
 }
-  
+
 .text-link:focus {
   border: 1px dotted -moz-DialogText;
 }
 
 /* :::::: autoscroll popup ::::: */
 
 .autoscroller {
   height: 28px;
--- a/toolkit/themes/winstripe/global/toolbarbutton.css
+++ b/toolkit/themes/winstripe/global/toolbarbutton.css
@@ -64,27 +64,25 @@ toolbarbutton {
   margin: 0 !important;
   text-align: center;
 }
 
 toolbarbutton.tabbable {
   -moz-user-focus: normal !important;
 }
 
-toolbarbutton:focus 
-{
+toolbarbutton:focus {
   /* -moz-appearance looks redundant here but is necessary.
       Without it, the outline won't appear. */
   -moz-appearance: toolbarbutton;
   outline: 1px dotted -moz-DialogText;
   outline-offset: -2px;
 }
 
-toolbarbutton:hover:not([disabled="true"]),
-toolbarbutton[buttonover="true"] {
+toolbarbutton:hover:not([disabled="true"]) {
   border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;
 }
 
 toolbarbutton:hover:active:not([disabled="true"]),
 toolbarbutton[open="true"]:hover,
 toolbarbutton[open="true"] {
   border-color: ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow;
   padding-top: 4px;
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -51,16 +51,17 @@
 #include "nsIAtom.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMDataTransfer.h"
 #include "nsWeakPtr.h"
 #include "nsIWidget.h"
 #include "nsTArray.h"
 #include "nsTraceRefcnt.h"
 #include "nsITransferable.h"
+#include "nsIVariant.h"
 
 class nsIRenderingContext;
 class nsIRegion;
 class nsIMenuItem;
 class nsIAccessible;
 class nsIContent;
 class nsIURI;
 class nsHashKey;
@@ -241,16 +242,17 @@ class nsHashKey;
 #define NS_SCROLLBAR_LINE_PREV          (NS_SCROLLBAR_MESSAGE_START + 4)
 
 #define NS_STREAM_EVENT_START           1100
 #define NS_LOAD                         (NS_STREAM_EVENT_START)
 #define NS_PAGE_UNLOAD                  (NS_STREAM_EVENT_START + 1)
 #define NS_HASHCHANGE                   (NS_STREAM_EVENT_START + 2)
 #define NS_IMAGE_ABORT                  (NS_STREAM_EVENT_START + 3)
 #define NS_LOAD_ERROR                   (NS_STREAM_EVENT_START + 4)
+#define NS_POPSTATE                     (NS_STREAM_EVENT_START + 5)
 #define NS_BEFORE_PAGE_UNLOAD           (NS_STREAM_EVENT_START + 6)
 #define NS_PAGE_RESTORE                 (NS_STREAM_EVENT_START + 7)
  
 #define NS_FORM_EVENT_START             1200
 #define NS_FORM_SUBMIT                  (NS_FORM_EVENT_START)
 #define NS_FORM_RESET                   (NS_FORM_EVENT_START + 1)
 #define NS_FORM_CHANGE                  (NS_FORM_EVENT_START + 2)
 #define NS_FORM_SELECTED                (NS_FORM_EVENT_START + 3)
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -1755,16 +1755,32 @@ void nsChildView::Scroll(const nsIntPoin
       for (nsIntRegionRectIterator iter(needsInvalidation);
            (invalidate = iter.Next()) != nsnull;) {
         NSRect rect;
         GeckoRectToNSRect(*invalidate, rect);
         [mView setNeedsDisplayInRect:rect];
       }
     }
 #endif // NS_LEOPARD_AND_LATER
+    // Invalidate the area that was scrolled into view from outside the window
+    // First, compute the destination region whose source was outside the
+    // window. We do this by subtracting from destRegion the window bounds,
+    // translated by the scroll amount.
+    NSView* rootView = [[mView window] contentView];
+    NSRect rootViewRect = [mView convertRect:[rootView bounds] fromView: rootView];
+    nsIntRect windowBounds;
+    NSRectToGeckoRect(rootViewRect, windowBounds);
+    destRegion.Sub(destRegion, windowBounds + aDelta);
+    nsIntRegionRectIterator iter(destRegion);
+    const nsIntRect* invalidate;
+    while ((invalidate = iter.Next()) != nsnull) {
+      NSRect rect;
+      GeckoRectToNSRect(*invalidate, rect);
+      [mView setNeedsDisplayInRect:rect];
+    }
 
     // Leopard, at least, has a nasty bug where calling scrollRect:by: doesn't
     // actually trigger a window update. A window update is only triggered
     // if you actually paint something. In some cases Gecko might optimize
     // scrolling in such a way that nothing actually gets repainted.
     // So let's invalidate one pixel. We'll pick a pixel on the trailing edge
     // of the last destination rectangle, since in most situations that's going
     // to be invalidated anyway.
--- a/widget/src/cocoa/nsCocoaWindow.mm
+++ b/widget/src/cocoa/nsCocoaWindow.mm
@@ -1366,18 +1366,17 @@ void nsCocoaWindow::SetMenuBar(nsMenuBar
     mMenuBar->Paint();
 }
 
 NS_IMETHODIMP nsCocoaWindow::SetFocus(PRBool aState)
 {
   if (mPopupContentView) {
     mPopupContentView->SetFocus(aState);
   }
-  else if (aState && [mWindow isVisible]) {
-    // if the window is shown, move it to the front
+  else if (aState && ([mWindow isVisible] || [mWindow isMiniaturized])) {
     [mWindow setAcceptsMouseMovedEvents:YES];
     [mWindow makeKeyAndOrderFront:nil];
     SendSetZLevelEvent();
   }
 
   return NS_OK;
 }
 
--- a/widget/src/xpwidgets/nsBaseWidget.cpp
+++ b/widget/src/xpwidgets/nsBaseWidget.cpp
@@ -997,18 +997,18 @@ void ScrollRectIterBase::Move(ScrollRect
   // Check subsequent rectangles that overlap vertically to see whether they
   // might need to be moved first.
   //
   // The overlapping subsequent rectangles that are not moved this time get
   // checked for each of their preceding unmoved overlapping rectangles,
   // which adds an O(n^2) cost to this algorithm (where n is the number of
   // rectangles across x).  The reverse-x ordering from InitialSortComparator
   // avoids this for the case when rectangles are aligned in y.
-  for (ScrollRect** nextLink = aUnmovedLink;
-       ScrollRect* otherRect = *nextLink; ) {
+  for (ScrollRect** nextLink = aUnmovedLink; *nextLink; ) {
+    ScrollRect* otherRect = *nextLink;
     NS_ASSERTION(otherRect->y >= rect->y, "Scroll rectangles out of order");
     if (otherRect->y >= rect->YMost()) // doesn't overlap vertically
       break;
 
     // This only moves the other rectangle first if it is entirely to the
     // left.  No promises are made regarding intersecting rectangles.  Moving
     // another intersecting rectangle with merely x < rect->x (but XMost() >
     // rect->x) can cause more conflicts between rectangles that do not
@@ -1093,16 +1093,17 @@ case _value: eventName.AssignWithConvers
     _ASSIGN_eventName(NS_MOUSE_EXIT,"NS_MOUSE_EXIT");
     _ASSIGN_eventName(NS_MOUSE_BUTTON_DOWN,"NS_MOUSE_BUTTON_DOWN");
     _ASSIGN_eventName(NS_MOUSE_BUTTON_UP,"NS_MOUSE_BUTTON_UP");
     _ASSIGN_eventName(NS_MOUSE_CLICK,"NS_MOUSE_CLICK");
     _ASSIGN_eventName(NS_MOUSE_DOUBLECLICK,"NS_MOUSE_DBLCLICK");
     _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE");
     _ASSIGN_eventName(NS_MOVE,"NS_MOVE");
     _ASSIGN_eventName(NS_LOAD,"NS_LOAD");
+    _ASSIGN_eventName(NS_POPSTATE,"NS_POPSTATE");
     _ASSIGN_eventName(NS_PAGE_UNLOAD,"NS_PAGE_UNLOAD");
     _ASSIGN_eventName(NS_HASHCHANGE,"NS_HASHCHANGE");
     _ASSIGN_eventName(NS_PAINT,"NS_PAINT");
     _ASSIGN_eventName(NS_XUL_BROADCAST, "NS_XUL_BROADCAST");
     _ASSIGN_eventName(NS_XUL_COMMAND_UPDATE, "NS_XUL_COMMAND_UPDATE");
     _ASSIGN_eventName(NS_SCROLLBAR_LINE_NEXT,"NS_SB_LINE_NEXT");
     _ASSIGN_eventName(NS_SCROLLBAR_LINE_PREV,"NS_SB_LINE_PREV");
     _ASSIGN_eventName(NS_SCROLLBAR_PAGE_NEXT,"NS_SB_PAGE_NEXT");
--- a/xpcom/ds/nsIVariant.idl
+++ b/xpcom/ds/nsIVariant.idl
@@ -72,26 +72,31 @@ interface nsIDataType : nsISupports
     const PRUint16 VTYPE_WSTRING_SIZE_IS     = 22; // TD_PWSTRING_SIZE_IS  = 22,
     const PRUint16 VTYPE_UTF8STRING          = 23; // TD_UTF8STRING        = 23,
     const PRUint16 VTYPE_CSTRING             = 24; // TD_CSTRING           = 24,
     const PRUint16 VTYPE_ASTRING             = 25; // TD_ASTRING           = 25,
     const PRUint16 VTYPE_EMPTY_ARRAY         = 254;
     const PRUint16 VTYPE_EMPTY               = 255;
 };
 
+%{ C++
+#include "jspubtd.h"
+%}
+
+native JSVal(jsval);
 
 /**
  * XPConnect has magic to transparently convert between nsIVariant and JS types.
  * We mark the interface [scriptable] so that JS can use methods
  * that refer to this interface. But we mark all the methods and attributes
  * [noscript] since any nsIVariant object will be automatically converted to a
  * JS type anyway.
  */
 
-[scriptable, uuid(6c9eb060-8c6a-11d5-90f3-0010a4e73d9a)]
+[scriptable, uuid(81e4c2de-acac-4ad6-901a-b5fb1b851a0d)]
 interface nsIVariant : nsISupports
 {
     [noscript] readonly attribute PRUint16     dataType;
 
     [noscript] PRUint8      getAsInt8();
     [noscript] PRInt16      getAsInt16();
     [noscript] PRInt32      getAsInt32();
     [noscript] PRInt64      getAsInt64();
@@ -107,16 +112,17 @@ interface nsIVariant : nsISupports
     [notxpcom] nsresult     getAsID(out nsID retval);
     [noscript] AString      getAsAString();
     [noscript] DOMString    getAsDOMString();
     [noscript] ACString     getAsACString();
     [noscript] AUTF8String  getAsAUTF8String();
     [noscript] string       getAsString();
     [noscript] wstring      getAsWString();
     [noscript] nsISupports  getAsISupports();
+    [noscript] JSVal        getAsJSVal();
 
     [noscript] void getAsInterface(out nsIIDPtr iid, 
                                    [iid_is(iid), retval] out nsQIResult iface);
 
     [notxpcom] nsresult getAsArray(out PRUint16 type, out nsIID iid,
                                    out PRUint32 count, out voidPtr ptr);
 
     [noscript] void getAsStringWithSize(out PRUint32 size, 
--- a/xpcom/ds/nsVariant.cpp
+++ b/xpcom/ds/nsVariant.cpp
@@ -1881,16 +1881,23 @@ NS_IMETHODIMP nsVariant::GetAsWString(PR
 }
 
 /* nsISupports getAsISupports (); */
 NS_IMETHODIMP nsVariant::GetAsISupports(nsISupports **_retval)
 {
     return nsVariant::ConvertToISupports(mData, _retval);
 }
 
+/* jsval getAsJSVal() */
+NS_IMETHODIMP nsVariant::GetAsJSVal(jsval *_retval)
+{
+    // Can only get the JSVal from an XPCVariant.
+    return NS_ERROR_CANNOT_CONVERT_DATA;
+}
+
 /* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */
 NS_IMETHODIMP nsVariant::GetAsInterface(nsIID * *iid, void * *iface)
 {
     return nsVariant::ConvertToInterface(mData, iid, iface);
 }
 
 /* [notxpcom] nsresult getAsArray (out PRUint16 type, out nsIID iid, out PRUint32 count, out voidPtr ptr); */
 NS_IMETHODIMP_(nsresult) nsVariant::GetAsArray(PRUint16 *type, nsIID *iid, PRUint32 *count, void * *ptr)
deleted file mode 100644
deleted file mode 100644
deleted file mode 100644
deleted file mode 100644