Merge m-c to devtools.
authorDave Camp <dcamp@mozilla.com>
Fri, 10 Jun 2011 15:35:17 -0700
changeset 70892 6da2c7c5c170
parent 70891 588eea08e466 (current diff)
parent 70884 fbeb460473f5 (diff)
child 70893 dc8d154f3710
child 71667 6f5e8757e0cd
push id20437
push userdcamp@campd.org
push dateFri, 10 Jun 2011 22:40:45 +0000
treeherdermozilla-central@6da2c7c5c170 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to devtools.
content/base/test/test_bug339494.xul
content/base/test/test_bug357450.xul
content/base/test/test_bug571390.xul
content/html/content/public/nsIFrameSetElement.h
content/xul/templates/tests/bug441785-1.rdf
content/xul/templates/tests/bug441785-2.rdf
content/xul/templates/tests/test_bug441785.xul
content/xul/templates/tests/test_sortservice.xul
extensions/spellcheck/osxspell/Makefile.in
extensions/spellcheck/osxspell/src/Makefile.in
extensions/spellcheck/osxspell/src/mozOSXSpell.h
extensions/spellcheck/osxspell/src/mozOSXSpell.mm
gfx/angle/angle-makefiles.patch
js/src/jit-test/tests/basic/testStackQuotaExhausted.js
js/src/yarr/Makefile
js/src/yarr/jswtfbridge.h
js/src/yarr/pcre/AUTHORS
js/src/yarr/pcre/COPYING
js/src/yarr/pcre/chartables.c
js/src/yarr/pcre/dftables
js/src/yarr/pcre/pcre.h
js/src/yarr/pcre/pcre.pri
js/src/yarr/pcre/pcre_compile.cpp
js/src/yarr/pcre/pcre_exec.cpp
js/src/yarr/pcre/pcre_internal.h
js/src/yarr/pcre/pcre_tables.cpp
js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp
js/src/yarr/pcre/pcre_xclass.cpp
js/src/yarr/pcre/ucpinternal.h
js/src/yarr/pcre/ucptable.cpp
js/src/yarr/wtf/ASCIICType.h
js/src/yarr/yarr/RegExpJitTables.h
js/src/yarr/yarr/RegexCommon.h
js/src/yarr/yarr/RegexCompiler.cpp
js/src/yarr/yarr/RegexCompiler.h
js/src/yarr/yarr/RegexJIT.cpp
js/src/yarr/yarr/RegexJIT.h
js/src/yarr/yarr/RegexParser.h
js/src/yarr/yarr/RegexPattern.h
layout/base/crashtests/331883-2-inner.html
layout/base/crashtests/331883-2.html
layout/generic/nsBidiFrames.cpp
layout/generic/nsBidiFrames.h
mobile/chrome/content/firstrun/facebook.png
mobile/chrome/content/firstrun/features.png
mobile/chrome/content/firstrun/firstrun.xhtml
mobile/chrome/content/firstrun/mozilla.png
mobile/chrome/content/firstrun/nav-arrow.png
mobile/chrome/content/firstrun/twitter.png
mobile/locales/en-US/chrome/firstrun.dtd
mobile/themes/core/firstRun.css
modules/staticmod/Makefile.in
modules/staticmod/nsMetaModule.cpp
--- a/accessible/src/base/AccEvent.cpp
+++ b/accessible/src/base/AccEvent.cpp
@@ -308,18 +308,18 @@ AccMutationEvent::
 // AccHideEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccHideEvent::
   AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode) :
   AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode)
 {
   mParent = mAccessible->GetParent();
-  mNextSibling = mAccessible->GetCachedNextSibling();
-  mPrevSibling = mAccessible->GetCachedPrevSibling();
+  mNextSibling = mAccessible->NextSibling();
+  mPrevSibling = mAccessible->PrevSibling();
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccShowEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccShowEvent::
--- a/accessible/src/base/AccGroupInfo.cpp
+++ b/accessible/src/base/AccGroupInfo.cpp
@@ -147,27 +147,27 @@ AccGroupInfo::AccGroupInfo(nsAccessible*
   // parent. Or, if the parent is something other than a tree we will
   // return that.
 
   if (parentRole != nsIAccessibleRole::ROLE_GROUPING) {
     mParent = parent;
     return;
   }
 
-  nsAccessible* parentPrevSibling = parent->GetSiblingAtOffset(-1);
+  nsAccessible* parentPrevSibling = parent->PrevSibling();
   if (!parentPrevSibling)
     return;
 
   PRUint32 parentPrevSiblingRole = parentPrevSibling->Role();
   if (parentPrevSiblingRole == nsIAccessibleRole::ROLE_TEXT_LEAF) {
     // XXX Sometimes an empty text accessible is in the hierarchy here,
     // although the text does not appear to be rendered, GetRenderedText()
     // says that it is so we need to skip past it to find the true
     // previous sibling.
-    parentPrevSibling = parentPrevSibling->GetSiblingAtOffset(-1);
+    parentPrevSibling = parentPrevSibling->PrevSibling();
     if (parentPrevSibling)
       parentPrevSiblingRole = parentPrevSibling->Role();
   }
 
   // Previous sibling of parent group is a tree item, this is the
   // conceptual tree item parent.
   if (parentPrevSiblingRole == nsIAccessibleRole::ROLE_OUTLINEITEM)
     mParent = parentPrevSibling;
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -85,17 +85,17 @@ nsApplicationAccessible *nsAccessNode::g
 
 /*
  * Class nsAccessNode
  */
  
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible. nsISupports
 
-NS_IMPL_CYCLE_COLLECTION_0(nsAccessNode)
+NS_IMPL_CYCLE_COLLECTION_1(nsAccessNode, mContent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccessNode)
   NS_INTERFACE_MAP_ENTRY(nsIAccessNode)
   NS_INTERFACE_MAP_ENTRY(nsAccessNode)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessNode)
 NS_INTERFACE_MAP_END
  
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAccessNode)
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -445,27 +445,35 @@ nsAccessible::GetParent(nsIAccessible **
   return *aParent ? NS_OK : NS_ERROR_FAILURE;
 }
 
   /* readonly attribute nsIAccessible nextSibling; */
 NS_IMETHODIMP
 nsAccessible::GetNextSibling(nsIAccessible **aNextSibling) 
 {
   NS_ENSURE_ARG_POINTER(aNextSibling);
+  *aNextSibling = nsnull;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   NS_IF_ADDREF(*aNextSibling = GetSiblingAtOffset(1, &rv));
   return rv;
 }
 
   /* readonly attribute nsIAccessible previousSibling; */
 NS_IMETHODIMP
 nsAccessible::GetPreviousSibling(nsIAccessible * *aPreviousSibling) 
 {
   NS_ENSURE_ARG_POINTER(aPreviousSibling);
+  *aPreviousSibling = nsnull;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   NS_IF_ADDREF(*aPreviousSibling = GetSiblingAtOffset(-1, &rv));
   return rv;
 }
 
   /* readonly attribute nsIAccessible firstChild; */
 NS_IMETHODIMP
@@ -598,17 +606,17 @@ nsresult nsAccessible::GetTranslatedStri
 
 nsresult nsAccessible::GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut)
 {
   nsXPIDLString modifierName, separator;
 
   if (!gKeyStringBundle ||
       NS_FAILED(gKeyStringBundle->GetStringFromName(PromiseFlatString(aModifierName).get(), 
                                                     getter_Copies(modifierName))) ||
-      NS_FAILED(gKeyStringBundle->GetStringFromName(PromiseFlatString(NS_LITERAL_STRING("MODIFIER_SEPARATOR")).get(), 
+      NS_FAILED(gKeyStringBundle->GetStringFromName(NS_LITERAL_STRING("MODIFIER_SEPARATOR").get(), 
                                                     getter_Copies(separator)))) {
     return NS_ERROR_FAILURE;
   }
 
   aStringOut = modifierName + separator + aKeyName; 
   return NS_OK;
 }
 
@@ -3161,49 +3169,31 @@ nsAccessible::EnsureChildren()
 
   if (document)
     document->NotifyOfCachingEnd(this);
 
   return false;
 }
 
 nsAccessible*
-nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError)
+nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError) const
 {
-  if (IsDefunct()) {
-    if (aError)
-      *aError = NS_ERROR_FAILURE;
-
-    return nsnull;
-  }
-
-  nsAccessible *parent = GetParent();
-  if (!parent) {
+  if (!mParent || mIndexInParent == -1) {
     if (aError)
       *aError = NS_ERROR_UNEXPECTED;
 
     return nsnull;
   }
 
-  if (mIndexInParent == -1) {
-    if (aError)
-      *aError = NS_ERROR_UNEXPECTED;
-
+  if (aError && mIndexInParent + aOffset >= mParent->GetChildCount()) {
+    *aError = NS_OK; // fail peacefully
     return nsnull;
   }
 
-  if (aError) {
-    PRInt32 childCount = parent->GetChildCount();
-    if (mIndexInParent + aOffset >= childCount) {
-      *aError = NS_OK; // fail peacefully
-      return nsnull;
-    }
-  }
-
-  nsAccessible* child = parent->GetChildAt(mIndexInParent + aOffset);
+  nsAccessible* child = mParent->GetChildAt(mIndexInParent + aOffset);
   if (aError && !child)
     *aError = NS_ERROR_UNEXPECTED;
 
   return child;
 }
 
 nsAccessible *
 nsAccessible::GetFirstAvailableAccessible(nsINode *aStartNode) const
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -300,47 +300,56 @@ public:
   virtual PRInt32 GetIndexInParent() const;
 
   /**
    * Return true if accessible has children;
    */
   PRBool HasChildren() { return !!GetChildAt(0); }
 
   /**
+   * Return next/previous sibling of the accessible.
+   */
+  inline nsAccessible* NextSibling() const
+    {  return GetSiblingAtOffset(1); }
+  inline nsAccessible* PrevSibling() const
+    { return GetSiblingAtOffset(-1); }
+
+  /**
    * Return embedded accessible children count.
    */
   PRInt32 GetEmbeddedChildCount();
 
   /**
    * Return embedded accessible child at the given index.
    */
   nsAccessible* GetEmbeddedChildAt(PRUint32 aIndex);
 
   /**
    * Return index of the given embedded accessible child.
    */
   PRInt32 GetIndexOfEmbeddedChild(nsAccessible* aChild);
 
   /**
-   * Return cached accessible of parent-child relatives.
+   * Return number of content children/content child at index. The content
+   * child is created from markup in contrast to it's never constructed by its
+   * parent accessible (like treeitem accessibles for XUL trees).
    */
-  nsAccessible* GetCachedNextSibling() const
-  {
-    return mParent ?
-      mParent->mChildren.SafeElementAt(mIndexInParent + 1, nsnull).get() : nsnull;
-  }
-  nsAccessible* GetCachedPrevSibling() const
-  {
-    return mParent ?
-      mParent->mChildren.SafeElementAt(mIndexInParent - 1, nsnull).get() : nsnull;
-  }
-  PRUint32 GetCachedChildCount() const { return mChildren.Length(); }
-  nsAccessible* GetCachedChildAt(PRUint32 aIndex) const { return mChildren.ElementAt(aIndex); }
+  PRUint32 ContentChildCount() const { return mChildren.Length(); }
+  nsAccessible* ContentChildAt(PRUint32 aIndex) const
+    { return mChildren.ElementAt(aIndex); }
+
+  /**
+   * Return true if children were initialized.
+   */
   inline bool AreChildrenCached() const
     { return !IsChildrenFlag(eChildrenUninitialized); }
+
+  /**
+   * Return true if the accessible is attached to tree.
+   */
   bool IsBoundToParent() const { return !!mParent; }
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous methods
 
   /**
    * Handle accessible event, i.e. process it, notifies observers and fires
    * platform specific event.
@@ -498,17 +507,17 @@ protected:
    */
   virtual void BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent);
   void UnbindFromParent();
 
   /**
    * Return sibling accessible at the given offset.
    */
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
-                                           nsresult *aError = nsnull);
+                                           nsresult *aError = nsnull) const;
 
   /**
    * Flags used to describe the state and type of children.
    */
   enum ChildrenFlags {
     eChildrenUninitialized = 0, // children aren't initialized
     eMixedChildren = 1 << 0, // text leaf children are presented
     eEmbeddedChildren = 1 << 1 // all children are embedded objects
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -423,25 +423,19 @@ nsApplicationAccessible::CacheChildren()
         GetAccService()->GetDocAccessible(docNode); // ensure creation
       }
     }
     windowEnumerator->HasMoreElements(&hasMore);
   }
 }
 
 nsAccessible*
-nsApplicationAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError)
+nsApplicationAccessible::GetSiblingAtOffset(PRInt32 aOffset,
+                                            nsresult* aError) const
 {
-  if (IsDefunct()) {
-    if (aError)
-      *aError = NS_ERROR_FAILURE;
-
-    return nsnull;
-  }
-
   if (aError)
     *aError = NS_OK; // fail peacefully
 
   return nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessNode and nsAccessNode
--- a/accessible/src/base/nsApplicationAccessible.h
+++ b/accessible/src/base/nsApplicationAccessible.h
@@ -131,16 +131,16 @@ public:
 
   virtual void InvalidateChildren();
 
 protected:
 
   // nsAccessible
   virtual void CacheChildren();
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
-                                           nsresult *aError = nsnull);
+                                           nsresult *aError = nsnull) const;
 
 private:
   nsCOMPtr<nsIXULAppInfo> mAppInfo;
 };
 
 #endif
 
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -133,29 +133,31 @@ nsDocAccessible::~nsDocAccessible()
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNotificationController,
                                                   NotificationController)
 
   PRUint32 i, length = tmp->mChildDocuments.Length();
   for (i = 0; i < length; ++i) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildDocuments[i]");
-    cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mChildDocuments[i].get()));
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mChildDocuments[i],
+                                                         nsIAccessible)
   }
 
   CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNotificationController)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mChildDocuments)
   tmp->mDependentIDsHash.Clear();
   tmp->mNodeToAccessibleMap.Clear();
   ClearCache(tmp->mAccessibleCache);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDocAccessible)
@@ -1914,51 +1916,54 @@ nsDocAccessible::UpdateTreeInternal(nsAc
   return updateFlags;
 }
 
 void
 nsDocAccessible::CacheChildrenInSubtree(nsAccessible* aRoot)
 {
   aRoot->EnsureChildren();
 
-  PRUint32 count = aRoot->GetChildCount();
-  for (PRUint32 idx = 0; idx < count; idx++)  {
-    nsAccessible* child = aRoot->GetChildAt(idx);
+  // Make sure we create accessible tree defined in DOM only, i.e. if accessible
+  // provides specific tree (like XUL trees) then tree creation is handled by
+  // this accessible.
+  PRUint32 count = aRoot->ContentChildCount();
+  for (PRUint32 idx = 0; idx < count; idx++) {
+    nsAccessible* child = aRoot->ContentChildAt(idx);
     NS_ASSERTION(child, "Illicit tree change while tree is created!");
     // Don't cross document boundaries.
     if (child && child->IsContent())
       CacheChildrenInSubtree(child);
   }
 }
 
 void
 nsDocAccessible::UncacheChildrenInSubtree(nsAccessible* aRoot)
 {
   if (aRoot->IsElement())
     RemoveDependentIDsFor(aRoot);
 
-  PRUint32 count = aRoot->GetCachedChildCount();
+  PRUint32 count = aRoot->ContentChildCount();
   for (PRUint32 idx = 0; idx < count; idx++)
-    UncacheChildrenInSubtree(aRoot->GetCachedChildAt(idx));
+    UncacheChildrenInSubtree(aRoot->ContentChildAt(idx));
 
   if (aRoot->IsPrimaryForNode() &&
       mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
     mNodeToAccessibleMap.Remove(aRoot->GetNode());
 }
 
 void
 nsDocAccessible::ShutdownChildrenInSubtree(nsAccessible* aAccessible)
 {
   // Traverse through children and shutdown them before this accessible. When
   // child gets shutdown then it removes itself from children array of its
   //parent. Use jdx index to process the cases if child is not attached to the
   // parent and as result doesn't remove itself from its children.
-  PRUint32 count = aAccessible->GetCachedChildCount();
+  PRUint32 count = aAccessible->ContentChildCount();
   for (PRUint32 idx = 0, jdx = 0; idx < count; idx++) {
-    nsAccessible* child = aAccessible->GetCachedChildAt(jdx);
+    nsAccessible* child = aAccessible->ContentChildAt(jdx);
     if (!child->IsBoundToParent()) {
       NS_ERROR("Parent refers to a child, child doesn't refer to parent!");
       jdx++;
     }
 
     ShutdownChildrenInSubtree(child);
   }
 
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -632,19 +632,36 @@ nsXULTreeItemAccessibleBase::
   mTree(aTree), mTreeView(aTreeView), mRow(aRow)
 {
   mParent = aParent;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: nsISupports implementation
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsXULTreeItemAccessibleBase,
-                             nsAccessible,
-                             nsXULTreeItemAccessibleBase)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeItemAccessibleBase)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeItemAccessibleBase,
+                                                  nsAccessible)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTree)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTreeView)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeItemAccessibleBase,
+                                                nsAccessible)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTree)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTreeView)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULTreeItemAccessibleBase)
+  NS_INTERFACE_TABLE_INHERITED1(nsXULTreeItemAccessibleBase,
+                                nsXULTreeItemAccessibleBase)
+NS_INTERFACE_TABLE_TAIL_INHERITING(nsAccessible)
+NS_IMPL_ADDREF_INHERITED(nsXULTreeItemAccessibleBase, nsAccessible)
+NS_IMPL_RELEASE_INHERITED(nsXULTreeItemAccessibleBase, nsAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: nsIAccessible implementation
 
 NS_IMETHODIMP
 nsXULTreeItemAccessibleBase::GetFocusedChild(nsIAccessible **aFocusedChild) 
 {
   NS_ENSURE_ARG_POINTER(aFocusedChild);
@@ -966,17 +983,17 @@ nsXULTreeItemAccessibleBase::NativeState
     state |= states::INVISIBLE;
 
   return state;
 }
 
 PRInt32
 nsXULTreeItemAccessibleBase::GetIndexInParent() const
 {
-  return mParent ? mParent->GetCachedChildCount() + mRow : -1;
+  return mParent ? mParent->ContentChildCount() + mRow : -1;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: nsAccessible protected methods
 
 void
 nsXULTreeItemAccessibleBase::DispatchClickEvent(nsIContent *aContent,
                                                 PRUint32 aActionIndex)
@@ -1003,25 +1020,18 @@ nsXULTreeItemAccessibleBase::DispatchCli
   }
 
   if (column)
     nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm);
 }
 
 nsAccessible*
 nsXULTreeItemAccessibleBase::GetSiblingAtOffset(PRInt32 aOffset,
-                                                nsresult* aError)
+                                                nsresult* aError) const
 {
-  if (IsDefunct()) {
-    if (aError)
-      *aError = NS_ERROR_FAILURE;
-
-    return nsnull;
-  }
-
   if (aError)
     *aError = NS_OK; // fail peacefully
 
   return mParent->GetChildAt(GetIndexInParent() + aOffset);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: protected implementation
@@ -1045,51 +1055,78 @@ nsXULTreeItemAccessibleBase::IsExpandabl
           return PR_TRUE;
       }
     }
   }
 
   return PR_FALSE;
 }
 
+void
+nsXULTreeItemAccessibleBase::GetCellName(nsITreeColumn* aColumn,
+                                         nsAString& aName)
+{
+  mTreeView->GetCellText(mRow, aColumn, aName);
+
+  // If there is still no name try the cell value:
+  // This is for graphical cells. We need tree/table view implementors to
+  // implement FooView::GetCellValue to return a meaningful string for cases
+  // where there is something shown in the cell (non-text) such as a star icon;
+  // in which case GetCellValue for that cell would return "starred" or
+  // "flagged" for example.
+  if (aName.IsEmpty())
+    mTreeView->GetCellValue(mRow, aColumn, aName);
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULTreeItemAccessible::
   nsXULTreeItemAccessible(nsIContent *aContent, nsIWeakReference *aShell,
                           nsAccessible *aParent, nsITreeBoxObject *aTree,
                           nsITreeView *aTreeView, PRInt32 aRow) :
   nsXULTreeItemAccessibleBase(aContent, aShell, aParent, aTree, aTreeView, aRow)
 {
   mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// nsXULTreeItemAccessible: nsISupports implementation
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeItemAccessible)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeItemAccessible,
+                                                  nsXULTreeItemAccessibleBase)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mColumn)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeItemAccessible,
+                                                nsXULTreeItemAccessibleBase)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mColumn)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeItemAccessible)
+NS_INTERFACE_MAP_END_INHERITING(nsXULTreeItemAccessibleBase)
+NS_IMPL_ADDREF_INHERITED(nsXULTreeItemAccessible, nsXULTreeItemAccessibleBase)
+NS_IMPL_RELEASE_INHERITED(nsXULTreeItemAccessible, nsXULTreeItemAccessibleBase)
+
+////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessible: nsIAccessible implementation
 
 NS_IMETHODIMP
 nsXULTreeItemAccessible::GetName(nsAString& aName)
 {
   aName.Truncate();
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  mTreeView->GetCellText(mRow, mColumn, aName);
-
-  // If there is still no name try the cell value:
-  // This is for graphical cells. We need tree/table view implementors to implement
-  // FooView::GetCellValue to return a meaningful string for cases where there is
-  // something shown in the cell (non-text) such as a star icon; in which case
-  // GetCellValue for that cell would return "starred" or "flagged" for example.
-  if (aName.IsEmpty())
-    mTreeView->GetCellValue(mRow, mColumn, aName);
-
+  GetCellName(mColumn, aName);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessible: nsAccessNode implementation
 
 bool
 nsXULTreeItemAccessible::IsDefunct() const
@@ -1167,40 +1204,33 @@ nsXULTreeItemAccessible::CacheChildren()
 nsXULTreeColumnsAccessible::
   nsXULTreeColumnsAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsXULColumnsAccessible(aContent, aShell)
 {
 }
 
 nsAccessible*
 nsXULTreeColumnsAccessible::GetSiblingAtOffset(PRInt32 aOffset,
-                                               nsresult* aError)
+                                               nsresult* aError) const
 {
   if (aOffset < 0)
     return nsXULColumnsAccessible::GetSiblingAtOffset(aOffset, aError);
 
-  if (IsDefunct()) {
-    if (aError)
-      *aError = NS_ERROR_FAILURE;
-
-    return nsnull;
-  }
-
   if (aError)
-    *aError = NS_OK; // fail peacefully
+    *aError =  NS_OK; // fail peacefully
 
   nsCOMPtr<nsITreeBoxObject> tree = nsCoreUtils::GetTreeBoxObject(mContent);
   if (tree) {
     nsCOMPtr<nsITreeView> treeView;
     tree->GetView(getter_AddRefs(treeView));
     if (treeView) {
       PRInt32 rowCount = 0;
       treeView->GetRowCount(&rowCount);
       if (rowCount > 0 && aOffset <= rowCount) {
-        nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
+        nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(GetParent());
 
         if (treeAcc)
           return treeAcc->GetTreeItemAccessible(aOffset - 1);
       }
     }
   }
 
   return nsnull;
--- a/accessible/src/xul/nsXULTreeAccessible.h
+++ b/accessible/src/xul/nsXULTreeAccessible.h
@@ -172,18 +172,20 @@ class nsXULTreeItemAccessibleBase : publ
 {
 public:
   using nsAccessible::GetParent;
 
   nsXULTreeItemAccessibleBase(nsIContent *aContent, nsIWeakReference *aShell,
                               nsAccessible *aParent, nsITreeBoxObject *aTree,
                               nsITreeView *aTreeView, PRInt32 aRow);
 
-  // nsISupports
+  // nsISupports and cycle collection
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeItemAccessibleBase,
+                                           nsAccessibleWrap)
 
   // nsIAccessible
   NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
 
   NS_IMETHOD GetBounds(PRInt32 *aX, PRInt32 *aY,
                        PRInt32 *aWidth, PRInt32 *aHeight);
 
   NS_IMETHOD SetSelected(PRBool aSelect); 
@@ -230,25 +232,30 @@ public:
   virtual void RowInvalidated(PRInt32 aStartColIdx, PRInt32 aEndColIdx) = 0;
 
 protected:
   enum { eAction_Click = 0, eAction_Expand = 1 };
 
   // nsAccessible
   virtual void DispatchClickEvent(nsIContent *aContent, PRUint32 aActionIndex);
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
-                                           nsresult *aError = nsnull);
+                                           nsresult *aError = nsnull) const;
 
   // nsXULTreeItemAccessibleBase
 
   /**
    * Return true if the tree item accessible is expandable (contains subrows).
    */
   PRBool IsExpandable();
 
+  /**
+   * Return name for cell at the given column.
+   */
+  void GetCellName(nsITreeColumn* aColumn, nsAString& aName);
+
   nsCOMPtr<nsITreeBoxObject> mTree;
   nsCOMPtr<nsITreeView> mTreeView;
   PRInt32 mRow;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsXULTreeItemAccessibleBase,
                               NS_XULTREEITEMBASEACCESSIBLE_IMPL_CID)
 
@@ -258,16 +265,21 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsXULTreeI
  */
 class nsXULTreeItemAccessible : public nsXULTreeItemAccessibleBase
 {
 public:
   nsXULTreeItemAccessible(nsIContent *aContent, nsIWeakReference *aShell,
                           nsAccessible *aParent, nsITreeBoxObject *aTree,
                           nsITreeView *aTreeView, PRInt32 aRow);
 
+  // nsISupports and cycle collection
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeItemAccessible,
+                                           nsXULTreeItemAccessibleBase)
+
   NS_IMETHOD GetName(nsAString& aName);
 
   // nsAccessNode
   virtual bool IsDefunct() const;
   virtual PRBool Init();
   virtual void Shutdown();
 
   // nsAccessible
@@ -294,12 +306,12 @@ class nsXULTreeColumnsAccessible : publi
 {
 public:
   nsXULTreeColumnsAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
 protected:
 
   // nsAccessible
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
-                                           nsresult *aError = nsnull);
+                                           nsresult *aError = nsnull) const;
 };
 
 #endif
--- a/accessible/src/xul/nsXULTreeGridAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeGridAccessible.cpp
@@ -623,22 +623,22 @@ nsXULTreeGridRowAccessible::
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridRowAccessible: nsISupports and cycle collection implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeGridRowAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeGridRowAccessible,
-                                                  nsAccessible)
+                                                  nsXULTreeItemAccessibleBase)
 CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeGridRowAccessible,
-                                                nsAccessible)
+                                                nsXULTreeItemAccessibleBase)
 ClearCache(tmp->mAccessibleCache);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeGridRowAccessible)
 NS_INTERFACE_MAP_STATIC_AMBIGUOUS(nsXULTreeGridRowAccessible)
 NS_INTERFACE_MAP_END_INHERITING(nsXULTreeItemAccessibleBase)
 
 NS_IMPL_ADDREF_INHERITED(nsXULTreeGridRowAccessible,
@@ -660,16 +660,35 @@ nsXULTreeGridRowAccessible::Shutdown()
 // nsXULTreeGridRowAccessible: nsAccessible implementation
 
 PRUint32
 nsXULTreeGridRowAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_ROW;
 }
 
+NS_IMETHODIMP
+nsXULTreeGridRowAccessible::GetName(nsAString& aName)
+{
+  aName.Truncate();
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsITreeColumns> columns;
+  mTree->GetColumns(getter_AddRefs(columns));
+  if (columns) {
+    nsCOMPtr<nsITreeColumn> primaryColumn;
+    columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
+    if (primaryColumn)
+      GetCellName(primaryColumn, aName);
+  }
+  return NS_OK;
+}
+
 nsAccessible*
 nsXULTreeGridRowAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                             EWhichChildAtPoint aWhichChild)
 {
   nsIFrame *frame = GetFrame();
   if (!frame)
     return nsnull;
 
@@ -792,20 +811,39 @@ nsXULTreeGridCellAccessible(nsIContent *
   mTreeView(aTreeView), mRow(aRow), mColumn(aColumn)
 {
   mParent = aRowAcc;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridCellAccessible: nsISupports implementation
 
-NS_IMPL_ISUPPORTS_INHERITED2(nsXULTreeGridCellAccessible,
-                             nsLeafAccessible,
-                             nsIAccessibleTableCell,
-                             nsXULTreeGridCellAccessible)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeGridCellAccessible)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeGridCellAccessible,
+                                                  nsLeafAccessible)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTree)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTreeView)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mColumn)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeGridCellAccessible,
+                                                nsLeafAccessible)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTree)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTreeView)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mColumn)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULTreeGridCellAccessible)
+  NS_INTERFACE_TABLE_INHERITED2(nsXULTreeGridCellAccessible,
+                                nsIAccessibleTableCell,
+                                nsXULTreeGridCellAccessible)
+NS_INTERFACE_TABLE_TAIL_INHERITING(nsLeafAccessible)
+NS_IMPL_ADDREF_INHERITED(nsXULTreeGridCellAccessible, nsLeafAccessible)
+NS_IMPL_RELEASE_INHERITED(nsXULTreeGridCellAccessible, nsLeafAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridCellAccessible: nsIAccessible implementation
 
 NS_IMETHODIMP
 nsXULTreeGridCellAccessible::GetFocusedChild(nsIAccessible **aFocusedChild) 
 {
   NS_ENSURE_ARG_POINTER(aFocusedChild);
@@ -1239,27 +1277,20 @@ nsXULTreeGridCellAccessible::CellInvalid
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridCellAccessible: nsAccessible protected implementation
 
 nsAccessible*
 nsXULTreeGridCellAccessible::GetSiblingAtOffset(PRInt32 aOffset,
-                                                nsresult* aError)
+                                                nsresult* aError) const
 {
-  if (IsDefunct()) {
-    if (aError)
-      *aError = NS_ERROR_FAILURE;
-
-    return nsnull;
-  }
-
   if (aError)
-    *aError = NS_OK; // fail peacefully
+    *aError =  NS_OK; // fail peacefully
 
   nsCOMPtr<nsITreeColumn> columnAtOffset(mColumn), column;
   if (aOffset < 0) {
     for (PRInt32 index = aOffset; index < 0 && columnAtOffset; index++) {
       column = nsCoreUtils::GetPreviousSensibleColumn(columnAtOffset);
       column.swap(columnAtOffset);
     }
   } else {
@@ -1267,18 +1298,17 @@ nsXULTreeGridCellAccessible::GetSiblingA
       column = nsCoreUtils::GetNextSensibleColumn(columnAtOffset);
       column.swap(columnAtOffset);
     }
   }
 
   if (!columnAtOffset)
     return nsnull;
 
-  nsRefPtr<nsXULTreeItemAccessibleBase> rowAcc = do_QueryObject(mParent);
-
+  nsRefPtr<nsXULTreeItemAccessibleBase> rowAcc = do_QueryObject(GetParent());
   return rowAcc->GetCellAccessible(columnAtOffset);
 }
 
 void
 nsXULTreeGridCellAccessible::DispatchClickEvent(nsIContent *aContent,
                                                 PRUint32 aActionIndex)
 {
   if (IsDefunct())
--- a/accessible/src/xul/nsXULTreeGridAccessible.h
+++ b/accessible/src/xul/nsXULTreeGridAccessible.h
@@ -81,23 +81,24 @@ public:
 
   nsXULTreeGridRowAccessible(nsIContent *aContent, nsIWeakReference *aShell,
                              nsAccessible *aParent, nsITreeBoxObject *aTree,
                              nsITreeView *aTreeView, PRInt32 aRow);
 
   // nsISupports and cycle collection
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeGridRowAccessible,
-                                           nsAccessible)
+                                           nsXULTreeItemAccessibleBase)
 
   // nsAccessNode
   virtual void Shutdown();
 
   // nsAccessible
   virtual PRUint32 NativeRole();
+  NS_IMETHOD GetName(nsAString& aName);
   virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                         EWhichChildAtPoint aWhichChild);
 
   virtual nsAccessible* GetChildAt(PRUint32 aIndex);
   virtual PRInt32 GetChildCount();
 
   // nsXULTreeItemAccessibleBase
   virtual nsAccessible* GetCellAccessible(nsITreeColumn *aColumn);
@@ -134,16 +135,18 @@ public:
 
   nsXULTreeGridCellAccessible(nsIContent *aContent, nsIWeakReference *aShell,
                               nsXULTreeGridRowAccessible *aRowAcc,
                               nsITreeBoxObject *aTree, nsITreeView *aTreeView,
                               PRInt32 aRow, nsITreeColumn* aColumn);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeGridCellAccessible,
+                                           nsLeafAccessible)
 
   // nsIAccessible
   NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
 
   NS_IMETHOD GetName(nsAString& aName);
   NS_IMETHOD GetBounds(PRInt32 *aX, PRInt32 *aY,
                        PRInt32 *aWidth, PRInt32 *aHeight);
 
@@ -177,17 +180,17 @@ public:
    * Fire name or state change event if the accessible text or value has been
    * changed.
    */
   void CellInvalidated();
 
 protected:
   // nsAccessible
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
-                                           nsresult *aError = nsnull);
+                                           nsresult *aError = nsnull) const;
   virtual void DispatchClickEvent(nsIContent *aContent, PRUint32 aActionIndex);
 
   // nsXULTreeGridCellAccessible
 
   /**
    * Return true if value of cell can be modified.
    */
   PRBool IsEditable() const;
--- a/accessible/tests/mochitest/name/Makefile.in
+++ b/accessible/tests/mochitest/name/Makefile.in
@@ -52,13 +52,14 @@ include $(topsrcdir)/config/rules.mk
 		nsRootAcc_wnd.xul \
 		test_button.html \
 		test_general.html \
 		test_general.xul \
 		test_link.html \
 		test_list.html \
 		test_markup.html \
 		test_nsRootAcc.xul \
+		test_tree.xul \
 		markuprules.xml \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/name/test_tree.xul
@@ -0,0 +1,200 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<?xml-stylesheet href="general.css"
+                 type="text/css"?>
+
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Accessibility Name Calculating Test.">
+
+  <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 type="application/javascript"
+          src="../treeview.js" />
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../name.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+  <![CDATA[
+    function treeTester(aID)
+    {
+      this.DOMNode = getNode(aID);
+
+      this.invoke = function treeTester_invoke()
+      {
+        this.DOMNode.treeBoxObject.view = new nsTreeTreeView();
+      }
+
+      this.check = function treeTester_check(aEvent)
+      {
+        var tree = {
+          role: ROLE_OUTLINE,
+          children: [
+            {
+              role: ROLE_LIST
+            },
+            {
+              role: ROLE_OUTLINEITEM,
+              children: [],
+              name: "row1col"
+            },
+            {
+              role: ROLE_OUTLINEITEM,
+              children: [],
+              name: "row2_col"
+            },
+            {
+              role: ROLE_OUTLINEITEM,
+              children: [],
+              name: "row2.1_col"
+            },
+            {
+              role: ROLE_OUTLINEITEM,
+              children: [],
+              name: "row2.2_col"
+            },
+            {
+              role: ROLE_OUTLINEITEM,
+              children: [],
+              name: "row3_col"
+            },
+            {
+              role: ROLE_OUTLINEITEM,
+              children: [],
+              name: "row4col"
+            }
+          ]
+        };
+        testAccessibleTree(this.DOMNode, tree);
+      }
+
+      this.getID = function treeTester_getID()
+      {
+        return "Tree name testing for " + aID;
+      }
+    }
+
+    function tableTester(aID)
+    {
+      this.DOMNode = getNode(aID);
+
+      this.invoke = function tableTester_invoke()
+      {
+        this.DOMNode.treeBoxObject.view = new nsTableTreeView(2);
+      }
+
+      this.check = function tableTester_check(aEvent)
+      {
+        var tree = {
+          role: ROLE_TREE_TABLE,
+          children: [
+            {
+              role: ROLE_LIST
+            },
+            {
+              role: ROLE_ROW,
+              children: [
+                {
+                  role: ROLE_GRID_CELL,
+                  children: [],
+                  name: "row0_col1"
+                },
+                {
+                  role: ROLE_GRID_CELL,
+                  children: [],
+                  name: "row0_col2"
+                }
+              ],
+              name: "row0_col1"
+            },
+            {
+              role: ROLE_ROW,
+              children: [
+                {
+                  role: ROLE_GRID_CELL,
+                  children: [],
+                  name: "row1_col1"
+                },
+                {
+                  role: ROLE_GRID_CELL,
+                  children: [],
+                  name: "row1_col2"
+                }
+              ],
+              name: "row1_col1"
+            }
+          ]
+        };
+        testAccessibleTree(this.DOMNode, tree);
+      }
+
+      this.getID = function tableTester_getID()
+      {
+        return "Tree name testing for " + aID;
+      }
+    }
+
+    var gQueue = null;
+    function doTest()
+    {
+      var gQueue = new eventQueue(EVENT_REORDER);
+
+      gQueue.push(new treeTester("tree"));
+      gQueue.push(new tableTester("table"));
+
+      gQueue.invoke(); // Will call SimpleTest.finish()
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=546812"
+       title="Treegrid row accessible shouldn't inherit name from tree accessible">
+      Mozilla Bug 546812
+    </a>
+  <p id="display"></p>
+    <div id="content" style="display: none">
+    </div>
+    <pre id="test">
+    </pre>
+  </body>
+
+  <vbox flex="1">
+
+  <tree id="tree" flex="1">
+    <treecols>
+      <treecol id="col" flex="1" primary="true" label="column"/>
+    </treecols>
+    <treechildren/>
+  </tree>
+
+  <tree id="table" flex="1">
+    <treecols>
+      <treecol id="col1" flex="1" label="column" primary="true"/>
+      <treecol id="col2" flex="1" label="column 2"/>
+    </treecols>
+    <treechildren/>
+  </tree>
+
+  </vbox> <!-- close tests area -->
+  </hbox> <!-- close main area -->
+</window>
+
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -859,16 +859,19 @@ pref("browser.zoom.siteSpecific", true);
 pref("browser.zoom.updateBackgroundTabs", true);
 
 // The breakpad report server to link to in about:crashes
 pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/");
 
 // base URL for web-based support pages
 pref("app.support.baseURL", "http://support.mozilla.com/1/firefox/%VERSION%/%OS%/%LOCALE%/");
 
+// URL for web-based support page on how to upgrade a graphics driver
+pref("app.support.updateGraphicsDriverURL", "http://support.mozilla.com/%LOCALE%/kb/how-do-i-upgrade-my-graphics-drivers");
+
 // Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror)
 pref("security.alternate_certificate_error_page", "certerror");
 
 // Whether to start the private browsing mode at application startup
 pref("browser.privatebrowsing.autostart", false);
 
 // Whether we should skip prompting before starting the private browsing mode
 pref("browser.privatebrowsing.dont_prompt_on_enter", false);
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -186,17 +186,17 @@
                  accesskey="&dontShowMessage.accesskey;"
                  type="checkbox"
                  oncommand="gPopupBlockerObserver.dontShowMessage();"/>
     <broadcaster id="blockedPopupsSeparator"/>
     <broadcaster id="isImage"/>
     <broadcaster id="isFrameImage"/>
     <broadcaster id="singleFeedMenuitemState" disabled="true"/>
     <broadcaster id="multipleFeedsMenuState" hidden="true"/>
-    <broadcaster id="tabviewGroupsNumber" groups="0"/>
+    <broadcaster id="tabviewGroupsNumber" groups="1"/>
 #ifdef MOZ_SERVICES_SYNC
     <broadcaster id="sync-setup-state"/>
     <broadcaster id="sync-syncnow-state"/>
 #endif
     <broadcaster id="workOfflineMenuitemState"/>
   </broadcasterset>
 
   <keyset id="mainKeyset">
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -35,25 +35,28 @@
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 let TabView = {
   _deck: null,
   _iframe: null,
   _window: null,
+  _initialized: false,
   _browserKeyHandlerInitialized: false,
   _isFrameLoading: false,
   _initFrameCallbacks: [],
+  _lastSessionGroupName: null,
   PREF_BRANCH: "browser.panorama.",
   PREF_FIRST_RUN: "browser.panorama.experienced_first_run",
   PREF_STARTUP_PAGE: "browser.startup.page",
   PREF_RESTORE_ENABLED_ONCE: "browser.panorama.session_restore_enabled_once",
+  GROUPS_IDENTIFIER: "tabview-groups",
   VISIBILITY_IDENTIFIER: "tabview-visibility",
-  GROUPS_IDENTIFIER: "tabview-groups",
+  LAST_SESSION_GROUP_NAME_IDENTIFIER: "tabview-last-session-group-name",
 
   // ----------
   get windowTitle() {
     delete this.windowTitle;
     let brandBundle = document.getElementById("bundle_brand");
     let brandShortName = brandBundle.getString("brandShortName");
     let title = gNavigatorBundle.getFormattedString("tabView2.title", [brandShortName]);
     return this.windowTitle = title;
@@ -84,71 +87,85 @@ let TabView = {
 
   // ----------
   set sessionRestoreEnabledOnce(val) {
     Services.prefs.setBoolPref(this.PREF_RESTORE_ENABLED_ONCE, val);
   },
 
   // ----------
   init: function TabView_init() {
+    if (this._initialized)
+      return;
+
     if (this.firstUseExperienced) {
       if ((gBrowser.tabs.length - gBrowser.visibleTabs.length) > 0)
         this._setBrowserKeyHandlers();
 
       // ___ visibility
       let sessionstore =
         Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
 
       let data = sessionstore.getWindowValue(window, this.VISIBILITY_IDENTIFIER);
       if (data && data == "true") {
         this.show();
       } else {
         try {
           data = sessionstore.getWindowValue(window, this.GROUPS_IDENTIFIER);
           if (data) {
             let parsedData = JSON.parse(data);
-            this.updateGroupNumberBroadcaster(parsedData.totalNumber || 0);
+            this.updateGroupNumberBroadcaster(parsedData.totalNumber || 1);
           }
         } catch (e) { }
 
         let self = this;
         // if a tab is changed from hidden to unhidden and the iframe is not
         // initialized, load the iframe and setup the tab.
         this._tabShowEventListener = function (event) {
           if (!self._window)
             self._initFrame(function() {
               self._window.UI.onTabSelect(gBrowser.selectedTab);
             });
         };
         gBrowser.tabContainer.addEventListener(
           "TabShow", this._tabShowEventListener, true);
+
+       // grab the last used group title
+       this._lastSessionGroupName = sessionstore.getWindowValue(window,
+         this.LAST_SESSION_GROUP_NAME_IDENTIFIER);
       }
     }
 
     Services.prefs.addObserver(this.PREF_BRANCH, this, false);
+
+    this._initialized = true;
   },
 
   // ----------
   // Observes topic changes.
   observe: function TabView_observe(subject, topic, data) {
     if (data == this.PREF_FIRST_RUN && this.firstUseExperienced) {
       this._addToolbarButton();
       this.enableSessionRestore();
     }
   },
 
   // ----------
   // Uninitializes TabView.
   uninit: function TabView_uninit() {
+    if (!this._initialized)
+      return;
+
     Services.prefs.removeObserver(this.PREF_BRANCH, this);
 
     if (this._tabShowEventListener) {
       gBrowser.tabContainer.removeEventListener(
         "TabShow", this._tabShowEventListener, true);
     }
+
+    this._initialized = false;
   },
 
   // ----------
   // Creates the frame and calls the callback once it's loaded. 
   // If the frame already exists, calls the callback immediately. 
   _initFrame: function TabView__initFrame(callback) {
     let hasCallback = typeof callback == "function";
 
@@ -231,28 +248,38 @@ let TabView = {
   toggle: function() {
     if (this.isVisible())
       this.hide();
     else 
       this.show();
   },
   
   getActiveGroupName: function TabView_getActiveGroupName() {
+    if (!this._window)
+      return this._lastSessionGroupName;
+
     // We get the active group this way, instead of querying
     // GroupItems.getActiveGroupItem() because the tabSelect event
     // will not have happened by the time the browser tries to
     // update the title.
+    let groupItem = null;
     let activeTab = window.gBrowser.selectedTab;
-    if (activeTab._tabViewTabItem && activeTab._tabViewTabItem.parent){
-      let groupName = activeTab._tabViewTabItem.parent.getTitle();
-      if (groupName)
-        return groupName;
+    let activeTabItem = activeTab._tabViewTabItem;
+
+    if (activeTab.pinned) {
+      // It's an app tab, so it won't have a .tabItem. However, its .parent
+      // will already be set as the active group. 
+      groupItem = this._window.GroupItems.getActiveGroupItem();
+    } else if (activeTabItem) {
+      groupItem = activeTabItem.parent;
     }
-    return null;
-  },  
+
+    // groupItem may still be null, if the active tab is an orphan.
+    return groupItem ? groupItem.getTitle() : "";
+  },
 
   // ----------
   updateContextMenu: function(tab, popup) {
     let separator = document.getElementById("context_tabViewNamedGroups");
     let isEmpty = true;
 
     while (popup.firstChild && popup.firstChild != separator)
       popup.removeChild(popup.firstChild);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4361,16 +4361,20 @@ var XULBrowserWindow = {
           this.throbberElement.removeAttribute("busy");
 
         this.stopCommand.setAttribute("disabled", "true");
         CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest);
       }
     }
   },
 
+  onLocationChange2: function (aWebProgress, aRequest, aLocationURI, aFlags) {
+    onLocationChange(aWebProgress, aRequest, aLocationURI);
+  },
+
   onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
     var location = aLocationURI ? aLocationURI.spec : "";
     this._hostChanged = true;
 
     // Hide the form invalid popup.
     if (gFormSubmitObserver.panelIsOpen()) {
       gFormSubmitObserver.panel.hidePopup();
     }
--- a/browser/base/content/tabview/drag.js
+++ b/browser/base/content/tabview/drag.js
@@ -80,29 +80,16 @@ function Drag(item, event, isFauxDrag) {
   this.startTime = Date.now();
 
   this.item.isDragging = true;
   this.item.setZ(999999);
 
   this.safeWindowBounds = Items.getSafeWindowBounds();
 
   Trenches.activateOthersTrenches(this.el);
-
-  if (!isFauxDrag) {
-    // When a tab drag starts, make it the focused tab.
-    if (this.item.isAGroupItem) {
-      var tab = UI.getActiveTab();
-      if (!tab || tab.parent != this.item) {
-        if (this.item._children.length)
-          UI.setActive(this.item._children[0]);
-      }
-    } else if (this.item.isATabItem) {
-      UI.setActive(this.item);
-    }
-  }
 };
 
 Drag.prototype = {
   // ----------
   // Function: toString
   // Prints [Drag (item)] for debug use
   toString: function Drag_toString() {
     return "[Drag (" + this.item + ")]";
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -1009,18 +1009,17 @@ GroupItem.prototype = Utils.extend(new I
             UI.setActive(self);
         });
 
         item.setParent(this);
 
         if (typeof item.setResizable == 'function')
           item.setResizable(false, options.immediately);
 
-        // if it is visually active, set it as the active tab.
-        if (iQ(item.container).hasClass("focus"))
+        if (item == UI.getActiveTab() || !this._activeTab)
           this.setActiveTab(item);
 
         // if it matches the selected tab or no active tab and the browser
         // tab is hidden, the active group item would be set.
         if (item.tab == gBrowser.selectedTab ||
             (!GroupItems.getActiveGroupItem() && !item.tab.hidden))
           UI.setActive(this);
       }
--- a/browser/base/content/tabview/items.js
+++ b/browser/base/content/tabview/items.js
@@ -146,20 +146,19 @@ Item.prototype = {
     this.$container = iQ(container);
 
     iQ(this.container).data('item', this);
 
     // ___ drag
     this.dragOptions = {
       cancelClass: 'close stackExpander',
       start: function(e, ui) {
-        if (this.isAGroupItem) {
-          UI.setActive(this);
+        UI.setActive(this);
+        if (this.isAGroupItem)
           this._unfreezeItemSize();
-        }
         // if we start dragging a tab within a group, start with dropSpace on.
         else if (this.parent != null)
           this.parent._dropSpaceActive = true;
         drag.info = new Drag(this, e);
       },
       drag: function(e) {
         drag.info.drag(e);
       },
@@ -196,18 +195,17 @@ Item.prototype = {
 
     // ___ resize
     var self = this;
     this.resizeOptions = {
       aspectRatio: self.keepProportional,
       minWidth: 90,
       minHeight: 90,
       start: function(e,ui) {
-        if (this.isAGroupItem)
-          UI.setActive(this);
+        UI.setActive(this);
         resize.info = new Drag(this, e);
       },
       resize: function(e,ui) {
         resize.info.snap(UI.rtl ? 'topright' : 'topleft', false, self.keepProportional);
       },
       stop: function() {
         self.setUserSize();
         self.pushAway();
--- a/browser/base/content/tabview/search.js
+++ b/browser/base/content/tabview/search.js
@@ -205,17 +205,17 @@ TabMatcher.prototype = {
   
   // ---------
   // Function: _filterForUnmatches
   // Given an array of <TabItem>s returns an unsorted array of tabs whose name
   // does not match the the search term.
   _filterForUnmatches: function TabMatcher__filterForUnmatches(tabs) {
     var self = this;
     return tabs.filter(function(tab) {
-      var name = tab.$tabTitle[0].innerHTML;
+      let name = tab.$tabTitle[0].textContent;
       let url = TabUtils.URLOf(tab);
       return !name.match(self.term, "i") && !url.match(self.term, "i");
     });
   },
   
   // ---------
   // Function: _getTabsForOtherWindows
   // Returns an array of <TabItem>s and <xul:tabs>s representing tabs
@@ -225,27 +225,18 @@ TabMatcher.prototype = {
   // been activated.
   _getTabsForOtherWindows: function TabMatcher__getTabsForOtherWindows() {
     var enumerator = Services.wm.getEnumerator("navigator:browser");
     var allTabs = [];
 
     while (enumerator.hasMoreElements()) {
       var win = enumerator.getNext();
       // This function gets tabs from other windows, not from the current window
-      if (win != gWindow) {
-        // If TabView is around iterate over all tabs, else get the currently
-        // shown tabs...
-        let tvWindow = win.TabView.getContentWindow();
-        if (tvWindow)
-          allTabs = allTabs.concat(tvWindow.TabItems.getItems());
-        else
-          // win.gBrowser.tabs isn't a proper array, so we can't use concat
-          for (let i = 0; i < win.gBrowser.tabs.length; i++)
-            allTabs.push(win.gBrowser.tabs[i]);
-      }
+      if (win != gWindow)
+        allTabs.push.apply(allTabs, win.gBrowser.tabs);
     }
     return allTabs;
   },
   
   // ----------
   // Function: matchedTabsFromOtherWindows
   // Returns an array of <TabItem>s and <xul:tab>s that match the search term
   // from all windows but the current window. <TabItem>s will be returned for
--- a/browser/base/content/tabview/storage.js
+++ b/browser/base/content/tabview/storage.js
@@ -216,16 +216,25 @@ let Storage = {
   // Function: saveVisibilityData
   // Saves visibility for the given window.
   saveVisibilityData: function Storage_saveVisibilityData(win, data) {
     this._sessionStore.setWindowValue(
       win, win.TabView.VISIBILITY_IDENTIFIER, data);
   },
 
   // ----------
+  // Function: saveActiveGroupName
+  // Saves the active group's name for the given window.
+  saveActiveGroupName: function Storage_saveActiveGroupName(win) {
+    let groupName = win.TabView.getActiveGroupName();
+    this._sessionStore.setWindowValue(
+      win, win.TabView.LAST_SESSION_GROUP_NAME_IDENTIFIER, groupName);
+  },
+
+  // ----------
   // Function: saveData
   // Generic routine for saving data to a window.
   saveData: function Storage_saveData(win, id, data) {
     try {
       this._sessionStore.setWindowValue(win, id, JSON.stringify(data));
     } catch (e) {
       Utils.log("Error in saveData: "+e);
     }
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -123,18 +123,17 @@ let UI = {
     wasInTabView: false 
   },
   
   // Variable: _storageBusyCount
   // Used to keep track of how many calls to storageBusy vs storageReady.
   _storageBusyCount: 0,
 
   // Variable: isDOMWindowClosing
-  // Tells wether we already received the "domwindowclosed" event and the parent
-  // windows is about to close.
+  // Tells wether the parent window is about to close
   isDOMWindowClosing: false,
 
   // Variable: _browserKeys
   // Used to keep track of allowed browser keys.
   _browserKeys: null,
 
   // Variable: ignoreKeypressForSearch
   // Used to prevent keypress being handled after quitting search mode.
@@ -252,31 +251,29 @@ let UI = {
         this._resize(true);
       else
         this._pageBounds = Items.getPageBounds();
 
       iQ(window).resize(function() {
         self._resize();
       });
 
-      // ___ setup observer to save canvas images
-      function domWinClosedObserver(subject, topic, data) {
-        if (topic == "domwindowclosed" && subject == gWindow) {
-          self.isDOMWindowClosing = true;
-          if (self.isTabViewVisible())
-            GroupItems.removeHiddenGroups();
-          TabItems.saveAll(true);
-          self._save();
-        }
-      }
-      Services.obs.addObserver(
-        domWinClosedObserver, "domwindowclosed", false);
-      this._cleanupFunctions.push(function() {
-        Services.obs.removeObserver(domWinClosedObserver, "domwindowclosed");
-      });
+      // ___ setup event listener to save canvas images
+      gWindow.addEventListener("SSWindowClosing", function onWindowClosing() {
+        gWindow.removeEventListener("SSWindowClosing", onWindowClosing, false);
+
+        self.isDOMWindowClosing = true;
+
+        if (self.isTabViewVisible())
+          GroupItems.removeHiddenGroups();
+
+        Storage.saveActiveGroupName(gWindow);
+        TabItems.saveAll(true);
+        self._save();
+      }, false);
 
       // ___ Done
       this._frameInitialized = true;
       this._save();
 
       // fire an iframe initialized event so everyone knows tab view is 
       // initialized.
       let event = document.createEvent("Events");
--- a/browser/base/content/test/browser_bug380960.js
+++ b/browser/base/content/test/browser_bug380960.js
@@ -56,16 +56,17 @@ function preperForNextText() {
     nextAsyncText(tab);
   });
 }
 
 function nextAsyncText(tab) {
   var gotCloseEvent = false;
 
   tab.addEventListener("TabClose", function () {
+    tab.removeEventListener("TabClose", arguments.callee, false);
     info("got TabClose event");
     gotCloseEvent = true;
 
     const DEFAULT_ANIMATION_LENGTH = 250;
     const MAX_WAIT_TIME = DEFAULT_ANIMATION_LENGTH * 7;
     var polls = Math.ceil(MAX_WAIT_TIME / DEFAULT_ANIMATION_LENGTH);
     var pollTabRemoved = setInterval(function () {
       --polls;
--- a/browser/base/content/test/browser_bug477014.js
+++ b/browser/base/content/test/browser_bug477014.js
@@ -47,35 +47,33 @@ function test() {
 
   function onPageShow(event) {
     // we get here if the test is executed before the pageshow
     // event for the window's first tab
     if (!tabToDetach ||
         tabToDetach.linkedBrowser.contentDocument != event.target)
       return;
 
+    event.currentTarget.removeEventListener("pageshow", onPageShow, false);
+
     if (!newWindow) {
-      gBrowser.removeEventListener("pageshow", onPageShow, false);
-
       // prepare the tab (set icon and busy state)
       // we have to set these only after onState* notification, otherwise
       // they're overriden
       setTimeout(function() {
         gBrowser.setIcon(tabToDetach, iconURLSpec);
         tabToDetach.setAttribute("busy", "true");
 
         // detach and set the listener on the new window
         newWindow = gBrowser.replaceTabWithWindow(tabToDetach);
         // wait for gBrowser to come along
-        function onLoad(event) {
-          newWindow.gBrowser
-                   .addEventListener("pageshow", onPageShow, false);
+        newWindow.addEventListener("load", function () {
           newWindow.removeEventListener("load", arguments.callee, false);
-        }
-        newWindow.addEventListener("load", onLoad, false);
+          newWindow.gBrowser.addEventListener("pageshow", onPageShow, false);
+        }, false);
       }, 0);
       return;
     }
 
     is(newWindow.gBrowser.selectedTab.hasAttribute("busy"), true);
     is(newWindow.gBrowser.getIcon(), iconURLSpec);
     newWindow.close();
     finish();
--- a/browser/base/content/test/browser_bug481560.js
+++ b/browser/base/content/test/browser_bug481560.js
@@ -4,20 +4,24 @@ function test() {
   var win = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
 
   win.addEventListener("load", function () {
     win.removeEventListener("load", arguments.callee, false);
 
     win.content.addEventListener("focus", function () {
       win.content.removeEventListener("focus", arguments.callee, false);
 
-      win.gBrowser.selectedTab.addEventListener("TabClose", function () {
+      function onTabClose() {
         ok(false, "shouldn't have gotten the TabClose event for the last tab");
-      }, false);
+      }
+      var tab = win.gBrowser.selectedTab;
+      tab.addEventListener("TabClose", onTabClose, false);
 
       EventUtils.synthesizeKey("w", { accelKey: true }, win);
 
       ok(win.closed, "accel+w closed the window immediately");
 
+      tab.removeEventListener("TabClose", onTabClose, false);
+
       finish();
     }, false);
   }, false);
 }
--- a/browser/base/content/test/browser_bug517902.js
+++ b/browser/base/content/test/browser_bug517902.js
@@ -8,16 +8,17 @@ function test() {
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
     var doc = gBrowser.contentDocument;
     var testImg = doc.getElementById("test-image");
     var pageInfo = BrowserPageInfo(doc, "mediaTab", testImg);
 
     pageInfo.addEventListener("load", function () {
+      pageInfo.removeEventListener("load", arguments.callee, true);
       pageInfo.onFinished.push(function () {
         executeSoon(function () {
           var pageInfoImg = pageInfo.document.getElementById("thepreviewimage");
 
           is(pageInfoImg.src, testImg.src, "selected image has the correct source");
           is(pageInfoImg.width, testImg.width, "selected image has the correct width");
           is(pageInfoImg.height, testImg.height, "selected image has the correct height");
 
--- a/browser/base/content/test/browser_bug550565.js
+++ b/browser/base/content/test/browser_bug550565.js
@@ -1,16 +1,18 @@
 function test() {
   waitForExplicitFinish();
 
   let testPath = getRootDirectory(gTestPath);
 
   let tab = gBrowser.addTab(testPath + "file_bug550565_popup.html");
 
-  tab.linkedBrowser.addEventListener('DOMContentLoaded', function() {
+  tab.linkedBrowser.addEventListener("DOMContentLoaded", function() {
+    tab.linkedBrowser.removeEventListener("DOMContentLoaded", arguments.callee, true);
+
     let expectedIcon = testPath + "file_bug550565_favicon.ico";
 
     is(gBrowser.getIcon(tab), expectedIcon, "Correct icon before pushState.");
     tab.linkedBrowser.contentWindow.history.pushState("page2", "page2", "page2");
     is(gBrowser.getIcon(tab), expectedIcon, "Correct icon after pushState.");
 
     gBrowser.removeTab(tab);
 
--- a/browser/base/content/test/browser_bug562649.js
+++ b/browser/base/content/test/browser_bug562649.js
@@ -11,14 +11,17 @@ function test() {
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.removeCurrentTab();
   is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI after switching tabs");
   is(gURLBar.value, URI, "location bar value matches test URI after switching tabs");
 
   waitForExplicitFinish();
   gBrowser.selectedBrowser.addEventListener("load", function () {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
     is(gBrowser.userTypedValue, null, "userTypedValue is null as the page has loaded");
     is(gURLBar.value, URI, "location bar value matches test URI as the page has loaded");
+
     gBrowser.removeCurrentTab();
     finish();
   }, true);
 }
--- a/browser/base/content/test/browser_bug580956.js
+++ b/browser/base/content/test/browser_bug580956.js
@@ -15,13 +15,16 @@ function test() {
   gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", 0);
   gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
   is(numClosedTabs(), 0, "There should be 0 closed tabs.");
   ok(!isUndoCloseEnabled(), "Undo Close Tab should be disabled.");
 
   var tab = gBrowser.addTab("http://mochi.test:8888/");
   var browser = gBrowser.getBrowserForTab(tab);
   browser.addEventListener("load", function() {
+    browser.removeEventListener("load", arguments.callee, true);
+
     gBrowser.removeTab(tab);
     ok(isUndoCloseEnabled(), "Undo Close Tab should be enabled.");
+
     finish();
   }, true);
 }
--- a/browser/base/content/test/browser_bug585785.js
+++ b/browser/base/content/test/browser_bug585785.js
@@ -22,15 +22,17 @@ function checkAnimationState() {
     ok(true, "tab removed synchronously since the opening animation hasn't moved yet");
     finish();
     return;
   }
 
   info("tab didn't close immediately, so the tab opening animation must have started moving");
   info("waiting for the tab to close asynchronously");
   tab.addEventListener("transitionend", function (event) {
-    if (event.propertyName == "max-width")
+    if (event.propertyName == "max-width") {
+      tab.removeEventListener("transitionend", arguments.callee, false);
       executeSoon(function () {
         ok(!tab.parentNode, "tab removed asynchronously");
         finish();
       });
+    }
   }, false);
 }
--- a/browser/base/content/test/browser_bug594131.js
+++ b/browser/base/content/test/browser_bug594131.js
@@ -38,16 +38,18 @@ function test() {
   let backgroundPref = "browser.tabs.loadBookmarksInBackground";
   let newTab = gBrowser.addTab("http://example.com");
   waitForExplicitFinish();
   newTab.linkedBrowser.addEventListener("load", mainPart, true);
   
   Services.prefs.setBoolPref(backgroundPref, true);
   
   function mainPart() {
+    newTab.linkedBrowser.removeEventListener("load", mainPart, true);
+
     gBrowser.pinTab(newTab);
     gBrowser.selectedTab = newTab;
     
     openUILinkIn("http://example.org/", "current");
     isnot(gBrowser.selectedTab, newTab, "shouldn't load in background");
     
     if (Services.prefs.prefHasUserValue(backgroundPref))
       Services.prefs.clearUserPref(backgroundPref);
--- a/browser/base/content/test/browser_bug596687.js
+++ b/browser/base/content/test/browser_bug596687.js
@@ -1,20 +1,26 @@
 function test() {
   var tab = gBrowser.addTab(null, {skipAnimation: true});
   gBrowser.selectedTab = tab;
 
   var gotTabAttrModified = false;
   var gotTabClose = false;
 
-  tab.addEventListener("TabClose", function () {
+  function onTabClose() {
     gotTabClose = true;
+    tab.addEventListener("TabAttrModified", onTabAttrModified, false);
+  }
 
-    tab.addEventListener("TabAttrModified", function () {
-      gotTabAttrModified = true;
-    }, false);
-  }, false);
+  function onTabAttrModified() {
+    gotTabAttrModified = true;
+  }
+
+  tab.addEventListener("TabClose", onTabClose, false);
 
   gBrowser.removeTab(tab);
 
   ok(gotTabClose, "should have got the TabClose event");
   ok(!gotTabAttrModified, "shouldn't have got the TabAttrModified event after TabClose");
+
+  tab.removeEventListener("TabClose", onTabClose, false);
+  tab.removeEventListener("TabAttrModified", onTabAttrModified, false);
 }
--- a/browser/base/content/test/browser_bug609700.js
+++ b/browser/base/content/test/browser_bug609700.js
@@ -3,16 +3,17 @@ function test() {
 
   Services.ww.registerNotification(function (aSubject, aTopic, aData) {
     if (aTopic == "domwindowopened") {
       Services.ww.unregisterNotification(arguments.callee);
 
       ok(true, "duplicateTabIn opened a new window");
 
       aSubject.addEventListener("load", function () {
+        aSubject.removeEventListener("load", arguments.callee, false);
         executeSoon(function () {
           aSubject.close();
           finish();
         });
       }, false);
     }
   });
 
--- a/browser/base/content/test/browser_customize_popupNotification.js
+++ b/browser/base/content/test/browser_customize_popupNotification.js
@@ -5,16 +5,18 @@ http://creativecommons.org/publicdomain/
 function test() {
   waitForExplicitFinish();
 
   var newWin = openDialog(location, "", "chrome,all,dialog=no", "about:blank");
   registerCleanupFunction(function () {
     newWin.close();
   });
   newWin.addEventListener("load", function test_win_onLoad() {
+    newWin.removeEventListener("load", test_win_onLoad, false);
+
     // Remove the URL bar
     newWin.gURLBar.parentNode.removeChild(newWin.gURLBar);
 
     waitForFocus(function () {
       let PN = newWin.PopupNotifications;
       try {
         let notification = PN.show(newWin.gBrowser.selectedBrowser, "some-notification", "Some message");
         ok(notification, "showed the notification");
--- a/browser/base/content/test/browser_page_style_menu.js
+++ b/browser/base/content/test/browser_page_style_menu.js
@@ -1,14 +1,17 @@
 function test() {
   waitForExplicitFinish();
 
   var tab = gBrowser.addTab();
   gBrowser.selectedTab = tab;
-  tab.linkedBrowser.addEventListener("load", checkPageStyleMenu, true);
+  tab.linkedBrowser.addEventListener("load", function () {
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+    checkPageStyleMenu();
+  }, true);
   let rootDir = getRootDirectory(gTestPath);
   content.location = rootDir + "page_style_sample.html";
 }
 
 function checkPageStyleMenu() {
   var menupopup = document.getElementById("pageStyleMenu")
                           .getElementsByTagName("menupopup")[0];
   stylesheetFillPopup(menupopup);
--- a/browser/base/content/test/browser_tabfocus.js
+++ b/browser/base/content/test/browser_tabfocus.js
@@ -19,16 +19,19 @@ function test() {
 
   var loadCount = 0;
   function check()
   {
     // wait for both tabs to load
     if (++loadCount != 2)
       return;
 
+    browser1.removeEventListener("load", check, true);
+    browser2.removeEventListener("load", check, true);
+
     window.focus();
 
     _browser_tabfocus_test_lastfocus = gURLBar;
     _browser_tabfocus_test_lastfocuswindow = window;
 
     window.addEventListener("focus", _browser_tabfocus_test_eventOccured, true);
     window.addEventListener("blur", _browser_tabfocus_test_eventOccured, true);
 
@@ -134,18 +137,18 @@ function test() {
     EventUtils.synthesizeKey("VK_F6", { });
     is(fm.focusedWindow, window, "switch document forward again with f6");
 
     browser1.style.MozUserFocus = "ignore";
     browser1.clientWidth;
     EventUtils.synthesizeKey("VK_F6", { });
     is(fm.focusedWindow, window, "switch document forward again with f6 when browser non-focusable");
 
-    window.addEventListener("focus", _browser_tabfocus_test_eventOccured, true);
-    window.addEventListener("blur", _browser_tabfocus_test_eventOccured, true);
+    window.removeEventListener("focus", _browser_tabfocus_test_eventOccured, true);
+    window.removeEventListener("blur", _browser_tabfocus_test_eventOccured, true);
 
     // next, check whether navigating forward, focusing the urlbar and then
     // navigating back maintains the focus in the urlbar.
     browser1.addEventListener("pageshow", _browser_tabfocus_navigation_test_eventOccured, true);
     button1.focus();
     browser1.contentWindow.location = testPage3;
   }
 
@@ -181,16 +184,17 @@ function _browser_tabfocus_navigation_te
   if (event.target instanceof Document) {
     var contentwin = event.target.defaultView;
     if (contentwin.location.toString().indexOf("3") > 0) {
       // just moved forward, so focus the urlbar and go back
       gURLBar.focus();
       setTimeout(function () contentwin.history.back(), 0);
     }
     else if (contentwin.location.toString().indexOf("2") > 0) {
+      event.currentTarget.removeEventListener("pageshow", _browser_tabfocus_navigation_test_eventOccured, true);
       is(window.document.activeElement, gURLBar.inputField, "urlbar still focused after navigating back");
       gBrowser.removeCurrentTab();
       gBrowser.removeCurrentTab();
       finish();
     }
   }
 }
 
--- a/browser/base/content/test/browser_typeAheadFind.js
+++ b/browser/base/content/test/browser_typeAheadFind.js
@@ -37,16 +37,17 @@
 
 let testWindow = null;
 
 function test() {
   waitForExplicitFinish();
 
   testWindow = OpenBrowserWindow();
   testWindow.addEventListener("load", function() {
+    testWindow.removeEventListener("load", arguments.callee, false);
     ok(true, "Load listener called");
 
     executeSoon(function() {
       let selectedBrowser = testWindow.gBrowser.selectedBrowser;
       selectedBrowser.addEventListener("pageshow", function() {
         selectedBrowser.removeEventListener("pageshow", arguments.callee,
                                             false);
         ok(true, "pageshow listener called");
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -54,16 +54,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug587351.js \
                  browser_tabview_bug587503.js \
                  browser_tabview_bug587990.js \
                  browser_tabview_bug588265.js \
                  browser_tabview_bug589324.js \
                  browser_tabview_bug590606.js \
                  browser_tabview_bug591706.js \
                  browser_tabview_bug594958.js \
+                 browser_tabview_bug595020.js \
                  browser_tabview_bug595191.js \
                  browser_tabview_bug595436.js \
                  browser_tabview_bug595518.js \
                  browser_tabview_bug595521.js \
                  browser_tabview_bug595560.js \
                  browser_tabview_bug595601.js \
                  browser_tabview_bug595804.js \
                  browser_tabview_bug595930.js \
@@ -135,20 +136,23 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug641802.js \
                  browser_tabview_bug642793.js \
                  browser_tabview_bug643392.js \
                  browser_tabview_bug644097.js \
                  browser_tabview_bug645653.js \
                  browser_tabview_bug648882.js \
                  browser_tabview_bug649006.js \
                  browser_tabview_bug649307.js \
+                 browser_tabview_bug649319.js \
                  browser_tabview_bug650573.js \
                  browser_tabview_bug651311.js \
                  browser_tabview_bug654941.js \
+                 browser_tabview_bug655269.js \
                  browser_tabview_bug656778.js \
+                 browser_tabview_bug656913.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_expander.js \
                  browser_tabview_firstrun_pref.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
                  browser_tabview_multiwindow_search.js \
                  browser_tabview_orphaned_tabs.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug595020.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
+let stateStartup = {windows:[
+  {tabs:[{entries:[{url:"about:home"}]}], extData:{"tabview-last-session-group-name":"title"}}
+]};
+
+function test() {
+  let assertWindowTitle = function (win, title) {
+    let browser = win.gBrowser.tabs[0].linkedBrowser;
+    let winTitle = win.gBrowser.getWindowTitleForBrowser(browser);
+    is(winTitle.indexOf(title), 0, "title starts with '" + title + "'");
+  };
+
+  let testGroupNameChange = function (win) {
+    showTabView(function () {
+      let cw = win.TabView.getContentWindow();
+      let groupItem = cw.GroupItems.groupItems[0];
+      groupItem.setTitle("new-title");
+
+      hideTabView(function () {
+        assertWindowTitle(win, "new-title");
+        waitForFocus(finish);
+      }, win);
+    }, win);
+  };
+
+  waitForExplicitFinish();
+
+  newWindowWithState(stateStartup, function (win) {
+    registerCleanupFunction(function () win.close());
+    assertWindowTitle(win, "title");
+    testGroupNameChange(win);
+  });
+}
--- a/browser/base/content/test/tabview/browser_tabview_bug595804.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug595804.js
@@ -77,16 +77,18 @@ function zoomInAndOut(transitionsExpecte
   };
   
   let onShownAgain = function() {
     contentWindow.removeEventListener("tabviewshown", onShownAgain, false);
     if (transitionsExpected)
       ok(transitioned >= 0, "There can be transitions");
     else
       ok(!transitioned, "There should have been no transitions");
+
+    contentWindow.document.removeEventListener("transitionend", onTransitionEnd, false);
     callback();
   };
   
   contentWindow.addEventListener("tabviewhidden", onHidden, false);
   contentWindow.addEventListener("tabviewshown", onShownAgain, false);
   
   // get this party started by hiding tab view
   TabView.toggle();
--- a/browser/base/content/test/tabview/browser_tabview_bug598375.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug598375.js
@@ -6,14 +6,16 @@ function test() {
 
   newWindowWithTabView(function (win) {
     registerCleanupFunction(function () win.close());
 
     let cw = win.TabView.getContentWindow();
     let groupItem = cw.GroupItems.groupItems[0];
     groupItem.setBounds(new cw.Rect(cw.innerWidth - 200, 0, 200, 200));
 
-    whenTabViewIsHidden(finish, win);
+    whenTabViewIsHidden(function () waitForFocus(finish), win);
 
-    let button = cw.document.getElementById("exit-button");
-    EventUtils.synthesizeMouseAtCenter(button, {}, cw);
+    waitForFocus(function () {
+      let button = cw.document.getElementById("exit-button");
+      EventUtils.synthesizeMouseAtCenter(button, {}, cw);
+    }, cw);
   });
 }
--- a/browser/base/content/test/tabview/browser_tabview_bug628061.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug628061.js
@@ -21,17 +21,33 @@ let state = {
         '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},"id":1},' +
         '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},"id":2}}'
     }
   }]
 };
 
 function test() {
   waitForExplicitFinish();
+  testOne();
+}
 
+function testOne() {
+  newWindowWithTabView(
+    function(win) {
+      testTwo();
+      win.close();
+    },
+    function(win) {
+      registerCleanupFunction(function() win.close());
+      is(win.document.getElementById("tabviewGroupsNumber").getAttribute("groups"),
+         "1", "There is one group");
+    });
+}
+
+function testTwo() {
   newWindowWithState(state, function(win) {
     registerCleanupFunction(function() win.close());
 
-    is(win.document.getElementById("tabviewGroupsNumber").getAttribute("groups"), 
+    is(win.document.getElementById("tabviewGroupsNumber").getAttribute("groups"),
        "2", "There are two groups");
     waitForFocus(finish);
   });
 }
--- a/browser/base/content/test/tabview/browser_tabview_bug630102.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug630102.js
@@ -1,64 +1,52 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
-  waitForExplicitFinish();
+  let win, contentWindow, originalTab, newTab1, newTab2;
 
-  let originalTab = gBrowser.visibleTabs[0];
-  let newTab1 = gBrowser.addTab("about:blank", { skipAnimation: true });
-  let newTab2 = gBrowser.addTab("about:blank", { skipAnimation: true });
-  
-  gBrowser.pinTab(newTab1);
-  
-  let contentWindow;
-
-  let partOne = function() {
-    window.removeEventListener("tabviewshown", partOne, false);
-
-    contentWindow = document.getElementById("tab-view").contentWindow;
-    is(contentWindow.GroupItems.groupItems.length, 1, "There is only one group item");
-
+  let partOne = function () {
     let groupItem = contentWindow.GroupItems.groupItems[0];
     let tabItems = groupItem.getChildren();
     is(tabItems.length, 2, "There are two tab items in that group item");
     is(tabItems[0].tab, originalTab, "The first tab item is linked to the first tab");
     is(tabItems[1].tab, newTab2, "The second tab item is linked to the second tab");
 
-    window.addEventListener("tabviewhidden", partTwo, false);
-    TabView.toggle();
-  };
-
-  let partTwo = function() {
-    window.removeEventListener("tabviewhidden", partTwo, false);
-
-    gBrowser.unpinTab(newTab1);
-
-    window.addEventListener("tabviewshown", partThree, false);
-    TabView.toggle();
+    hideTabView(partTwo, win);
   };
 
-  let partThree = function() {
-    window.removeEventListener("tabviewshown", partThree, false);
+  let partTwo = function () {
+    win.gBrowser.unpinTab(newTab1);
+    showTabView(partThree, win);
+  };
 
+  let partThree = function () {
     let tabItems = contentWindow.GroupItems.groupItems[0].getChildren();
     is(tabItems.length, 3, "There are three tab items in that group item");
-    is(tabItems[0].tab, gBrowser.visibleTabs[0], "The first tab item is linked to the first tab");
-    is(tabItems[1].tab, gBrowser.visibleTabs[1], "The second tab item is linked to the second tab");
-    is(tabItems[2].tab, gBrowser.visibleTabs[2], "The third tab item is linked to the third tab");
-
-    window.addEventListener("tabviewhidden", endGame, false);
-    TabView.toggle();
-  };
-
-  let endGame = function() {
-    window.removeEventListener("tabviewhidden", endGame, false);
-
-    gBrowser.removeTab(newTab1);
-    gBrowser.removeTab(newTab2);
+    is(tabItems[0].tab, win.gBrowser.tabs[0], "The first tab item is linked to the first tab");
+    is(tabItems[1].tab, win.gBrowser.tabs[1], "The second tab item is linked to the second tab");
+    is(tabItems[2].tab, win.gBrowser.tabs[2], "The third tab item is linked to the third tab");
 
     finish();
   };
 
-  window.addEventListener("tabviewshown", partOne, false);
-  TabView.toggle();
+  let onLoad = function (tvwin) {
+    win = tvwin;
+    registerCleanupFunction(function () win.close());
+
+    for (let i = 0; i < 2; i++)
+      win.gBrowser.loadOneTab("about:blank", {inBackground: true});
+
+    [originalTab, newTab1, newTab2] = win.gBrowser.tabs;
+    win.gBrowser.pinTab(newTab1);
+  };
+
+  let onShow = function () {
+    contentWindow = win.TabView.getContentWindow();
+    is(contentWindow.GroupItems.groupItems.length, 1, "There is only one group item");
+
+    partOne();
+  };
+
+  waitForExplicitFinish();
+  newWindowWithTabView(onShow, onLoad);
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug649319.js
@@ -0,0 +1,88 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function (win) {
+    registerCleanupFunction(function () win.close());
+    waitForFocus(function () testScenarios(win));
+  });
+}
+
+function testScenarios(win) {
+  let simulateDragDrop = function (target) {
+    EventUtils.synthesizeMouseAtCenter(target, {type: "mousedown"}, cw);
+    EventUtils.synthesizeMouse(target, 40, 20, {type: "mousemove"}, cw);
+    EventUtils.synthesizeMouse(target, 80, 20, {type: "mouseup"}, cw);
+  }
+
+  let dragOutOfGroup = function (target) {
+    EventUtils.synthesizeMouseAtCenter(target, {type: "mousedown"}, cw);
+    EventUtils.synthesizeMouse(target, 600, 5, {type: "mousemove"}, cw);
+    EventUtils.synthesizeMouse(target, 600, 5, {type: "mouseup"}, cw);
+  }
+
+  let dragIntoGroup = function (target) {
+    EventUtils.synthesizeMouseAtCenter(target, {type: "mousedown"}, cw);
+    EventUtils.synthesizeMouse(target, -200, 5, {type: "mousemove"}, cw);
+    EventUtils.synthesizeMouse(target, -200, 5, {type: "mouseup"}, cw);
+  }
+
+  let assertActiveOrphan = function (tabItem) {
+    ok(!cw.GroupItems.getActiveGroupItem(), "no groupItem is active");
+    is(cw.UI.getActiveTab(), tabItem, "orphan tab is active");
+    is(cw.UI.getActiveOrphanTab(), tabItem, "orphan tab is active");
+  }
+
+  let cw = win.TabView.getContentWindow();
+  let groupItem = cw.GroupItems.groupItems[0];
+  let groupItem2 = createGroupItemWithBlankTabs(win, 400, 300, 20, 4);
+
+  // move group
+  cw.UI.setActive(groupItem);
+  simulateDragDrop(groupItem2.container);
+  is(cw.GroupItems.getActiveGroupItem(), groupItem2, "second groupItem is active");
+  is(cw.UI.getActiveTab(), groupItem2.getChild(0), "second groupItem's first tab is active");
+
+  // resize group
+  cw.UI.setActive(groupItem);
+  let tabItem = groupItem2.getChild(2);
+  groupItem2.setActiveTab(tabItem);
+  simulateDragDrop(groupItem2.$resizer[0]);
+  is(cw.GroupItems.getActiveGroupItem(), groupItem2, "second groupItem is active");
+  is(cw.UI.getActiveTab(), tabItem, "second groupItem's third tab is active");
+
+  // create orphan
+  tabItem = groupItem2.getChild(0);
+  dragOutOfGroup(tabItem.container);
+
+  // move orphan
+  cw.UI.setActive(groupItem2);
+  simulateDragDrop(tabItem.container);
+  assertActiveOrphan(tabItem);
+
+  // resize orphan
+  cw.UI.setActive(groupItem2);
+  let $resizer = cw.iQ('.iq-resizable-handle', tabItem.container);
+  simulateDragDrop($resizer[0]);
+  assertActiveOrphan(tabItem);
+
+  // drag back into group
+  dragIntoGroup(tabItem.container);
+  cw.UI.setActive(groupItem);
+  cw.UI.setActive(groupItem2);
+  is(cw.UI.getActiveTab(), tabItem, "the dropped tab is active");
+
+  // hide + unhide groupItem
+  hideGroupItem(groupItem2, function () {
+    is(cw.GroupItems.getActiveGroupItem(), groupItem, "first groupItem is active");
+
+    unhideGroupItem(groupItem2, function () {
+      is(cw.GroupItems.getActiveGroupItem(), groupItem2, "second groupItem is active");
+      is(cw.UI.getActiveTab(), tabItem, "the dropped tab is active");
+
+      finish();
+    });
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug655269.js
@@ -0,0 +1,20 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function (win) {
+    let cw = win.TabView.getContentWindow();
+    let tabItem = win.gBrowser.tabs[0]._tabViewTabItem;
+
+    tabItem.addSubscriber(tabItem, "savedCachedImageData", function () {
+      tabItem.removeSubscriber(tabItem, "savedCachedImageData");
+
+      ok(cw.UI.isDOMWindowClosing, "dom window is closing");
+      waitForFocus(finish);
+    });
+
+    win.close();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug656913.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// ----------
+function test() {
+  waitForExplicitFinish();
+
+  let urlBase = "http://mochi.test:8888/browser/browser/base/content/test/tabview/";
+  let newTab = gBrowser.addTab(urlBase + "search1.html");
+
+  registerCleanupFunction(function() {
+    if (gBrowser.tabs[1])
+      gBrowser.removeTab(gBrowser.tabs[1]);
+    TabView.hide();
+  });
+
+  afterAllTabsLoaded(function() {
+    showTabView(function() {
+      hideTabView(function() {
+        newTab.linkedBrowser.loadURI(urlBase + "dummy_page.html");
+
+        newWindowWithTabView(function(win) {
+          registerCleanupFunction(function() win.close());
+
+          let contentWindow = win.TabView.getContentWindow();
+
+          EventUtils.synthesizeKey("d", { }, contentWindow);
+          EventUtils.synthesizeKey("u", { }, contentWindow);
+          EventUtils.synthesizeKey("m", { }, contentWindow);
+
+          let resultsElement = contentWindow.document.getElementById("results");
+          let childElements = resultsElement.childNodes;
+
+          is(childElements.length, 1, "There is one result element");
+          is(childElements[0].childNodes[1].textContent, 
+             "This is a dummy test page", 
+             "The label matches the title of dummy page");
+
+          finish();
+        });
+      });
+    });
+  });
+}
+
--- a/browser/base/content/test/tabview/browser_tabview_multiwindow_search.js
+++ b/browser/base/content/test/tabview/browser_tabview_multiwindow_search.js
@@ -4,21 +4,23 @@
 let newWindows = [];
 
 function test() {
   waitForExplicitFinish();
   let windowOne = openDialog(location, "", "chrome,all,dialog=no", "data:text/html,");
   let windowTwo;
 
   windowOne.addEventListener("load", function() {
+    windowOne.removeEventListener("load", arguments.callee, false);
     windowOne.gBrowser.selectedBrowser.addEventListener("load", function() {
       windowOne.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
       windowTwo = openDialog(location, "", "chrome,all,dialog=no", "http://mochi.test:8888/");
       windowTwo.addEventListener("load", function() {
+        windowTwo.removeEventListener("load", arguments.callee, false);
         windowTwo.gBrowser.selectedBrowser.addEventListener("load", function() {
           windowTwo.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
           newWindows = [ windowOne, windowTwo ];
 
           // show the tab view
           window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
           ok(!TabView.isVisible(), "Tab View is hidden");
@@ -140,9 +142,9 @@ function whenWindowObservesOnce(win, top
       if (origWin && theWin != origWin)
         return;
       if(aTopic == origTopic) {
           windowWatcher.unregisterNotification(windowObserver);
           origFunc.apply(this, []);
       }
     }
     windowWatcher.registerNotification(windowObserver);
-}
\ No newline at end of file
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1283,17 +1283,19 @@
   </binding>
 
  <binding id="promobox">
     <content>
       <xul:hbox class="panel-promo-box" align="start" flex="1">
         <xul:hbox align="center" flex="1">
           <xul:image class="panel-promo-icon"/>
           <xul:description anonid="promo-message" class="panel-promo-message" flex="1">
-            placeholder <xul:description anonid="promo-link" class="plain text-link inline-link"/>
+            placeholder <xul:description anonid="promo-link"
+                                         class="plain text-link inline-link"
+                                         onclick="document.getBindingParent(this).onLinkClick();"/>
           </xul:description>
         </xul:hbox>
         <xul:toolbarbutton class="panel-promo-closebutton"
                            oncommand="document.getBindingParent(this).onCloseButtonCommand();"
                            tooltiptext="&closeNotification.tooltip;"/>
       </xul:hbox>
     </content>
 
@@ -1356,16 +1358,24 @@
         ]]></getter>
       </property>
       <method name="onCloseButtonCommand">
         <body><![CDATA[
           this._viewsLeft = 0;
           this.hidden = true;
         ]]></body>
       </method>
+      <method name="onLinkClick">
+        <body><![CDATA[
+          // Open a new selected tab and close the current panel.
+          gBrowser.loadOneTab(this._promolink.getAttribute("href"),
+                              { inBackground: false });
+          this._panel.hidePopup();
+        ]]></body>
+      </method>
       <method name="handleEvent">
         <parameter name="event"/>
         <body><![CDATA[
           if (event.type != "popupshowing" || event.target != this._panel)
             return;
 
           // A previous notification may have unhidden this.
           this.hidden = true;
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -42,16 +42,19 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}");
+const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1";
+
 function LOG(str) {
   var prefB = Cc["@mozilla.org/preferences-service;1"].
               getService(Ci.nsIPrefBranch);
 
   var shouldLog = false;
   try {
     shouldLog = prefB.getBoolPref("feeds.log");
   } 
@@ -1372,24 +1375,19 @@ FeedWriter.prototype = {
           var codeStr = "menuItem.setAttribute('image', dataURL);";
           Cu.evalInSandbox(codeStr, self._contentSandbox);
           self._contentSandbox.menuItem = null;
           self._contentSandbox.dataURL = null;
         }
       });
   },
 
-  // nsIClassInfo
-  getInterfaces: function FW_getInterfaces(countRef) {
-    var interfaces = [Ci.nsIFeedWriter, Ci.nsIClassInfo, Ci.nsISupports];
-    countRef.value = interfaces.length;
-    return interfaces;
-  },
-  getHelperForLanguage: function FW_getHelperForLanguage(language) null,
-  classID: Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"),
-  implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
-  flags: Ci.nsIClassInfo.DOM_OBJECT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFeedWriter, Ci.nsIClassInfo,
+  classID: FEEDWRITER_CID,
+  classInfo: XPCOMUtils.generateCI({classID: FEEDWRITER_CID,
+                                    contractID: FEEDWRITER_CONTRACTID,
+                                    interfaces: [Ci.nsIFeedWriter],
+                                    flags: Ci.nsIClassInfo.DOM_OBJECT}),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFeedWriter,
                                          Ci.nsIDOMEventListener, Ci.nsIObserver,
                                          Ci.nsINavHistoryObserver])
 };
 
 var NSGetFactory = XPCOMUtils.generateNSGetFactory([FeedWriter]);
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -906,43 +906,32 @@ WebContentConverterRegistrar.prototype =
    * See nsIFactory
    */
   createInstance: function WCCR_createInstance(outer, iid) {
     if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return this.QueryInterface(iid);
   },
 
-  /**
-   * See nsIClassInfo
-   */
-  getInterfaces: function WCCR_getInterfaces(countRef) {
-    var interfaces = 
-        [Ci.nsIWebContentConverterService, Ci.nsIWebContentHandlerRegistrar,
-         Ci.nsIObserver, Ci.nsIClassInfo, Ci.nsIFactory, Ci.nsISupports];
-    countRef.value = interfaces.length;
-    return interfaces;
-  },
-  getHelperForLanguage: function WCCR_getHelperForLanguage(language) {
-    return null;
-  },
   classID: WCCR_CLASSID,
-  implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
-  flags: Ci.nsIClassInfo.DOM_OBJECT,
-  
+  classInfo: XPCOMUtils.generateCI({classID: WCCR_CLASSID,
+                                    contractID: WCCR_CONTRACTID,
+                                    interfaces: [Ci.nsIWebContentConverterService,
+                                                 Ci.nsIWebContentHandlerRegistrar,
+                                                 Ci.nsIObserver, Ci.nsIFactory],
+                                    flags: Ci.nsIClassInfo.DOM_OBJECT}),
+
   /**
    * See nsISupports
    */
   QueryInterface: XPCOMUtils.generateQI(
      [Ci.nsIWebContentConverterService, 
       Ci.nsIWebContentHandlerRegistrar,
       Ci.nsIObserver,
-      Ci.nsIClassInfo,
-      Ci.nsIFactory,
-      Ci.nsISupports]),
+      Ci.nsIFactory]),
 
   _xpcom_categories: [{
     category: "app-startup",
     service: true
   }]
 };
 
 var NSGetFactory = XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]);
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -648,16 +648,21 @@ PlacesViewBase.prototype = {
   uninit: function PVB_uninit() {
     if (this._result) {
       this._result.removeObserver(this);
       this._resultNode.containerOpen = false;
       this._resultNode = null;
       this._result = null;
     }
 
+    if (this._controller) {
+      this._viewElt.controllers.removeController(this._controller);
+      this._controller = null;
+    }
+
     delete this._viewElt._placesView;
   },
 
   get isRTL() {
     if ("_isRTL" in this)
       return this._isRTL;
 
     return this._isRTL = document.defaultView
--- a/browser/components/places/tests/browser/browser_library_panel_leak.js
+++ b/browser/components/places/tests/browser/browser_library_panel_leak.js
@@ -53,46 +53,38 @@ const TEST_URI = "http://www.mozilla.org
 let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
          getService(Ci.nsIWindowWatcher);
 
 function windowObserver(aSubject, aTopic, aData) {
   if (aTopic != "domwindowopened")
     return;
   ww.unregisterNotification(windowObserver);
   let organizer = aSubject.QueryInterface(Ci.nsIDOMWindow);
-  organizer.addEventListener("load", function onLoad(event) {
-    organizer.removeEventListener("load", onLoad, false);
-    executeSoon(function () {
-      let contentTree = organizer.document.getElementById("placeContent");
-      isnot(contentTree, null, "Sanity check: placeContent tree should exist");
-      isnot(organizer.PlacesOrganizer, null, "Sanity check: PlacesOrganizer should exist");
-      isnot(organizer.gEditItemOverlay, null, "Sanity check: gEditItemOverlay should exist");
+  waitForFocus(function () {
+    let contentTree = organizer.document.getElementById("placeContent");
+    isnot(contentTree, null, "Sanity check: placeContent tree should exist");
+    isnot(organizer.PlacesOrganizer, null, "Sanity check: PlacesOrganizer should exist");
+    isnot(organizer.gEditItemOverlay, null, "Sanity check: gEditItemOverlay should exist");
 
-      if (!organizer.gEditItemOverlay._initialized){
-        // The overlay is initialized on focus, we wait for it to be fully operational.
-        setTimeout(arguments.callee, 10);
-        return;
-      }
+    ok(organizer.gEditItemOverlay._initialized, "gEditItemOverlay is initialized");
+    isnot(organizer.gEditItemOverlay.itemId, -1, "Editing a bookmark");
 
-      isnot(organizer.gEditItemOverlay.itemId, -1, "Editing a bookmark");
-      // Select History in the left pane.
-      organizer.PlacesOrganizer.selectLeftPaneQuery('History');
-      // Select the first history entry.
-      let selection = contentTree.view.selection;
-      selection.clearSelection();
-      selection.rangedSelect(0, 0, true);
-      // Check the panel is editing the history entry.
-      is(organizer.gEditItemOverlay.itemId, -1, "Editing an history entry");
-      // Close Library window.
-      organizer.close();
-      // Clean up history.
-      PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
-      finish();
-    });
-  }, false);
+    // Select History in the left pane.
+    organizer.PlacesOrganizer.selectLeftPaneQuery('History');
+    // Select the first history entry.
+    let selection = contentTree.view.selection;
+    selection.clearSelection();
+    selection.rangedSelect(0, 0, true);
+    // Check the panel is editing the history entry.
+    is(organizer.gEditItemOverlay.itemId, -1, "Editing an history entry");
+    // Close Library window.
+    organizer.close();
+    // Clean up history.
+    waitForClearHistory(finish);
+  }, organizer);
 }
 
 function test() {
   waitForExplicitFinish();
   // Add an history entry.
   ok(PlacesUtils, "checking PlacesUtils, running in chrome context?");
   PlacesUtils.history.addVisit(PlacesUtils._uri(TEST_URI), Date.now() * 1000,
                                null, PlacesUtils.history.TRANSITION_TYPED,
@@ -100,8 +92,19 @@ function test() {
 
   ww.registerNotification(windowObserver);
   ww.openWindow(null,
                 "chrome://browser/content/places/places.xul",
                 "",
                 "chrome,toolbar=yes,dialog=no,resizable",
                 null);
 }
+
+function waitForClearHistory(aCallback) {
+  let observer = {
+    observe: function(aSubject, aTopic, aData) {
+      Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
+      aCallback(aSubject, aTopic, aData);
+    }
+  };
+  Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
+  PlacesUtils.bhistory.removeAllPages();
+}
--- a/browser/components/places/tests/browser/browser_library_search.js
+++ b/browser/components/places/tests/browser/browser_library_search.js
@@ -109,19 +109,19 @@ var testCases = [
     resetSearch("scopeBarFolder");
     search(folderId, "dummy", "scopeBarFolder");
     bmsvc.removeItem(folderId);
   },
 ];
 
 ///////////////////////////////////////////////////////////////////////////////
 
-const bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
+var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
               getService(Ci.nsINavBookmarksService);
-const histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
+var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
                 getService(Ci.nsINavHistoryService);
 var libraryWin;
 
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
  * Returns the default search scope for a given folder.
  *
--- a/browser/components/places/tests/unit/test_bookmarks_html.js
+++ b/browser/components/places/tests/unit/test_bookmarks_html.js
@@ -16,285 +16,386 @@
  * The Original Code is mozilla.com code.
  *
  * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dietrich Ayala <dietrich@mozilla.com>
+ *  Marco Bonardo <mak77@bonardo.net>
  *
  * 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 ***** */
 
-// get history service
-try {
-  var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService);
-} catch(ex) {
-  do_throw("Could not get nav-history-service\n");
-}
-
-// Get bookmark service
-try {
-  var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].getService(Ci.nsINavBookmarksService);
-} catch(ex) {
-  do_throw("Could not get nav-bookmarks-service\n");
-}
-
-// Get annotation service
-try {
-  var annosvc = Cc["@mozilla.org/browser/annotation-service;1"].getService(Ci.nsIAnnotationService);
-} catch(ex) {
-  do_throw("Could not get annotation service\n");
-} 
-
-// Get livemark service
-try {
-  var livemarksvc = Cc["@mozilla.org/browser/livemark-service;2"].getService(Ci.nsILivemarkService);
-} catch(ex) {
-  do_throw("Could not get livemark service\n");
-} 
-
-// Get favicon service
-try {
-  var iconsvc = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService);
-} catch(ex) {
-  do_throw("Could not get favicon service\n");
-} 
+// An object representing the contents of bookmarks.preplaces.html.
+let test_bookmarks = {
+  menu: [
+    { title: "Mozilla Firefox",
+      children: [
+        { title: "Help and Tutorials", 
+          url: "http://en-us.www.mozilla.com/en-US/firefox/help/",
+          icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
+        },
+        { title: "Customize Firefox",
+          url: "http://en-us.www.mozilla.com/en-US/firefox/customize/",
+          icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
+        },
+        { title: "Get Involved",
+          url: "http://en-us.www.mozilla.com/en-US/firefox/community/",
+          icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
+        },
+        { title: "About Us",
+          url: "http://en-us.www.mozilla.com/en-US/about/",
+          icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
+        },
+      ],
+    },
+    { title: "test",
+      description: "folder test comment",
+      dateAdded: 1177541020000000,
+      lastModified: 1177541050000000,
+      children: [
+        { title: "test post keyword",
+          description: "item description",
+          dateAdded: 1177375336000000,
+          lastModified: 1177375423000000,
+          keyword: "test",
+          sidebar: true,
+          postData: "hidden1%3Dbar&text1%3D%25s",
+          charset: "ISO-8859-1",
+        },
+      ]
+    },
+  ],
+  toolbar: [
+    { title: "Getting Started",
+      url: "http://en-us.www.mozilla.com/en-US/firefox/central/",
+      icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
+    },
+    { title: "Latest Headlines",
+      description: "Livemark test comment",
+      url: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
+      feedUrl: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
+    }
+  ],
+  unfiled: [
+    { title: "Example.tld",
+      url: "http://example.tld/",
+    },
+  ],
+};
 
-// Get io service
-try {
-  var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-} catch (ex) {
-  do_throw("Could not get io service\n");
-}
+// Pre-Places bookmarks.html file pointer.
+let gBookmarksFileOld;
+// Places bookmarks.html file pointer.
+let gBookmarksFileNew;
 
-const DESCRIPTION_ANNO = "bookmarkProperties/description";
-const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
-const POST_DATA_ANNO = "bookmarkProperties/POSTData";
+let importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
+               getService(Ci.nsIPlacesImportExportService);
 
-const TEST_FAVICON_PAGE_URL = "http://en-US.www.mozilla.com/en-US/firefox/central/";
-const TEST_FAVICON_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
+function run_test()
+{
+  // Avoid creating smart bookmarks during the test.
+  Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1);
 
-// main
-function run_test() {
-  // get places import/export service
-  var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].getService(Ci.nsIPlacesImportExportService);
-
-  // avoid creating the places smart folder during tests
-  Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch).
-  setIntPref("browser.places.smartBookmarksVersion", -1);
+  // File pointer to legacy bookmarks file.
+  gBookmarksFileOld = do_get_file("bookmarks.preplaces.html");
 
-  // file pointer to legacy bookmarks file
-  var bookmarksFileOld = do_get_file("bookmarks.preplaces.html");
-  // file pointer to a new places-exported bookmarks file
-  var bookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
-  bookmarksFileNew.append("bookmarks.exported.html");
+  // File pointer to a new Places-exported bookmarks file.
+  gBookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
+  gBookmarksFileNew.append("bookmarks.exported.html");
+  if (gBookmarksFileNew.exists()) {
+    gBookmarksFileNew.remove(false);
+  }
+  gBookmarksFileNew.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
+  if (!gBookmarksFileNew.exists()) {
+    do_throw("couldn't create file: bookmarks.exported.html");
+  }
 
-  // create bookmarks.exported.html
-  if (bookmarksFileNew.exists())
-    bookmarksFileNew.remove(false);
-  bookmarksFileNew.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
-  if (!bookmarksFileNew.exists())
-    do_throw("couldn't create file: bookmarks.exported.html");
-
+  // This test must be the first one, since it setups the new bookmarks.html.
   // Test importing a pre-Places canonical bookmarks file.
   // 1. import bookmarks.preplaces.html
   // 2. run the test-suite
   // Note: we do not empty the db before this import to catch bugs like 380999
   try {
-    importer.importHTMLFromFile(bookmarksFileOld, true);
+    importer.importHTMLFromFile(gBookmarksFileOld, true);
   } catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); }
-  testCanonicalBookmarks(bmsvc.bookmarksMenuFolder);
+
+  testImportedBookmarks();
+
+  // Prepare for next tests.
+  try {
+    importer.exportHTMLToFile(gBookmarksFileNew);
+  } catch(ex) { do_throw("couldn't export to file: " + ex); }
 
-  // Test exporting a Places canonical bookmarks file.
-  // 1. export to bookmarks.exported.html
-  // 2. empty bookmarks db
-  // 3. import bookmarks.exported.html
-  // 4. run the test-suite
+  remove_all_bookmarks();
+  run_next_test();
+}
+
+add_test(function test_import_new()
+{
+  // Test importing a Places bookmarks.html file.
+  // 1. import bookmarks.exported.html
+  // 2. run the test-suite
+
   try {
-    importer.exportHTMLToFile(bookmarksFileNew);
-  } catch(ex) { do_throw("couldn't export to file: " + ex); }
-  bmsvc.removeFolderChildren(bmsvc.bookmarksMenuFolder);
-  bmsvc.removeFolderChildren(bmsvc.toolbarFolder);
+    importer.importHTMLFromFile(gBookmarksFileNew, true);
+  } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
+
+  testImportedBookmarks();
+
+  remove_all_bookmarks();
+  run_next_test();
+});
+
+add_test(function test_emptytitle_export()
+{
+  // Test exporting and importing with an empty-titled bookmark.
+  // 1. import bookmarks
+  // 1. create an empty-titled bookmark.
+  // 2. export to bookmarks.exported.html
+  // 3. empty bookmarks db
+  // 4. import bookmarks.exported.html
+  // 5. run the test-suite
+
   try {
-    importer.importHTMLFromFile(bookmarksFileNew, true);
+    importer.importHTMLFromFile(gBookmarksFileNew, true);
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
-  testCanonicalBookmarks(bmsvc.bookmarksMenuFolder);
+
+  const NOTITLE_URL = "http://notitle.mozilla.org/";
+  let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
+                                                NetUtil.newURI(NOTITLE_URL),
+                                                PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                                "");
+  test_bookmarks.unfiled.push({ title: "", url: NOTITLE_URL });
+
+  try {
+    importer.exportHTMLToFile(gBookmarksFileNew);
+  } catch(ex) { do_throw("couldn't export to file: " + ex); }
+
+  remove_all_bookmarks();
 
-  /*
-  // XXX import-to-folder tests disabled due to bug 363634
+  try {
+    importer.importHTMLFromFile(gBookmarksFileNew, true);
+  } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
+
+  testImportedBookmarks();
+
+  // Cleanup.
+  test_bookmarks.unfiled.pop();
+  PlacesUtils.bookmarks.removeItem(id);
+
+  try {
+    importer.exportHTMLToFile(gBookmarksFileNew);
+  } catch(ex) { do_throw("couldn't export to file: " + ex); }
+
+  remove_all_bookmarks();
+  run_next_test();
+});
+
+add_test(function test_import_preplaces_to_folder()
+{
   // Test importing a pre-Places canonical bookmarks file to a specific folder.
   // 1. create a new folder
   // 2. import bookmarks.preplaces.html to that folder
   // 3. run the test-suite
-  var testFolder = bmsvc.createFolder(bmsvc.bookmarksMenuFolder, "test-import", bmsvc.DEFAULT_INDEX);
+
+  let testFolder = PlacesUtils.bookmarks.createFolder(
+    PlacesUtils.bookmarksMenuFolderId, "test-import",
+    PlacesUtils.bookmarks.DEFAULT_INDEX
+  );
   try {
-    importer.importHTMLFromFileToFolder(bookmarksFileOld, testFolder, false);
+    importer.importHTMLFromFileToFolder(gBookmarksFileOld, testFolder, false);
   } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
-  testCanonicalBookmarks(testFolder);
-  bmsvc.removeFolder(testFolder);
+
+  // Import-to-folder creates subfolders for toolbar and unfiled.
+  testImportedBookmarksToFolder(testFolder);
 
+  remove_all_bookmarks();
+  run_next_test();
+});
+
+add_test(function test_import_to_folder()
+{
   // Test importing a Places canonical bookmarks file to a specific folder.
   // 1. create a new folder
   // 2. import bookmarks.exported.html to that folder
   // 3. run the test-suite
-  var testFolder = bmsvc.createFolder(bmsvc.bookmarksMenuFolder, "test-import", bmsvc.DEFAULT_INDEX);
+
+  let testFolder = PlacesUtils.bookmarks.createFolder(
+    PlacesUtils.bookmarksMenuFolderId, "test-import",
+    PlacesUtils.bookmarks.DEFAULT_INDEX
+  );
   try {
-    importer.importHTMLFromFileToFolder(bookmarksFileNew, testFolder, false);
+    importer.importHTMLFromFileToFolder(gBookmarksFileNew, testFolder, false);
   } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
-  testCanonicalBookmarks(testFolder); 
-  bmsvc.removeFolder(testFolder);
+
+  // Import-to-folder creates subfolders for toolbar and unfiled.
+  testImportedBookmarksToFolder(testFolder);
 
-  // XXX Disabled due to bug 381129 - separators will be duplicated on re-import
+  remove_all_bookmarks();
+  run_next_test();
+});
+
+add_test(function test_import_ontop()
+{
   // Test importing the exported bookmarks.html file *on top of* the existing
-  // bookmarks. This tests import of IDs. If we support IDs correctly, there
-  // should be no difference after the import.
+  // bookmarks.
   // 1. empty bookmarks db
   // 2. import the exported bookmarks file
   // 3. export to file
   // 3. import the exported bookmarks file
   // 4. run the test-suite
-  bmsvc.removeFolderChildren(bmsvc.bookmarksMenuFolder);
+
   try {
-    importer.importHTMLFromFile(bookmarksFileNew, true);
+    importer.importHTMLFromFile(gBookmarksFileNew, true);
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
   try {
-    importer.exportHTMLToFile(bookmarksFileNew);
+    importer.exportHTMLToFile(gBookmarksFileNew);
   } catch(ex) { do_throw("couldn't export to file: " + ex); }
   try {
-    importer.importHTMLFromFile(bookmarksFileNew, true);
+    importer.importHTMLFromFile(gBookmarksFileNew, true);
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
-  testCanonicalBookmarks(bmsvc.bookmarksMenuFolder);
-  */
-  /*
-  XXX if there are new fields we add to the bookmarks HTML format
-  then test them here
-  Test importing a Places canonical bookmarks file
-  1. empty the bookmarks datastore
-  2. import bookmarks.places.html
-  3. run the test-suite
-  4. run the additional-test-suite
-  */
+
+  testImportedBookmarks();
+
+  remove_all_bookmarks();
+  run_next_test();
+});
+
+function testImportedBookmarks()
+{
+  for (let group in test_bookmarks) {
+    let root;
+    switch (group) {
+      case "menu":
+        root = PlacesUtils.getFolderContents(PlacesUtils.bookmarksMenuFolderId).root;
+        break;
+      case "toolbar":
+        root = PlacesUtils.getFolderContents(PlacesUtils.toolbarFolderId).root;
+        break;
+      case "unfiled":
+        root = PlacesUtils.getFolderContents(PlacesUtils.unfiledBookmarksFolderId).root;
+        break;
+    }
+
+    let items = test_bookmarks[group];
+    do_check_eq(root.childCount, items.length);
+
+    items.forEach(function (item, index) checkItem(item, root.getChild(index)));
+
+    root.containerOpen = false;
+  }
+}
+
+function testImportedBookmarksToFolder(aFolder)
+{
+  root = PlacesUtils.getFolderContents(aFolder).root;
+
+  // Menu bookmarks are put directly into the folder, while other roots are
+  // imported into subfolders.
+  let rootFolderCount = test_bookmarks.menu.length;
+
+  for (let i = 0; i < root.childCount; i++) {
+    let child = root.getChild(i);
+    if (i < rootFolderCount) {
+      checkItem(test_bookmarks.menu[i], child);
+    }
+    else {
+      let container = child.QueryInterface(Ci.nsINavHistoryContainerResultNode);
+      let group = /Toolbar/.test(container.title) ? test_bookmarks.toolbar
+                                                  : test_bookmarks.unfiled;
+      container.containerOpen = true;
+      print(container.title);
+      for (let t = 0; t < container.childCount; t++) {
+        print(group[t].title + " " + container.getChild(t).title);
+        checkItem(group[t], container.getChild(t));
+      }
+      container.containerOpen = false;
+    }
+  }
+
+  root.containerOpen = false;
 }
 
-// Tests a bookmarks datastore that has a set of bookmarks, etc
-// that flex each supported field and feature.
-function testCanonicalBookmarks(aFolder) {
-  // query to see if the deleted folder and items have been imported
-  var query = histsvc.getNewQuery();
-  query.setFolders([aFolder], 1);
-  var result = histsvc.executeQuery(query, histsvc.getNewQueryOptions());
-  var rootNode = result.root;
-  rootNode.containerOpen = true;
-
-  // 6-2: the toolbar folder and unfiled bookmarks folder imported to the
-  // corresponding places folders
-  do_check_eq(rootNode.childCount, DEFAULT_BOOKMARKS_ON_MENU + 1);
-
-  // get test folder
-  var testFolder = rootNode.getChild(DEFAULT_BOOKMARKS_ON_MENU);
-  do_check_eq(testFolder.type, testFolder.RESULT_TYPE_FOLDER);
-  do_check_eq(testFolder.title, "test");
-
-  // add date 
-  do_check_eq(bmsvc.getItemDateAdded(testFolder.itemId)/1000000, 1177541020);
-  // last modified
-  do_check_eq(bmsvc.getItemLastModified(testFolder.itemId)/1000000, 1177541050);
-
-  testFolder = testFolder.QueryInterface(Ci.nsINavHistoryQueryResultNode);
-  do_check_eq(testFolder.hasChildren, true);
-  // folder description
-  do_check_true(annosvc.itemHasAnnotation(testFolder.itemId,
-                                          DESCRIPTION_ANNO));
-  do_check_eq("folder test comment",
-              annosvc.getItemAnnotation(testFolder.itemId, DESCRIPTION_ANNO));
-  // open test folder, and test the children
-  testFolder.containerOpen = true;
-  var cc = testFolder.childCount;
-  // XXX Bug 380468
-  // do_check_eq(cc, 2);
-  do_check_eq(cc, 1);
-
-  // test bookmark 1
-  var testBookmark1 = testFolder.getChild(0);
-  // url
-  do_check_eq("http://test/post", testBookmark1.uri);
-  // title
-  do_check_eq("test post keyword", testBookmark1.title);
-  // keyword
-  do_check_eq("test", bmsvc.getKeywordForBookmark(testBookmark1.itemId));
-  // sidebar
-  do_check_true(annosvc.itemHasAnnotation(testBookmark1.itemId,
-                                          LOAD_IN_SIDEBAR_ANNO));
-  // add date 
-  do_check_eq(testBookmark1.dateAdded/1000000, 1177375336);
-
-  // last modified
-  do_check_eq(testBookmark1.lastModified/1000000, 1177375423);
+function checkItem(aExpected, aNode)
+{
+  let id = aNode.itemId;
+  for (prop in aExpected) {
+    switch (prop) {
+      case "title":
+        do_check_eq(aNode.title, aExpected.title);
+        break;
+      case "description":
+        do_check_eq(PlacesUtils.annotations
+                               .getItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO),
+                    aExpected.description);
+        break;
+      case "dateAdded":
+          do_check_eq(PlacesUtils.bookmarks.getItemDateAdded(id),
+                      aExpected.dateAdded);
+        break;
+      case "lastModified":
+          do_check_eq(PlacesUtils.bookmarks.getItemLastModified(id),
+                      aExpected.lastModified);
+        break;
+      case "url":
+        if (!PlacesUtils.livemarks.isLivemark(id))
+          do_check_eq(aNode.uri, aExpected.url);
+        break;
+      case "icon":
+        let faviconURI = PlacesUtils.favicons.getFaviconForPage(
+          NetUtil.newURI(aExpected.url)
+        );
+        let dataURL = PlacesUtils.favicons.getFaviconDataAsDataURL(faviconURI);
+        // Avoid do_check_eq for console spam.
+        do_check_true(dataURL == aExpected.icon);
+        break;
+      case "keyword":
+        break;
+      case "sidebar":
+        do_check_eq(PlacesUtils.annotations
+                               .itemHasAnnotation(id, PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO),
+                    aExpected.sidebar);
+        break;
+      case "postData":
+        do_check_eq(PlacesUtils.annotations
+                               .getItemAnnotation(id, PlacesUtils.POST_DATA_ANNO),
+                    aExpected.postData);
+        break;
+      case "charset":
+        do_check_eq(PlacesUtils.history.getCharsetForURI(NetUtil.newURI(aNode.uri)),
+                    aExpected.charset);
+        break;
+      case "feedUrl":
+        do_check_true(PlacesUtils.livemarks.isLivemark(id));
+        do_check_eq(PlacesUtils.livemarks.getSiteURI(id).spec,
+                    aExpected.url);
+        do_check_eq(PlacesUtils.livemarks.getFeedURI(id).spec,
+                    aExpected.feedUrl);
+        break;
+      case "children":
+        let folder = aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
+        do_check_eq(folder.hasChildren, aExpected.children.length > 0);
+        folder.containerOpen = true;
+        do_check_eq(folder.childCount, aExpected.children.length);
 
-  // post data
-  do_check_true(annosvc.itemHasAnnotation(testBookmark1.itemId,
-                                          POST_DATA_ANNO));
-  do_check_eq("hidden1%3Dbar&text1%3D%25s",
-              annosvc.getItemAnnotation(testBookmark1.itemId, POST_DATA_ANNO));
-
-  // last charset
-  var testURI = uri(testBookmark1.uri);
-  do_check_eq("ISO-8859-1", histsvc.getCharsetForURI(testURI));
-
-  // description
-  do_check_true(annosvc.itemHasAnnotation(testBookmark1.itemId,
-                                          DESCRIPTION_ANNO));
-  do_check_eq("item description",
-              annosvc.getItemAnnotation(testBookmark1.itemId,
-                                        DESCRIPTION_ANNO));
-
-  // clean up
-  testFolder.containerOpen = false;
-  rootNode.containerOpen = false;
+        aExpected.children.forEach(function (item, index) checkItem(item, folder.getChild(index)));
 
-  query.setFolders([bmsvc.toolbarFolder], 1);
-  result = histsvc.executeQuery(query, histsvc.getNewQueryOptions());
-  // bookmarks toolbar
-  var toolbar = result.root;
-  toolbar.containerOpen = true;
-  do_check_eq(toolbar.childCount, 2);
-  
-  // livemark
-  var livemark = toolbar.getChild(1);
-  // title
-  do_check_eq("Latest Headlines", livemark.title);
-  // livemark check
-  do_check_true(livemarksvc.isLivemark(livemark.itemId));
-  // site url
-  do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
-              livemarksvc.getSiteURI(livemark.itemId).spec);
-  // feed url
-  do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
-              livemarksvc.getFeedURI(livemark.itemId).spec);
-
-  toolbar.containerOpen = false;
-  
-  // unfiled bookmarks
-  query.setFolders([bmsvc.unfiledBookmarksFolder], 1);
-  result = histsvc.executeQuery(query, histsvc.getNewQueryOptions());
-  var unfiledBookmarks = result.root;
-  unfiledBookmarks.containerOpen = true;
-  do_check_eq(unfiledBookmarks.childCount, 1);
-  unfiledBookmarks.containerOpen = false;
-
-  // favicons
-  var faviconURI = iconsvc.getFaviconForPage(uri(TEST_FAVICON_PAGE_URL));
-  var dataURL = iconsvc.getFaviconDataAsDataURL(faviconURI);
-  do_check_eq(TEST_FAVICON_DATA_URL, dataURL);
+        folder.containerOpen = false;
+        break;
+      default:
+        throw new Error("Unknown property");
+    }
+  };
 }
--- a/browser/components/preferences/aboutPermissions.js
+++ b/browser/components/preferences/aboutPermissions.js
@@ -420,16 +420,17 @@ let AboutPermissions = {
       Services.obs.removeObserver(this, "perm-changed", false);
       Services.obs.removeObserver(this, "passwordmgr-storage-changed", false);
       Services.obs.removeObserver(this, "cookie-changed", false);
       Services.obs.removeObserver(this, "browser:purge-domain-data", false);
     }
 
     gSitesStmt.finalize();
     gVisitStmt.finalize();
+    gPlacesDatabase.asyncClose(null);
   },
 
   observe: function (aSubject, aTopic, aData) {
     switch(aTopic) {
       case "perm-changed":
         // Permissions changes only affect individual sites.
         if (!this._selectedSite) {
           break;
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_certexceptionsui.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_certexceptionsui.js
@@ -58,16 +58,17 @@ function test() {
   function step1() {
     let params = {
       exceptionAdded : false,
       location: INVALID_CERT_LOCATION,
       handlePrivateBrowsing : true,
       prefetchCert: true,
     };
     function testCheckbox() {
+      win.removeEventListener("load", testCheckbox, false);
       Services.obs.addObserver(function (aSubject, aTopic, aData) {
         Services.obs.removeObserver(arguments.callee, "cert-exception-ui-ready", false);
         ok(win.gCert, "The certificate information should be available now");
 
         let checkbox = win.document.getElementById("permanent");
         ok(checkbox.hasAttribute("disabled"),
           "the permanent checkbox should be disabled when handling the private browsing mode");
         ok(!checkbox.hasAttribute("checked"),
@@ -83,16 +84,17 @@ function test() {
   // Test the certificate excetions dialog as it is invoked from the Preferences dialog
   function step2() {
     let params = {
       exceptionAdded : false,
       location: INVALID_CERT_LOCATION,
       prefetchCert: true,
     };
     function testCheckbox() {
+      win.removeEventListener("load", testCheckbox, false);
       Services.obs.addObserver(function (aSubject, aTopic, aData) {
         Services.obs.removeObserver(arguments.callee, "cert-exception-ui-ready", false);
         ok(win.gCert, "The certificate information should be available now");
 
         let checkbox = win.document.getElementById("permanent");
         ok(!checkbox.hasAttribute("disabled"),
           "the permanent checkbox should not be disabled when not handling the private browsing mode");
         ok(checkbox.hasAttribute("checked"),
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_pageinfo.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_pageinfo.js
@@ -47,34 +47,38 @@ function test() {
     let tab1 = gBrowser.addTab();
     gBrowser.selectedTab = tab1;
     let browser1 = gBrowser.getBrowserForTab(tab1);
     browser1.addEventListener("load", function () {
       browser1.removeEventListener("load", arguments.callee, true);
 
       let pageInfo1 = BrowserPageInfo();
       pageInfo1.addEventListener("load", function () {
+        pageInfo1.removeEventListener("load", arguments.callee, false);
 
         let tab2 = gBrowser.addTab();
         gBrowser.selectedTab = tab2;
         let browser2 = gBrowser.getBrowserForTab(tab2);
         browser2.addEventListener("load", function () {
           browser2.removeEventListener("load", arguments.callee, true);
 
           let pageInfo2 = BrowserPageInfo();
           pageInfo2.addEventListener("load", function () {
+            pageInfo2.removeEventListener("load", arguments.callee, false);
 
             pageInfo1.addEventListener("unload", function () {
+              pageInfo1.removeEventListener("unload", arguments.callee, false);
               pageInfo1 = null;
               ok(true, "Page info 1 being closed as expected");
               if (!pageInfo2)
                 aCallBack();
             }, false);
 
             pageInfo2.addEventListener("unload", function () {
+              pageInfo2.removeEventListener("unload", arguments.callee, false);
               pageInfo2 = null;
               ok(true, "Page info 2 being closed as expected");
               if (!pageInfo1)
                 aCallBack();
             }, false);
 
             pb.privateBrowsingEnabled = aPBMode;
           }, false);
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_urlbarfocus.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_urlbarfocus.js
@@ -54,31 +54,37 @@ function test() {
       "URL Bar should not be focused before entering the private browsing mode");
     // ensure that the URL bar is not empty initially
     isnot(gURLBar.value, "", "URL Bar should no longer be empty after leaving the private browsing mode");
 
     // enter private browsing mode
     pb.privateBrowsingEnabled = true;
     browser = gBrowser.selectedBrowser;
     browser.addEventListener("load", function() {
+      browser.removeEventListener("load", arguments.callee, true);
+
       // setTimeout is needed here because the onload handler of about:privatebrowsing sets the focus
       setTimeout(function() {
         // ensure that the URL bar is focused inside the private browsing mode
         is(document.commandDispatcher.focusedElement, gURLBar.inputField,
           "URL Bar should be focused inside the private browsing mode");
+
         // ensure that the URL bar is emptied inside the private browsing mode
         is(gURLBar.value, "", "URL Bar should be empty inside the private browsing mode");
 
         // leave private browsing mode
         pb.privateBrowsingEnabled = false;
         browser = gBrowser.selectedBrowser;
         browser.addEventListener("load", function() {
+          browser.removeEventListener("load", arguments.callee, true);
+
           // ensure that the URL bar is no longer focused after leaving the private browsing mode
           isnot(document.commandDispatcher.focusedElement, gURLBar.inputField,
             "URL Bar should no longer be focused after leaving the private browsing mode");
+
           // ensure that the URL bar is no longer empty after leaving the private browsing mode
           isnot(gURLBar.value, "", "URL Bar should no longer be empty after leaving the private browsing mode");
 
           gBrowser.removeCurrentTab();
           finish();
         }, true);
       }, 0);
     }, true);
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -864,17 +864,24 @@ SessionStoreService.prototype = {
       delete this._statesToRestore[aWindow.__SS_restoreID];
       delete aWindow.__SS_restoreID;
     }
     
     // ignore windows not tracked by SessionStore
     if (!aWindow.__SSi || !this._windows[aWindow.__SSi]) {
       return;
     }
-    
+
+    // notify that the session store will stop tracking this window so that
+    // extensions can store any data about this window in session store before
+    // that's not possible anymore
+    let event = aWindow.document.createEvent("Events");
+    event.initEvent("SSWindowClosing", true, false);
+    aWindow.dispatchEvent(event);
+
     if (this.windowToFocus && this.windowToFocus == aWindow) {
       delete this.windowToFocus;
     }
     
     var tabbrowser = aWindow.gBrowser;
 
     TAB_EVENTS.forEach(function(aEvent) {
       tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -142,16 +142,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_615394-SSWindowState_events.js \
 	browser_618151.js \
 	browser_623779.js \
 	browser_624727.js \
 	browser_625257.js \
 	browser_628270.js \
 	browser_635418.js \
 	browser_636279.js \
+	browser_659591.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),Darwin)
 _BROWSER_TEST_FILES += \
 	browser_597071.js \
 	$(NULL)
 endif
 
--- a/browser/components/sessionstore/test/browser/browser_394759.js
+++ b/browser/components/sessionstore/test/browser/browser_394759.js
@@ -66,16 +66,18 @@ function test() {
   
     // make sure that the next closed window will increase getClosedWindowCount
     let max_windows_undo = gPrefService.getIntPref("browser.sessionstore.max_windows_undo");
     gPrefService.setIntPref("browser.sessionstore.max_windows_undo", max_windows_undo + 1);
     let closedWindowCount = ss.getClosedWindowCount();
   
     let newWin = openDialog(location, "", "chrome,all,dialog=no", testURL);
     newWin.addEventListener("load", function(aEvent) {
+      newWin.removeEventListener("load", arguments.callee, false);
+
       newWin.gBrowser.selectedBrowser.addEventListener("load", function(aEvent) {
         newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
         executeSoon(function() {
           newWin.gBrowser.addTab().linkedBrowser.stop();
           executeSoon(function() {
             // mark the window with some unique data to be restored later on
             ss.setWindowValue(newWin, uniqueKey, uniqueValue);
@@ -97,16 +99,18 @@ function test() {
                "undoCloseWindow actually returned a window");
             is(ss.getClosedWindowCount(), closedWindowCount,
                "The reopened window was removed from Recently Closed Windows");
 
             // SSTabRestored will fire more than once, so we need to make sure we count them
             let restoredTabs = 0;
             let expectedTabs = data.tabs.length;
             newWin2.addEventListener("load", function(aEvent) {
+              newWin2.removeEventListener("load", arguments.callee, false);
+
               newWin2.gBrowser.tabContainer.addEventListener("SSTabRestored", function(aEvent) {
                 if (++restoredTabs < expectedTabs)
                   return;
                 newWin2.gBrowser.tabContainer.removeEventListener("SSTabRestored", arguments.callee, true);
 
                 is(newWin2.gBrowser.tabs.length, 2,
                    "The window correctly restored 2 tabs");
                 is(newWin2.gBrowser.currentURI.spec, testURL,
@@ -155,31 +159,33 @@ function test() {
       }
       // hack to force window to be considered a popup (toolbar=no didn't work)
       let winData = windowsToOpen.shift();
       let settings = "chrome,dialog=no," +
                      (winData.isPopup ? "all=no" : "all");
       let url = "http://window" + windowsToOpen.length + ".example.com";
       let win = openDialog(location, "", settings, url);
       win.addEventListener("load", function(aEvent) {
+        win.removeEventListener("load", arguments.callee, false);
+
         win.gBrowser.selectedBrowser.addEventListener("DOMContentLoaded", function(aEvent) {
           win.gBrowser.selectedBrowser.removeEventListener("DOMContentLoaded", arguments.callee, true);
           // the window _should_ have state with a tab of url, but it doesn't
           // always happend before window.close(). addTab ensure we don't treat
           // this window as a stateless window
           win.gBrowser.addTab();
 
           executeSoon(function() {
             win.close();
             executeSoon(function() {
               openWindowRec(windowsToOpen, expectedResults, recCallback);
             });
           });
         }, true);
-      }, true);
+      }, false);
     }
 
     let windowsToOpen = [{isPopup: false},
                          {isPopup: false},
                          {isPopup: true},
                          {isPopup: true},
                          {isPopup: true}];
     let expectedResults = {mac: {popup: 3, normal: 0},
--- a/browser/components/sessionstore/test/browser/browser_461634.js
+++ b/browser/components/sessionstore/test/browser/browser_461634.js
@@ -43,71 +43,73 @@ function browserWindowsCount() {
       ++count;
   }
   return count;
 }
 
 function test() {
   /** Test for Bug 461634 **/
   is(browserWindowsCount(), 1, "Only one browser window should be open initially");
-  
+
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
-  
+
   const REMEMBER = Date.now(), FORGET = Math.random();
   let test_state = { windows: [{ "tabs": [{ "entries": [] }], _closedTabs: [
     { state: { entries: [{ url: "http://www.example.net/" }] }, title: FORGET },
     { state: { entries: [{ url: "http://www.example.net/" }] }, title: REMEMBER },
     { state: { entries: [{ url: "http://www.example.net/" }] }, title: FORGET },
     { state: { entries: [{ url: "http://www.example.net/" }] }, title: REMEMBER },
   ] }] };
   let remember_count = 2;
-  
+
   function countByTitle(aClosedTabList, aTitle)
     aClosedTabList.filter(function(aData) aData.title == aTitle).length;
-  
+
   function testForError(aFunction) {
     try {
       aFunction();
       return false;
     }
     catch (ex) {
       return ex.name == "NS_ERROR_ILLEGAL_VALUE";
     }
   }
-  
+
   // open a window and add the above closed tab list
   let newWin = openDialog(location, "", "chrome,all,dialog=no");
   newWin.addEventListener("load", function(aEvent) {
+    newWin.removeEventListener("load", arguments.callee, false);
+
     gPrefService.setIntPref("browser.sessionstore.max_tabs_undo",
                             test_state.windows[0]._closedTabs.length);
     ss.setWindowState(newWin, JSON.stringify(test_state), true);
-    
+
     let closedTabs = JSON.parse(ss.getClosedTabData(newWin));
     is(closedTabs.length, test_state.windows[0]._closedTabs.length,
        "Closed tab list has the expected length");
     is(countByTitle(closedTabs, FORGET),
        test_state.windows[0]._closedTabs.length - remember_count,
        "The correct amout of tabs are to be forgotten");
     is(countByTitle(closedTabs, REMEMBER), remember_count,
        "Everything is set up.");
-    
+
     // all of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE
     ok(testForError(function() ss.forgetClosedTab({}, 0)),
        "Invalid window for forgetClosedTab throws");
     ok(testForError(function() ss.forgetClosedTab(newWin, -1)),
        "Invalid tab for forgetClosedTab throws");
     ok(testForError(function() ss.forgetClosedTab(newWin, test_state.windows[0]._closedTabs.length + 1)),
        "Invalid tab for forgetClosedTab throws");
-	   
+
     // Remove third tab, then first tab
     ss.forgetClosedTab(newWin, 2);
     ss.forgetClosedTab(newWin, null);
-    
+
     closedTabs = JSON.parse(ss.getClosedTabData(newWin));
     is(closedTabs.length, remember_count,
        "The correct amout of tabs was removed");
     is(countByTitle(closedTabs, FORGET), 0,
        "All tabs specifically forgotten were indeed removed");
     is(countByTitle(closedTabs, REMEMBER), remember_count,
        "... and tabs not specifically forgetten weren't.");
 
--- a/browser/components/sessionstore/test/browser/browser_464199.js
+++ b/browser/components/sessionstore/test/browser/browser_464199.js
@@ -42,21 +42,21 @@ function browserWindowsCount() {
       ++count;
   }
   return count;
 }
 
 function test() {
   /** Test for Bug 464199 **/
   is(browserWindowsCount(), 1, "Only one browser window should be open initially");
-  
+
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
-  
+
   const REMEMBER = Date.now(), FORGET = Math.random();
   let test_state = { windows: [{ "tabs": [{ "entries": [] }], _closedTabs: [
     { state: { entries: [{ url: "http://www.example.net/" }] }, title: FORGET },
     { state: { entries: [{ url: "http://www.example.org/" }] }, title: REMEMBER },
     { state: { entries: [{ url: "http://www.example.net/" },
                          { url: "http://www.example.org/" }] }, title: FORGET },
     { state: { entries: [{ url: "http://example.net/" }] }, title: FORGET },
     { state: { entries: [{ url: "http://sub.example.net/" }] }, title: FORGET },
@@ -74,48 +74,50 @@ function test() {
                            ] }] }, title: FORGET },
     { state: { entries: [{ url: "http://www.example.org/form",
                            formdata: { "#url": "http://www.example.net/" }
                          }] }, title: REMEMBER },
     { state: { entries: [{ url: "http://www.example.org/form" }],
                extData: { "setTabValue": "http://example.net:80" } }, title: REMEMBER }
   ] }] };
   let remember_count = 5;
-  
+
   function countByTitle(aClosedTabList, aTitle)
     aClosedTabList.filter(function(aData) aData.title == aTitle).length;
-  
+
   // open a window and add the above closed tab list
   let newWin = openDialog(location, "", "chrome,all,dialog=no");
   newWin.addEventListener("load", function(aEvent) {
+    newWin.removeEventListener("load", arguments.callee, false);
+
     gPrefService.setIntPref("browser.sessionstore.max_tabs_undo",
                             test_state.windows[0]._closedTabs.length);
     ss.setWindowState(newWin, JSON.stringify(test_state), true);
     
     let closedTabs = JSON.parse(ss.getClosedTabData(newWin));
     is(closedTabs.length, test_state.windows[0]._closedTabs.length,
        "Closed tab list has the expected length");
     is(countByTitle(closedTabs, FORGET),
        test_state.windows[0]._closedTabs.length - remember_count,
        "The correct amout of tabs are to be forgotten");
     is(countByTitle(closedTabs, REMEMBER), remember_count,
        "Everything is set up.");
-    
+
     let pb = Cc["@mozilla.org/privatebrowsing;1"].
              getService(Ci.nsIPrivateBrowsingService);
     pb.removeDataFromDomain("example.net");
-    
+
     closedTabs = JSON.parse(ss.getClosedTabData(newWin));
     is(closedTabs.length, remember_count,
        "The correct amout of tabs was removed");
     is(countByTitle(closedTabs, FORGET), 0,
        "All tabs to be forgotten were indeed removed");
     is(countByTitle(closedTabs, REMEMBER), remember_count,
        "... and tabs to be remembered weren't.");
-    
+
     // clean up
     newWin.close();
     is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
     if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
       gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
     finish();
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_465223.js
+++ b/browser/components/sessionstore/test/browser/browser_465223.js
@@ -42,50 +42,52 @@ function browserWindowsCount() {
       ++count;
   }
   return count;
 }
 
 function test() {
   /** Test for Bug 465223 **/
   is(browserWindowsCount(), 1, "Only one browser window should be open initially");
-  
+
   // test setup
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
-  
+
   let uniqueKey1 = "bug 465223.1";
   let uniqueKey2 = "bug 465223.2";
   let uniqueValue1 = "unik" + Date.now();
   let uniqueValue2 = "pi != " + Math.random();
-  
+
   // open a window and set a value on it
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
   newWin.addEventListener("load", function(aEvent) {
+    newWin.removeEventListener("load", arguments.callee, false);
+
     ss.setWindowValue(newWin, uniqueKey1, uniqueValue1);
-    
+
     let newState = { windows: [{ tabs:[{ entries: [] }], extData: {} }] };
     newState.windows[0].extData[uniqueKey2] = uniqueValue2;
     ss.setWindowState(newWin, JSON.stringify(newState), false);
-    
+
     is(newWin.gBrowser.tabs.length, 2,
        "original tab wasn't overwritten");
     is(ss.getWindowValue(newWin, uniqueKey1), uniqueValue1,
        "window value wasn't overwritten when the tabs weren't");
     is(ss.getWindowValue(newWin, uniqueKey2), uniqueValue2,
        "new window value was correctly added");
-    
+
     newState.windows[0].extData[uniqueKey2] = uniqueValue1;
     ss.setWindowState(newWin, JSON.stringify(newState), true);
-    
+
     is(newWin.gBrowser.tabs.length, 1,
        "original tabs were overwritten");
     is(ss.getWindowValue(newWin, uniqueKey1), "",
        "window value was cleared");
     is(ss.getWindowValue(newWin, uniqueKey2), uniqueValue1,
        "window value was correctly overwritten");
-    
+
     // clean up
     newWin.close();
     is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
     finish();
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_477657.js
+++ b/browser/components/sessionstore/test/browser/browser_477657.js
@@ -52,60 +52,62 @@ function test() {
   if ("nsILocalFileMac" in Ci)
     return;
 
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
   waitForExplicitFinish();
   
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
   newWin.addEventListener("load", function(aEvent) {
+    newWin.removeEventListener("load", arguments.callee, false);
+
     let newState = { windows: [{
       tabs: [{ entries: [] }],
       _closedTabs: [{
         state: { entries: [{ url: "about:" }]},
         title: "About:"
       }],
       sizemode: "maximized"
     }] };
-    
+
     let uniqueKey = "bug 477657";
     let uniqueValue = "unik" + Date.now();
-  
+
     ss.setWindowValue(newWin, uniqueKey, uniqueValue);
     is(ss.getWindowValue(newWin, uniqueKey), uniqueValue,
        "window value was set before the window was overwritten");
     ss.setWindowState(newWin, JSON.stringify(newState), true);
-    
+
     // use setTimeout(..., 0) to mirror sss_restoreWindowFeatures
     setTimeout(function() {
       is(ss.getWindowValue(newWin, uniqueKey), "",
          "window value was implicitly cleared");
-      
+
       is(newWin.windowState, newWin.STATE_MAXIMIZED,
          "the window was maximized");
-      
+
       is(JSON.parse(ss.getClosedTabData(newWin)).length, 1,
          "the closed tab was added before the window was overwritten");
       delete newState.windows[0]._closedTabs;
       delete newState.windows[0].sizemode;
       ss.setWindowState(newWin, JSON.stringify(newState), true);
-      
+
       setTimeout(function() {
         is(JSON.parse(ss.getClosedTabData(newWin)).length, 0,
            "closed tabs were implicitly cleared");
-        
+
         is(newWin.windowState, newWin.STATE_MAXIMIZED,
            "the window remains maximized");
         newState.windows[0].sizemode = "normal";
         ss.setWindowState(newWin, JSON.stringify(newState), true);
-        
+
         setTimeout(function() {
           isnot(newWin.windowState, newWin.STATE_MAXIMIZED,
                 "the window was explicitly unmaximized");
-          
+
           newWin.close();
           is(browserWindowsCount(), 1, "Only one browser window should be open eventually");
           finish();
         }, 0);
       }, 0);
     }, 0);
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_514751.js
+++ b/browser/components/sessionstore/test/browser/browser_514751.js
@@ -61,16 +61,18 @@ function test() {
           {}
         ]
       }]
     }]
   };
 
   var theWin = openDialog(location, "", "chrome,all,dialog=no");
   theWin.addEventListener("load", function () {
+    theWin.removeEventListener("load", arguments.callee, false);
+
     executeSoon(function () {
       var gotError = false;
       try {
         ss.setWindowState(theWin, JSON.stringify(state), true);
       } catch (e) {
         if (/NS_ERROR_MALFORMED_URI/.test(e))
           gotError = true;
       }
--- a/browser/components/sessionstore/test/browser/browser_528776.js
+++ b/browser/components/sessionstore/test/browser/browser_528776.js
@@ -15,14 +15,15 @@ function browserWindowsCount(expected) {
 
 function test() {
   waitForExplicitFinish();
 
   browserWindowsCount(1);
 
   var win = openDialog(location, "", "chrome,all,dialog=no");
   win.addEventListener("load", function () {
+    win.removeEventListener("load", arguments.calle, false);
     browserWindowsCount(2);
     win.close();
     browserWindowsCount(1);
     finish();
   }, false);
 }
--- a/browser/components/sessionstore/test/browser/browser_579868.js
+++ b/browser/components/sessionstore/test/browser/browser_579868.js
@@ -32,20 +32,22 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 function test() {
   let tab1 = gBrowser.addTab("about:robots");
   let tab2 = gBrowser.addTab("about:mozilla");
-  tab1.addEventListener("load", mainPart, true);
+  tab1.linkedBrowser.addEventListener("load", mainPart, true);
   waitForExplicitFinish();
 
   function mainPart() {
+    tab1.linkedBrowser.removeEventListener("load", mainPart, true);
+
     // Tell the session storer that the tab is pinned
     let newTabState = '{"entries":[{"url":"about:robots"}],"pinned":true,"userTypedValue":"Hello World!"}';
     let ss = Cc["@mozilla.org/browser/sessionstore;1"]
                .getService(Ci.nsISessionStore);
     ss.setTabState(tab1, newTabState);
 
     // Undo pinning
     gBrowser.unpinTab(tab1);
--- a/browser/components/sessionstore/test/browser/browser_579879.js
+++ b/browser/components/sessionstore/test/browser/browser_579879.js
@@ -1,15 +1,17 @@
 function test() {
   waitForExplicitFinish();
 
   var tab1 = gBrowser.addTab("data:text/plain,foo");
   gBrowser.pinTab(tab1);
 
   tab1.linkedBrowser.addEventListener("load", function () {
+    tab1.linkedBrowser.removeEventListener("load", arguments.callee, true);
+
     var tab2 = gBrowser.addTab();
     gBrowser.pinTab(tab2);
 
     is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 is at the first position");
     gBrowser.removeTab(tab1);
     tab1 = undoCloseTab();
     ok(tab1.pinned, "pinned tab 1 has been restored as a pinned tab");
     is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 has been restored to the first position");
--- a/browser/components/sessionstore/test/browser/browser_580512.js
+++ b/browser/components/sessionstore/test/browser/browser_580512.js
@@ -39,16 +39,17 @@ function checkSecondWin(win) {
 function openWinWithCb(cb, argURIs, expectedURIs) {
   if (!expectedURIs)
     expectedURIs = argURIs;
 
   var win = openDialog("chrome://browser/content/", "_blank",
                        "chrome,all,dialog=no", argURIs.join("|"));
 
   win.addEventListener("load", function () {
+    win.removeEventListener("load", arguments.callee, false);
     info("the window loaded");
 
     var expectedLoads = expectedURIs.length;
 
     win.gBrowser.addTabsProgressListener({
       onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
         if (aRequest &&
             aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
--- a/browser/components/sessionstore/test/browser/browser_589246.js
+++ b/browser/components/sessionstore/test/browser/browser_589246.js
@@ -201,17 +201,20 @@ function onStateRestored(aSubject, aTopi
 
     newWin.gBrowser.selectedBrowser.addEventListener("load", function() {
       newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
       // pin this tab
       if (shouldPinTab)
         newWin.gBrowser.pinTab(newWin.gBrowser.selectedTab);
 
-      newWin.addEventListener("unload", onWindowUnloaded, false);
+      newWin.addEventListener("unload", function () {
+        newWin.removeEventListener("unload", arguments.callee, false);
+        onWindowUnloaded();
+      }, false);
       // Open a new tab as well. On Windows/Linux this will be restored when the
       // new window is opened below (in onWindowUnloaded). On OS X we'll just
       // restore the pinned tabs, leaving the unpinned tab in the closedWindowsData.
       if (shouldOpenTabs) {
         let newTab = newWin.gBrowser.addTab("about:config");
         let newTab2 = newWin.gBrowser.addTab("about:buildconfig");
 
         newTab.linkedBrowser.addEventListener("load", function() {
@@ -252,16 +255,18 @@ function onWindowUnloaded() {
   let previousClosedWindowData = ss.getClosedWindowData();
 
   // Now we want to open a new window
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:robots");
   newWin.addEventListener("load", function(aEvent) {
     newWin.removeEventListener("load", arguments.callee, false);
 
     newWin.gBrowser.selectedBrowser.addEventListener("load", function () {
+      newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
       // Good enough for checking the state
       afterTestCallback(previousClosedWindowData, ss.getClosedWindowData());
       afterTestCleanup(newWin);
     }, true);
 
   }, false);
 }
 
--- a/browser/components/sessionstore/test/browser/browser_597071.js
+++ b/browser/components/sessionstore/test/browser/browser_597071.js
@@ -68,28 +68,31 @@ function test() {
 
   // set this window to be a popup.
   ss.setWindowState(window, JSON.stringify(popupState), true);
 
   // open a new non-popup window
   let newWin = openDialog(location, "", "chrome,all,dialog=no", "http://example.com");
   newWin.addEventListener("load", function(aEvent) {
     newWin.removeEventListener("load", arguments.callee, false);
+
     newWin.gBrowser.addEventListener("load", function(aEvent) {
       newWin.gBrowser.removeEventListener("load", arguments.callee, true);
 
       newWin.gBrowser.addTab().linkedBrowser.stop();
       // make sure there are 2 windows open
       is(browserWindowsCount(), 2, "there should be 2 windows open currently");
       // make sure sessionstore sees this window
       let state = JSON.parse(ss.getBrowserState());
       is(state.windows.length, 2, "sessionstore knows about this window");
 
       newWin.close();
       newWin.addEventListener("unload", function(aEvent) {
+        newWin.removeEventListener("unload", arguments.callee, false);
+
         is(ss.getClosedWindowCount(), closedWindowCount + 1,
            "increased closed window count");
         is(browserWindowsCount(), 1, "there should be 1 window open currently");
 
         try {
           Services.prefs.clearUserPref("browser.sessionstore.max_windows_undo");
         } catch (e) {}
         ss.setBrowserState(currentState);
--- a/browser/components/sessionstore/test/browser/browser_615394-SSWindowState_events.js
+++ b/browser/components/sessionstore/test/browser/browser_615394-SSWindowState_events.js
@@ -30,17 +30,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const ss = Cc["@mozilla.org/browser/sessionstore;1"].
+var ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
 
 const stateBackup = ss.getBrowserState();
 const testState = {
   windows: [{
     tabs: [
       { entries: [{ url: "about:blank" }] },
       { entries: [{ url: "about:robots" }] }
@@ -287,21 +287,23 @@ function test_setWindowState() {
 function test_setBrowserState() {
   // We'll track events per window so we are sure that they are each happening once
   // pre window.
   let windowEvents = {};
   windowEvents[getOuterWindowID(window)] = { busyEventCount: 0, readyEventCount: 0 };
 
   // waitForBrowserState does it's own observing for windows, but doesn't attach
   // the listeners we want here, so do it ourselves.
+  let newWindow;
   function windowObserver(aSubject, aTopic, aData) {
     if (aTopic == "domwindowopened") {
-      let newWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
+      newWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
       newWindow.addEventListener("load", function() {
         newWindow.removeEventListener("load", arguments.callee, false);
+
         Services.ww.unregisterNotification(windowObserver);
 
         windowEvents[getOuterWindowID(newWindow)] = { busyEventCount: 0, readyEventCount: 0 };
 
         newWindow.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false);
         newWindow.addEventListener("SSWindowStateReady", onSSWindowStateReady, false);
       }, false);
     }
@@ -327,16 +329,18 @@ function test_setBrowserState() {
       is(winEvents.readyEventCount, 1,
          "[test_setBrowserState] window" + id + " ready event count correct");
       checkedWindows++;
     }
     is(checkedWindows, 2,
        "[test_setBrowserState] checked 2 windows");
     window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false);
     window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false);
+    newWindow.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false);
+    newWindow.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false);
     runNextTest();
   });
 }
 
 
 function test_undoCloseWindow() {
   let newWindow, reopenedWindow;
 
@@ -352,16 +356,17 @@ function test_undoCloseWindow() {
     // Close the window which isn't window
     newWindow.close();
     reopenedWindow = ss.undoCloseWindow(0);
     reopenedWindow.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false);
     reopenedWindow.addEventListener("SSWindowStateReady", onSSWindowStateReady, false);
 
     reopenedWindow.addEventListener("load", function() {
       reopenedWindow.removeEventListener("load", arguments.callee, false);
+
       reopenedWindow.gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, false);
     }, false);
   });
 
   let busyEventCount = 0,
       readyEventCount = 0,
       tabRestoredCount = 0;
   // These will listen to the reopened closed window...
--- a/browser/components/sessionstore/test/browser/browser_618151.js
+++ b/browser/components/sessionstore/test/browser/browser_618151.js
@@ -30,17 +30,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const ss = Cc["@mozilla.org/browser/sessionstore;1"].
+var ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
 
 const stateBackup = ss.getBrowserState();
 const testState = {
   windows: [{
     tabs: [
       { entries: [{ url: "about:blank" }] },
       { entries: [{ url: "about:robots" }] }
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_659591.js
@@ -0,0 +1,32 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  let eventReceived = false;
+
+  registerCleanupFunction(function () {
+    ok(eventReceived, "SSWindowClosing event received");
+  });
+
+  newWindow(function (win) {
+    win.addEventListener("SSWindowClosing", function onWindowClosing() {
+      win.removeEventListener("SSWindowClosing", onWindowClosing, false);
+      eventReceived = true;
+      waitForFocus(finish);
+    }, false);
+
+    win.close();
+  });
+}
+
+function newWindow(callback) {
+  let opts = "chrome,all,dialog=no,height=800,width=800";
+  let win = window.openDialog(getBrowserURL(), "_blank", opts);
+
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+    executeSoon(function () callback(win));
+  }, false);
+}
--- a/browser/components/shell/test/browser_420786.js
+++ b/browser/components/shell/test/browser_420786.js
@@ -1,14 +1,16 @@
 const DG_BACKGROUND = "/desktop/gnome/background"
 const DG_IMAGE_KEY = DG_BACKGROUND + "/picture_filename";
 const DG_OPTION_KEY = DG_BACKGROUND + "/picture_options";
 const DG_DRAW_BG_KEY = DG_BACKGROUND + "/draw_background";
 
 function onPageLoad() {
+  gBrowser.selectedBrowser.removeEventListener("load", onPageLoad, true);
+
   var bs = Cc["@mozilla.org/intl/stringbundle;1"].
            getService(Ci.nsIStringBundleService);
   var brandName = bs.createBundle("chrome://branding/locale/brand.properties").
                   GetStringFromName("brandShortName");
 
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                getService(Ci.nsIDirectoryServiceProvider);
   var homeDir = dirSvc.getFile("Home", {});
--- a/browser/components/sidebar/src/nsSidebar.js
+++ b/browser/components/sidebar/src/nsSidebar.js
@@ -41,18 +41,18 @@
 #
 # ***** END LICENSE BLOCK *****
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const DEBUG = false; /* set to false to suppress debug messages */
 
+const SIDEBAR_CONTRACTID        = "@mozilla.org/sidebar;1";
 const SIDEBAR_CID               = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}");
-const nsISupports               = Components.interfaces.nsISupports;
 const nsISidebar                = Components.interfaces.nsISidebar;
 const nsISidebarExternal        = Components.interfaces.nsISidebarExternal;
 const nsIClassInfo              = Components.interfaces.nsIClassInfo;
 
 // File extension for Sherlock search plugin description files
 const SHERLOCK_FILE_EXT_REGEXP = /\.src$/i;
 
 function nsSidebar()
@@ -209,42 +209,23 @@ function (aDescriptionURL)
 // http://msdn.microsoft.com/en-us/library/aa342526%28VS.85%29.aspx .
 // XXX Implement this!
 nsSidebar.prototype.IsSearchProviderInstalled =
 function (aSearchURL)
 {
   return 0;
 }
 
-// property of nsIClassInfo
-nsSidebar.prototype.flags = nsIClassInfo.DOM_OBJECT;
-
-// property of nsIClassInfo
-nsSidebar.prototype.classDescription = "Sidebar";
-
-// method of nsIClassInfo
-nsSidebar.prototype.getInterfaces = function(count) {
-    var interfaceList = [nsISidebar, nsISidebarExternal, nsIClassInfo];
-    count.value = interfaceList.length;
-    return interfaceList;
-}
+nsSidebar.prototype.classInfo = XPCOMUtils.generateCI({classID: SIDEBAR_CID,
+                                                       contractID: SIDEBAR_CONTRACTID,
+                                                       classDescription: "Sidebar",
+                                                       interfaces: [nsISidebar, nsISidebarExternal],
+                                                       flags: nsIClassInfo.DOM_OBJECT});
 
-// method of nsIClassInfo
-nsSidebar.prototype.getHelperForLanguage = function(count) {return null;}
-
-nsSidebar.prototype.QueryInterface =
-function (iid) {
-    if (iid.equals(nsISidebar) ||
-        iid.equals(nsISidebarExternal) ||
-        iid.equals(nsIClassInfo) ||
-        iid.equals(nsISupports))
-        return this;
-
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-};
+nsSidebar.prototype.QueryInterface = XPCOMUtils.generateQI([nsISidebar, nsISidebarExternal]);
 
 var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSidebar]);
 
 /* static functions */
 if (DEBUG)
     debug = function (s) { dump("-*- sidebar component: " + s + "\n"); }
 else
     debug = function (s) {}
--- a/browser/components/test/browser/browser_bug538331.js
+++ b/browser/components/test/browser/browser_bug538331.js
@@ -160,17 +160,20 @@ var gWindowCatcher = {
 
   observe: function(subject, topic, data) {
     if (topic != "domwindowopened")
       return;
 
     this.windowsOpen++;
     let win = subject.QueryInterface(Ci.nsIDOMWindow);
     info("window catcher caught window opening: " + win.document.documentURI);
-    win.addEventListener("load", this.windowLoad.bind(this, win), false);
+    win.addEventListener("load", function () {
+      win.removeEventListener("load", arguments.callee, false);
+      gWindowCatcher.windowLoad(win);
+    }, false);
   }
 };
 
 function finish_test()
 {
   // Reset browser.startup.homepage_override.mstone to the original value or
   // clear it if it didn't exist.
   if (gOriginalMStone) {
@@ -352,17 +355,20 @@ function testShowNotification()
           }
         }
         // The last test opens an url and verifies the url from the updates.xml
         // is correct.
         if (i == (BG_NOTIFY_TESTS.length - 1)) {
           // Wait for any windows caught by the windowcatcher to close
           gWindowCatcher.finish(function () {
             button.click();
-            gBrowser.selectedBrowser.addEventListener("load", testNotificationURL, true);
+            gBrowser.selectedBrowser.addEventListener("load", function () {
+              gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+              testNotificationURL();
+            }, true);
           });
         } else {
           notifyBox.removeAllNotifications(true);
         }
       } else if (i == (BG_NOTIFY_TESTS.length - 1)) {
         // If updateBox is null the test has already reported errors so bail
         finish_test();
       }
--- a/browser/fuel/src/fuelApplication.js
+++ b/browser/fuel/src/fuelApplication.js
@@ -35,16 +35,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
+const APPLICATION_CID = Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66");
+const APPLICATION_CONTRACTID = "@mozilla.org/fuel/application;1";
+
 //=================================================
 // Singleton that holds services and utilities
 var Utilities = {
   get bookmarks() {
     let bookmarks = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
                     getService(Ci.nsINavBookmarksService);
     this.__defineGetter__("bookmarks", function() bookmarks);
     return this.bookmarks;
@@ -663,31 +666,32 @@ function Application() {
   this.initToolkitHelpers();
   this._bookmarks = null;
 }
 
 //=================================================
 // Application implementation
 Application.prototype = {
   // for nsIClassInfo + XPCOMUtils
-  classID:          Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66"),
+  classID:          APPLICATION_CID,
 
   // redefine the default factory for XPCOMUtils
   _xpcom_factory: ApplicationFactory,
 
   // for nsISupports
   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIApplication, Ci.extIApplication,
-                                          Ci.nsIObserver, Ci.nsIClassInfo]),
+                                          Ci.nsIObserver]),
 
-  getInterfaces : function app_gi(aCount) {
-    var interfaces = [Ci.fuelIApplication, Ci.extIApplication, Ci.nsIObserver,
-                      Ci.nsIClassInfo];
-    aCount.value = interfaces.length;
-    return interfaces;
-  },
+  // for nsIClassInfo
+  classInfo: XPCOMUtils.generateCI({classID: APPLICATION_CID,
+                                    contractID: APPLICATION_CONTRACTID,
+                                    interfaces: [Ci.fuelIApplication,
+                                                 Ci.extIApplication,
+                                                 Ci.nsIObserver],
+                                    flags: Ci.nsIClassInfo.SINGLETON}),
 
   // for nsIObserver
   observe: function app_observe(aSubject, aTopic, aData) {
     // Call the extApplication version of this function first
     this.__proto__.__proto__.observe.call(this, aSubject, aTopic, aData);
     if (aTopic == "xpcom-shutdown") {
       this._obs.removeObserver(this, "xpcom-shutdown");
       this._bookmarks = null;
--- a/browser/locales/en-US/chrome/overrides/appstrings.properties
+++ b/browser/locales/en-US/chrome/overrides/appstrings.properties
@@ -58,9 +58,10 @@ externalProtocolTitle=External Protocol 
 externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n
 #LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined
 externalProtocolUnknown=<Unknown>
 externalProtocolChkMsg=Remember my choice for all links of this type.
 externalProtocolLaunchBtn=Launch application
 malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
 phishingBlocked=The web site at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
 cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
+corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
 remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -166,16 +166,20 @@ be temporary, and you can try again late
 <!ENTITY phishingBlocked.longDesc "
 <p>Entering any personal information on this page may result in identity theft or other fraud.</p>
 <p>These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.</p>
 ">
 
 <!ENTITY cspFrameAncestorBlocked.title "Blocked by Content Security Policy">
 <!ENTITY cspFrameAncestorBlocked.longDesc "<p>&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
 
+<!ENTITY corruptedContentError.title "Corrupted Content Error">
+<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
+
+
 <!ENTITY securityOverride.linkText "Or you can add an exception…">
 <!ENTITY securityOverride.getMeOutOfHereButton "Get me out of here!">
 <!ENTITY securityOverride.exceptionButtonLabel "Add Exception…">
 
 <!-- LOCALIZATION NOTE (securityOverride.warningContent) - Do not translate the
 contents of the <button> tags. It uses strings already defined above. The
 button is included here (instead of netError.xhtml) because it exposes
 functionality specific to firefox. -->
new file mode 100755
--- /dev/null
+++ b/build/autoconf/libstdcxx.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+
+# This script find the version of libstdc++ and prints it as single number
+# with 8 bits per element. For example, GLIBCXX_3.4.10 becomes
+# 3 << 16 | 4 << 8 | 10 = 197642. This format is easy to use
+# in the C preprocessor.
+
+# We find out both the host and target versions. Since the output
+# will be used from shell, we just print the two assignments and evaluate
+# them from shell.
+
+import os
+import subprocess
+import re
+
+re_for_ld = re.compile('.*\((.*)\).*')
+
+def parse_readelf_line(x):
+    """Return the version from a readelf line that looks like:
+    0x00ec: Rev: 1  Flags: none  Index: 8  Cnt: 2  Name: GLIBCXX_3.4.6
+    """
+    return x.split(':')[-1].split('_')[-1].strip()
+
+def parse_ld_line(x):
+    """Parse a line from the output of ld -t. The output of gold is just
+    the full path, gnu ld prints "-lstdc++ (path)".
+    """
+    t = re_for_ld.match(x)
+    if t:
+        return t.groups()[0].strip()
+    return x.strip()
+
+def split_ver(v):
+    """Covert the string '1.2.3' into the list [1,2,3]
+    """
+    return [int(x) for x in v.split('.')]
+
+def cmp_ver(a, b):
+    """Compare versions in the form 'a.b.c'
+    """
+    for (i, j) in zip(split_ver(a), split_ver(b)):
+        if i != j:
+            return i - j
+    return 0
+
+def encode_ver(v):
+    """Encode the version as a single number.
+    """
+    t = split_ver(v)
+    return t[0] << 16 | t[1] << 8 | t[2]
+
+def find_version(e):
+    """Given the value of environment variable CXX or HOST_CXX, find the
+    version of the libstdc++ it uses.
+    """
+    args = e.split()
+    args +=  ['-shared', '-Wl,-t']
+    p = subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+    candidates = [x for x in p.stdout if 'libstdc++.so' in x]
+    assert len(candidates) == 1
+    libstdcxx = parse_ld_line(candidates[-1])
+
+    p = subprocess.Popen(['readelf', '-V', libstdcxx], stdout=subprocess.PIPE)
+    versions = [parse_readelf_line(x)
+                for x in p.stdout.readlines() if 'Name: GLIBCXX' in x]
+    last_version = sorted(versions, cmp = cmp_ver)[-1]
+    return encode_ver(last_version)
+
+if __name__ == '__main__':
+    cxx_env = os.environ['CXX']
+    print 'MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env)
+    host_cxx_env = os.environ.get('HOST_CXX', cxx_env)
+    print 'MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env)
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -329,16 +329,17 @@ class Automation(object):
     # Set up permissions database
     locations = self.readLocations()
     self.setupPermissionsDatabase(profileDir,
       {'allowXULXBL':[(l.host, 'noxul' not in l.options) for l in locations]});
 
     part = """\
 user_pref("browser.console.showInPanel", true);
 user_pref("browser.dom.window.dump.enabled", true);
+user_pref("browser.firstrun.show.localepicker", false);
 user_pref("dom.allow_scripts_to_close_windows", true);
 user_pref("dom.disable_open_during_load", false);
 user_pref("dom.max_script_run_time", 0); // no slow script dialogs
 user_pref("dom.max_chrome_script_run_time", 0);
 user_pref("dom.popup_maximum", -1);
 user_pref("dom.send_after_paint_to_content", true);
 user_pref("dom.successive_dialog_time_limit", 0);
 user_pref("signed.applets.codebase_principal_support", true);
--- a/build/stdc++compat.cpp
+++ b/build/stdc++compat.cpp
@@ -36,27 +36,40 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include <ostream>
 #include <istream>
 #ifdef DEBUG
 #include <string>
 #endif
 
+
+/* GLIBCXX_3.4.8  is from gcc 4.1.1 (111691)
+   GLIBCXX_3.4.9  is from gcc 4.2.0 (111690)
+   GLIBCXX_3.4.10 is from gcc 4.3.0 (126287)
+   GLIBCXX_3.4.11 is from gcc 4.4.0 (133006)
+   GLIBCXX_3.4.12 is from gcc 4.4.1 (147138)
+   GLIBCXX_3.4.13 is from gcc 4.4.2 (151127)
+   GLIBCXX_3.4.14 is from gcc 4.5.0 (151126)
+   GLIBCXX_3.4.15 is from gcc 4.6.0 (160071)
+   GLIBCXX_3.4.16 is form gcc 4.6.1 (172240) */
+
+#define GLIBCXX_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c))
+
 namespace std {
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 9)
     /* Instantiate these templates to avoid GLIBCXX_3.4.9 symbol versions */
     template ostream& ostream::_M_insert(double);
     template ostream& ostream::_M_insert(long);
     template ostream& ostream::_M_insert(unsigned long);
     template ostream& __ostream_insert(ostream&, const char*, streamsize);
     template istream& istream::_M_extract(double&);
 #endif
 #ifdef DEBUG
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
     /* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions
      * in debug builds */
     template char *string::_S_construct_aux_2(size_type, char, allocator<char> const&);
 #ifdef _GLIBCXX_USE_WCHAR_T
     template wchar_t *wstring::_S_construct_aux_2(size_type, wchar_t, allocator<wchar_t> const&);
 #endif /* _GLIBCXX_USE_WCHAR_T */
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
     template string::basic_string(string&&);
@@ -65,45 +78,45 @@ namespace std {
     template wstring& wstring::operator=(wstring&&);
     template wstring& wstring::assign(wstring&&);
 #endif /* __GXX_EXPERIMENTAL_CXX0X__ */
 #endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */
 #endif /* DEBUG */
 }
 
 namespace std __attribute__((visibility("default"))) {
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
     /* Hack to avoid GLIBCXX_3.4.14 symbol versions */
     struct _List_node_base
     {
         void hook(_List_node_base * const __position) throw ();
 
         void unhook() throw ();
 
         void transfer(_List_node_base * const __first,
                       _List_node_base * const __last) throw();
 
 /* Hack to avoid GLIBCXX_3.4.15 symbol versions */
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 15)
         static void swap(_List_node_base& __x, _List_node_base& __y) throw ();
     };
 
     namespace __detail {
 
     struct _List_node_base
     {
 #endif
         void _M_hook(_List_node_base * const __position) throw ();
 
         void _M_unhook() throw ();
 
         void _M_transfer(_List_node_base * const __first,
                          _List_node_base * const __last) throw();
 
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 15)
         static void swap(_List_node_base& __x, _List_node_base& __y) throw ();
 #endif
     };
 
     /* The functions actually have the same implementation */
     void
     _List_node_base::_M_hook(_List_node_base * const __position) throw ()
     {
@@ -119,29 +132,29 @@ namespace std __attribute__((visibility(
     void
     _List_node_base::_M_transfer(_List_node_base * const __first,
                                  _List_node_base * const __last) throw ()
     {
         ((std::_List_node_base *)this)->transfer((std::_List_node_base * const)__first,
                                                  (std::_List_node_base * const)__last);
     }
 
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 15)
     void
     _List_node_base::swap(_List_node_base& __x, _List_node_base& __y) throw ()
     {
         std::_List_node_base::swap(*((std::_List_node_base *) &__x),
                                    *((std::_List_node_base *) &__y));
     }
 }
 #endif
 
-#endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */
+#endif /*MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)*/
 
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)
+#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 11)
     /* Hack to avoid GLIBCXX_3.4.11 symbol versions
        An inline definition of ctype<char>::_M_widen_init() used to be in
        locale_facets.h before GCC 4.4, but moved out of headers in more
        recent versions.
        It is actually safe to make it do nothing. */
     void ctype<char>::_M_widen_init() const {}
 #endif
 
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2794,17 +2794,19 @@ nsScriptSecurityManager::RequestCapabili
                                            const char *capability, PRInt16* canEnable)
 {
     if (NS_FAILED(aPrincipal->CanEnableCapability(capability, canEnable)))
         return NS_ERROR_FAILURE;
     if (*canEnable == nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
     {
         // Prompt user for permission to enable capability.
         JSContext* cx = GetCurrentJSContext();
-        PRBool remember;
+        // The actual value is irrelevant but we shouldn't be handing out
+        // malformed JSBools to XPConnect.
+        PRBool remember = PR_FALSE;
         if (CheckConfirmDialog(cx, aPrincipal, capability, &remember))
             *canEnable = nsIPrincipal::ENABLE_GRANTED;
         else
             *canEnable = nsIPrincipal::ENABLE_DENIED;
         if (remember)
         {
             //-- Save principal to prefs and to mPrincipals
             if (NS_FAILED(aPrincipal->SetCanEnableCapability(capability, *canEnable)))
--- a/chrome/src/nsChromeRegistry.h
+++ b/chrome/src/nsChromeRegistry.h
@@ -111,17 +111,17 @@ public:
   static nsresult Canonify(nsIURL* aChromeURL);
 
 protected:
   void FlushSkinCaches();
   void FlushAllCaches();
 
   // Update the selected locale used by the chrome registry, and fire a
   // notification about this change
-  virtual void UpdateSelectedLocale() = 0;
+  virtual nsresult UpdateSelectedLocale() = 0;
 
   static void LogMessage(const char* aMsg, ...);
   static void LogMessageWithContext(nsIURI* aURL, PRUint32 aLineNumber, PRUint32 flags,
                                     const char* aMsg, ...);
 
   virtual nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                         const nsCString& aProvider,
                                         const nsCString& aPath) = 0;
--- a/chrome/src/nsChromeRegistryChrome.cpp
+++ b/chrome/src/nsChromeRegistryChrome.cpp
@@ -363,22 +363,19 @@ nsChromeRegistryChrome::Observe(nsISuppo
   if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
     nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
     NS_ASSERTION(prefs, "Bad observer call!");
 
     NS_ConvertUTF16toUTF8 pref(someData);
 
     if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
         pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
-      if (!mProfileLoaded) {
-        rv = SelectLocaleFromPref(prefs);
-        if (NS_FAILED(rv))
-          return rv;
-      }
-      FlushAllCaches();
+        rv = UpdateSelectedLocale();
+        if (NS_SUCCEEDED(rv) && mProfileLoaded)
+          FlushAllCaches();
     }
     else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
       nsXPIDLCString provider;
       rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
       if (NS_FAILED(rv)) {
         NS_ERROR("Couldn't get new skin pref!");
         return rv;
       }
@@ -421,29 +418,32 @@ nsChromeRegistryChrome::CheckForNewChrom
   mOverlayHash.Clear();
   mStyleHash.Clear();
   mOverrideTable.Clear();
 
   nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
   return NS_OK;
 }
 
-void nsChromeRegistryChrome::UpdateSelectedLocale()
+nsresult nsChromeRegistryChrome::UpdateSelectedLocale()
 {
+  nsresult rv = NS_OK;
   nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefs) {
-    nsresult rv = SelectLocaleFromPref(prefs);
+    rv = SelectLocaleFromPref(prefs);
     if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<nsIObserverService> obsSvc =
         mozilla::services::GetObserverService();
       NS_ASSERTION(obsSvc, "Couldn't get observer service.");
       obsSvc->NotifyObservers((nsIChromeRegistry*) this,
                               "selected-locale-has-changed", nsnull);
     }
   }
+
+  return rv;
 }
 
 static void
 SerializeURI(nsIURI* aURI,
              SerializedURI& aSerializedURI)
 {
   if (!aURI)
     return;
--- a/chrome/src/nsChromeRegistryChrome.h
+++ b/chrome/src/nsChromeRegistryChrome.h
@@ -78,17 +78,17 @@ class nsChromeRegistryChrome : public ns
   void SendRegisteredChrome(mozilla::dom::PContentParent* aChild);
 
  private:
   static PLDHashOperator CollectPackages(PLDHashTable *table,
                                          PLDHashEntryHdr *entry,
                                          PRUint32 number, void *arg);
 
   nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
-  NS_OVERRIDE void UpdateSelectedLocale();
+  NS_OVERRIDE nsresult UpdateSelectedLocale();
   NS_OVERRIDE nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                              const nsCString& aProvider,
                                              const nsCString& aPath);
   NS_OVERRIDE nsresult GetFlagsFromPackage(const nsCString& aPackage,
                                            PRUint32* aFlags);
 
   static const PLDHashTableOps kTableOps;
   static PLDHashNumber HashKey(PLDHashTable *table, const void *key);
--- a/chrome/src/nsChromeRegistryContent.cpp
+++ b/chrome/src/nsChromeRegistryContent.cpp
@@ -273,19 +273,19 @@ nsChromeRegistryContent::GetStyleOverlay
 
 NS_IMETHODIMP
 nsChromeRegistryContent::GetXULOverlays(nsIURI *aChromeURL,
                                         nsISimpleEnumerator **aResult)
 {
   CONTENT_NOT_IMPLEMENTED();
 }
 
-void nsChromeRegistryContent::UpdateSelectedLocale()
+nsresult nsChromeRegistryContent::UpdateSelectedLocale()
 {
-  CONTENT_NOTREACHED();
+  CONTENT_NOT_IMPLEMENTED();
 }
 
 void
 nsChromeRegistryContent::ManifestContent(ManifestProcessingContext& cx,
                                          int lineno, char *const * argv,
                                          bool platform, bool contentaccessible)
 {
   CONTENT_NOTREACHED();
--- a/chrome/src/nsChromeRegistryContent.h
+++ b/chrome/src/nsChromeRegistryContent.h
@@ -84,17 +84,17 @@ class nsChromeRegistryContent : public n
     nsCOMPtr<nsIURI> skinBaseURI;
     PRUint32         flags;
   };
   
   void RegisterPackage(const ChromePackage& aPackage);
   void RegisterResource(const ResourceMapping& aResource);
   void RegisterOverride(const OverrideMapping& aOverride);
 
-  NS_OVERRIDE void UpdateSelectedLocale();
+  NS_OVERRIDE nsresult UpdateSelectedLocale();
   NS_OVERRIDE nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                  const nsCString& aProvider,
                                  const nsCString& aPath);
   NS_OVERRIDE nsresult GetFlagsFromPackage(const nsCString& aPackage, PRUint32* aFlags);
 
   nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
   nsCString mLocale;
 
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -115,16 +115,18 @@ MOZ_VTUNE       = @MOZ_VTUNE@
 MOZ_TRACE_JSCALLS = @MOZ_TRACE_JSCALLS@
 MOZ_TRACEVIS    = @MOZ_TRACEVIS@
 DEHYDRA_PATH    = @DEHYDRA_PATH@
 
 NS_TRACE_MALLOC = @NS_TRACE_MALLOC@
 USE_ELF_DYNSTR_GC = @USE_ELF_DYNSTR_GC@
 USE_ELF_HACK = @USE_ELF_HACK@
 STDCXX_COMPAT = @STDCXX_COMPAT@
+MOZ_LIBSTDCXX_TARGET_VERSION=@MOZ_LIBSTDCXX_TARGET_VERSION@
+MOZ_LIBSTDCXX_HOST_VERSION=@MOZ_LIBSTDCXX_HOST_VERSION@
 INCREMENTAL_LINKER = @INCREMENTAL_LINKER@
 MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@
 MOZ_MAIL_NEWS	= @MOZ_MAIL_NEWS@
 ENABLE_TESTS	= @ENABLE_TESTS@
 IBMBIDI = @IBMBIDI@
 MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
 ACCESSIBILITY = @ACCESSIBILITY@
 MOZ_BRANDING_DIRECTORY = @MOZ_BRANDING_DIRECTORY@
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -902,16 +902,19 @@ ifdef SHARED_LIBRARY
 endif
 endif # SHARED_LIBRARY || PROGRAM
 endif # WINNT_
 endif # MOZ_PROFILE_GENERATE || MOZ_PROFILE_USE
 endif # NO_PROFILE_GUIDED_OPTIMIZE
 
 ##############################################
 
+stdc++compat.$(OBJ_SUFFIX): CXXFLAGS+=-DMOZ_LIBSTDCXX_VERSION=$(MOZ_LIBSTDCXX_TARGET_VERSION)
+host_stdc++compat.$(OBJ_SUFFIX): CXXFLAGS+=-DMOZ_LIBSTDCXX_VERSION=$(MOZ_LIBSTDCXX_HOST_VERSION)
+
 checkout:
 	$(MAKE) -C $(topsrcdir) -f client.mk checkout
 
 clean clobber realclean clobber_all:: $(SUBMAKEFILES)
 	-$(RM) $(ALL_TRASH)
 	-$(RM) -r $(ALL_TRASH_DIRS)
 	$(foreach dir,$(PARALLEL_DIRS) $(DIRS) $(STATIC_DIRS) $(TOOL_DIRS),-$(call SUBMAKE,$@,$(dir)))
 
--- a/configure.in
+++ b/configure.in
@@ -1051,17 +1051,16 @@ MOZ_ARG_ENABLE_STRING(macos-target,
                           Set the minimum MacOS version needed at runtime],
                       [_MACOSX_DEPLOYMENT_TARGET=$enableval])
 
 case "$target" in
 *-darwin*)
     if test -n "$_MACOSX_DEPLOYMENT_TARGET" ; then
         dnl Use the specified value
         export MACOSX_DEPLOYMENT_TARGET=$_MACOSX_DEPLOYMENT_TARGET
-        AC_DEFINE_UNQUOTED(__ENVIRONMENT_MAC_OS_X_VERION_MIN_REQUIRED__,$_MACOSX_DEPLOYMENT_TARGET)
     else
         dnl No value specified on the command line or in the environment,
         dnl use architecture minimum.
         case "${target_cpu}" in
           ppc*)
             export MACOSX_DEPLOYMENT_TARGET=10.5
             ;;
           i*86)
@@ -5062,16 +5061,17 @@ cairo-qt)
     MOZ_ENABLE_XREMOTE=1
     MOZ_WEBGL=1
     MOZ_WEBGL_GLX=1
     USE_ELF_DYNSTR_GC=
 
     AC_DEFINE(MOZ_X11)
     MOZ_X11=1
     USE_FC_FREETYPE=1
+    XT_LIBS=
 
     TK_CFLAGS='$(MOZ_QT_CFLAGS)'
     TK_LIBS='$(MOZ_QT_LIBS)'
     AC_DEFINE(MOZ_WIDGET_QT)
     MOZ_PDF_PRINTING=1
     ;;
 
 cairo-os2)
@@ -7660,16 +7660,22 @@ dnl ====================================
 
 STDCXX_COMPAT=
 MOZ_ARG_ENABLE_BOOL(stdcxx-compat,
 [  --enable-stdcxx-compat  Enable compatibility with older libstdc++],
     STDCXX_COMPAT=stdc++compat.cpp)
 
 AC_SUBST(STDCXX_COMPAT)
 
+if test -n "$STDCXX_COMPAT"; then
+   eval $($_topsrcdir/build/autoconf/libstdcxx.py)
+   AC_SUBST(MOZ_LIBSTDCXX_TARGET_VERSION)
+   AC_SUBST(MOZ_LIBSTDCXX_HOST_VERSION)
+fi
+
 dnl ========================================================
 dnl = 
 dnl = Profiling and Instrumenting
 dnl = 
 dnl ========================================================
 MOZ_ARG_HEADER(Profiling and Instrumenting)
 
 dnl ========================================================
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -554,28 +554,74 @@ nsContentSink::DoProcessLinkHeader()
 }
 
 static const PRUnichar kSemiCh = PRUnichar(';');
 static const PRUnichar kCommaCh = PRUnichar(',');
 static const PRUnichar kEqualsCh = PRUnichar('=');
 static const PRUnichar kLessThanCh = PRUnichar('<');
 static const PRUnichar kGreaterThanCh = PRUnichar('>');
 
+
+// check whether the Link header field applies to the context resource
+// see <http://tools.ietf.org/html/rfc5988#section-5.2>
+
+PRBool
+nsContentSink::LinkContextIsOurDocument(const nsSubstring& aAnchor)
+{
+  if (aAnchor.IsEmpty()) {
+    // anchor parameter not present or empty -> same document reference
+    return PR_TRUE;
+  }
+
+  nsIURI* docUri = mDocument->GetDocumentURI();
+
+  // the document URI might contain a fragment identifier ("#...')
+  // we want to ignore that because it's invisible to the server
+  // and just affects the local interpretation in the recipient
+  nsCOMPtr<nsIURI> contextUri;
+  nsresult rv = docUri->CloneIgnoringRef(getter_AddRefs(contextUri));
+  
+  if (NS_FAILED(rv)) {
+    // copying failed
+    return PR_FALSE;
+  }
+  
+  // resolve anchor against context    
+  nsCOMPtr<nsIURI> resolvedUri;
+  rv = NS_NewURI(getter_AddRefs(resolvedUri), aAnchor,
+      nsnull, contextUri);
+  
+  if (NS_FAILED(rv)) {
+    // resolving failed
+    return PR_FALSE;
+  }
+
+  PRBool same;
+  rv = contextUri->Equals(resolvedUri, &same); 
+  if (NS_FAILED(rv)) {
+    // comparison failed
+    return PR_FALSE;
+  }
+
+  return same;
+}
+
 nsresult
 nsContentSink::ProcessLinkHeader(nsIContent* aElement,
                                  const nsAString& aLinkData)
 {
   nsresult rv = NS_OK;
 
   // parse link content and call process style link
   nsAutoString href;
   nsAutoString rel;
   nsAutoString title;
   nsAutoString type;
   nsAutoString media;
+  nsAutoString anchor;
 
   // copy to work buffer
   nsAutoString stringList(aLinkData);
 
   // put an extra null at the end
   stringList.Append(kNullCh);
 
   PRUnichar* start = stringList.BeginWriting();
@@ -694,58 +740,72 @@ nsContentSink::ProcessLinkHeader(nsICont
             }
           } else if (attr.LowerCaseEqualsLiteral("media")) {
             if (media.IsEmpty()) {
               media = value;
 
               // HTML4.0 spec is inconsistent, make it case INSENSITIVE
               ToLowerCase(media);
             }
+          } else if (attr.LowerCaseEqualsLiteral("anchor")) {
+            if (anchor.IsEmpty()) {
+              anchor = value;
+              anchor.StripWhitespace();
+            }
           }
         }
       }
     }
 
     if (endCh == kCommaCh) {
       // hit a comma, process what we've got so far
 
       href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
       if (!href.IsEmpty() && !rel.IsEmpty()) {
-        rv = ProcessLink(aElement, href, rel, title, type, media);
+        rv = ProcessLink(aElement, anchor, href, rel, title, type, media);
       }
 
       href.Truncate();
       rel.Truncate();
       title.Truncate();
       type.Truncate();
       media.Truncate();
+      anchor.Truncate();
     }
 
     start = ++end;
   }
-
+                
   href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
   if (!href.IsEmpty() && !rel.IsEmpty()) {
-    rv = ProcessLink(aElement, href, rel, title, type, media);
+    rv = ProcessLink(aElement, anchor, href, rel, title, type, media);
   }
 
   return rv;
 }
 
 
 nsresult
 nsContentSink::ProcessLink(nsIContent* aElement,
-                           const nsSubstring& aHref, const nsSubstring& aRel,
-                           const nsSubstring& aTitle, const nsSubstring& aType,
-                           const nsSubstring& aMedia)
+                           const nsSubstring& aAnchor, const nsSubstring& aHref,
+                           const nsSubstring& aRel, const nsSubstring& aTitle,
+                           const nsSubstring& aType, const nsSubstring& aMedia)
 {
   // XXX seems overkill to generate this string array
   nsTArray<nsString> linkTypes;
   nsStyleLinkElement::ParseLinkTypes(aRel, linkTypes);
 
+  // The link relation may apply to a different resource, specified
+  // in the anchor parameter. For the link relations supported so far,
+  // we simply abort if the link applies to a resource different to the
+  // one we've loaded
+  if (!LinkContextIsOurDocument(aAnchor)) {
+    return NS_OK;
+  }
+  
   PRBool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch"));
   // prefetch href if relation is "next" or "prefetch"
   if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) {
     PrefetchHref(aHref, aElement, hasPrefetch);
   }
 
   if ((!aHref.IsEmpty()) && linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) {
     PrefetchDNS(aHref);
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -146,16 +146,17 @@ class nsContentSink : public nsICSSLoade
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
   NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
 
   virtual void UpdateChildCounts() = 0;
 
   PRBool IsTimeToNotify();
+  PRBool LinkContextIsOurDocument(const nsSubstring& aAnchor);
 
   static void InitializeStatics();
 
 protected:
   nsContentSink();
   virtual ~nsContentSink();
 
   enum CacheSelectionAction {
@@ -183,19 +184,20 @@ protected:
   nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
                 nsISupports* aContainer, nsIChannel* aChannel);
 
   nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
   nsresult ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
                              nsIContent* aContent = nsnull);
   nsresult ProcessLinkHeader(nsIContent* aElement,
                              const nsAString& aLinkData);
-  nsresult ProcessLink(nsIContent* aElement, const nsSubstring& aHref,
-                       const nsSubstring& aRel, const nsSubstring& aTitle,
-                       const nsSubstring& aType, const nsSubstring& aMedia);
+  nsresult ProcessLink(nsIContent* aElement, const nsSubstring& aAnchor,
+                       const nsSubstring& aHref, const nsSubstring& aRel,
+                       const nsSubstring& aTitle, const nsSubstring& aType,
+                       const nsSubstring& aMedia);
 
   virtual nsresult ProcessStyleLink(nsIContent* aElement,
                                     const nsSubstring& aHref,
                                     PRBool aAlternate,
                                     const nsSubstring& aTitle,
                                     const nsSubstring& aType,
                                     const nsSubstring& aMedia);
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1717,17 +1717,16 @@ GK_ATOM(bcTableCellFrame, "BCTableCellFr
 GK_ATOM(blockFrame, "BlockFrame")
 GK_ATOM(boxFrame, "BoxFrame")
 GK_ATOM(brFrame, "BRFrame")
 GK_ATOM(bulletFrame, "BulletFrame")
 GK_ATOM(columnSetFrame, "ColumnSetFrame")
 GK_ATOM(comboboxControlFrame, "ComboboxControlFrame")
 GK_ATOM(comboboxDisplayFrame, "ComboboxDisplayFrame")
 GK_ATOM(deckFrame, "DeckFrame")
-GK_ATOM(directionalFrame, "DirectionalFrame")
 GK_ATOM(fieldSetFrame, "FieldSetFrame")
 GK_ATOM(frameSetFrame, "FrameSetFrame")
 GK_ATOM(gfxButtonControlFrame, "gfxButtonControlFrame")
 GK_ATOM(HTMLButtonControlFrame, "HTMLButtonControlFrame")
 GK_ATOM(HTMLCanvasFrame, "HTMLCanvasFrame")
 GK_ATOM(subDocumentFrame, "subDocumentFrame")
 GK_ATOM(imageBoxFrame, "ImageBoxFrame")
 GK_ATOM(imageFrame, "ImageFrame")
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -290,17 +290,16 @@ nsInProcessTabChildGlobal::InitTabChildG
   NS_ENSURE_STATE(cx);
 
   mCx = cx;
 
   nsContentUtils::XPConnect()->SetSecurityManagerForJSContext(cx, nsContentUtils::GetSecurityManager(), 0);
   nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
 
   JS_SetNativeStackQuota(cx, 128 * sizeof(size_t) * 1024);
-  JS_SetScriptStackQuota(cx, 25 * sizeof(size_t) * 1024 * 1024);
 
   JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_ANONFUNFIX | JSOPTION_PRIVATE_IS_NSISUPPORTS);
   JS_SetVersion(cx, JSVERSION_LATEST);
   JS_SetErrorReporter(cx, ContentScriptErrorReporter);
 
   xpc_LocalizeContext(cx);
 
   JSAutoRequest ar(cx);
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -309,16 +309,17 @@ nsWebSocketEstablishedConnection::Init(n
 
 nsresult
 nsWebSocketEstablishedConnection::PrintErrorOnConsole(const char *aBundleURI,
                                                       const PRUnichar *aError,
                                                       const PRUnichar **aFormatStrings,
                                                       PRUint32 aFormatStringsLen)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(mOwner, "No owner");
 
   nsresult rv;
 
   nsCOMPtr<nsIStringBundleService> bundleService =
     do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStringBundle> strBundle;
@@ -360,16 +361,18 @@ nsWebSocketEstablishedConnection::PrintE
   return NS_OK;
 }
 
 // when this is called the browser side wants no more part of it
 nsresult
 nsWebSocketEstablishedConnection::Close()
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  if (!mOwner)
+    return NS_OK;
 
   // Disconnect() can release this object, so we keep a
   // reference until the end of the method
   nsRefPtr<nsWebSocketEstablishedConnection> kungfuDeathGrip = this;
 
   if (mOwner->mReadyState == nsIWebSocket::CONNECTING) {
     mOwner->SetReadyState(nsIWebSocket::CLOSING);
     mOwner->SetReadyState(nsIWebSocket::CLOSED);
@@ -453,16 +456,18 @@ nsWebSocketEstablishedConnection::Discon
   nsLayoutStatics::Release();
   return NS_OK;
 }
 
 nsresult
 nsWebSocketEstablishedConnection::UpdateMustKeepAlive()
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  NS_ABORT_IF_FALSE(mOwner, "No owner");
+
   mOwner->UpdateMustKeepAlive();
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsWebSocketEstablishedConnection::nsIWebSocketListener methods:
 //-----------------------------------------------------------------------------
 
@@ -567,16 +572,19 @@ nsWebSocketEstablishedConnection::OnServ
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsWebSocketEstablishedConnection::GetInterface(const nsIID &aIID,
                                                void **aResult)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
+  if (!mOwner)
+    return NS_ERROR_FAILURE;
+
   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
       aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
     nsresult rv;
 
     nsCOMPtr<nsIDocument> doc =
       nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext);
 
     if (!doc) {
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -84,29 +84,27 @@ include $(topsrcdir)/config/rules.mk
 		test_bug330925.xhtml \
 		test_bug331959.html \
 		test_bug333673.html \
 		test_bug337631.html \
 		test_bug338541.xhtml \
 		test_bug338679.html \
 		test_bug339494.html \
 		test_bug339494.xhtml \
-		test_bug339494.xul \
 		test_bug340571.html \
 		test_bug343596.html \
 		test_bug345339.html \
 		345339_iframe.html \
 		test_bug352728.html \
 		test_bug352728.xhtml \
 		test_bug353334.html \
 		test_bug355026.html \
 		test_bug357450.js \
 		test_bug357450.html \
 		test_bug357450.xhtml \
-		test_bug357450.xul \
 		test_bug357450_svg.xhtml \
 		test_bug357509.html \
 		test_bug358660.html \
 		test_bug362391.xhtml \
 		test_bug364092.xhtml \
 		test_bug364413.xhtml \
 		test_bug366946.html \
 		test_bug367164.html \
@@ -407,17 +405,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug560780.html \
 		test_bug562652.html \
 		test_bug562137.html \
 		file_bug562137.txt \
 		test_bug548193.html \
 		file_bug548193.sjs \
 		test_html_colors_quirks.html \
 		test_html_colors_standards.html \
-		test_bug571390.xul \
 		test_bug300992.html \
 		test_websocket_hello.html \
 		file_websocket_hello_wsh.py \
 		test_ws_basic_tests.html \
 		file_ws_basic_tests_wsh.py \
 		test_websocket.html \
 		file_websocket_wsh.py \
 		file_websocket_http_resource.txt \
@@ -499,16 +496,20 @@ include $(topsrcdir)/config/rules.mk
 		accesscontrol.resource^headers^ \
 		invalid_accesscontrol.resource \
 		invalid_accesscontrol.resource^headers^ \
 		somedatas.resource \
 		somedatas.resource^headers^ \
 		delayedServerEvents.sjs \
 		$(NULL)
 
+_CHROME_FILES =	\
+		test_bug357450.js \
+		$(NULL)
+
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
 _TEST_FILES2 += 	test_copyimage.html \
 		$(NULL)
 endif
 
 # Disabled for now. Mochitest isn't reliable enough for these.
 # test_bug444546.html \
@@ -525,8 +526,12 @@ endif
 libs:: $(_TEST_FILES1)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_TEST_FILES2)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
+
+libs:: $(_CHROME_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
+
--- a/content/base/test/browser_bug593387.js
+++ b/content/base/test/browser_bug593387.js
@@ -22,16 +22,18 @@ function test() {
 function testXFOFrameInChrome() {
   newBrowser.removeEventListener("load", testXFOFrameInChrome, true);
 
   // Insert an iframe that specifies "X-Frame-Options: DENY" and verify
   // that it loads, since the top context is chrome
   var frame = newBrowser.contentDocument.createElement("iframe");
   frame.src = "http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny";
   frame.addEventListener("load", function() {
+    frame.removeEventListener("load", arguments.callee, true);
+
     // Test that the frame loaded
     var test = this.contentDocument.getElementById("test");
     is(test.tagName, "H1", "wrong element type");
     is(test.textContent, "deny", "wrong textContent");
     
     // Run next test (try the same with a content top-level context)
     newBrowser.addEventListener("load", testXFOFrameInContent, true);
     newBrowser.contentWindow.location = "http://example.com/";  
@@ -43,16 +45,18 @@ function testXFOFrameInChrome() {
 function testXFOFrameInContent() {
   newBrowser.removeEventListener("load", testXFOFrameInContent, true);
 
   // Insert an iframe that specifies "X-Frame-Options: DENY" and verify that it
   // is blocked from loading since the top browsing context is another site
   var frame = newBrowser.contentDocument.createElement("iframe");
   frame.src = "http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny";
   frame.addEventListener("load", function() {
+    frame.removeEventListener("load", arguments.callee, true);
+
     // Test that the frame DID NOT load
     var test = this.contentDocument.getElementById("test");
     is(test, undefined, "should be about:blank");
 
     // Finalize the test
     gBrowser.removeCurrentTab();
     finish();
   }, true);
--- a/content/base/test/chrome/Makefile.in
+++ b/content/base/test/chrome/Makefile.in
@@ -57,15 +57,18 @@ include $(topsrcdir)/config/rules.mk
     title_window.xul \
     test_bug549682.xul \
     file_bug549682.xul \
     test_bug616841.xul \
     file_bug616841.xul \
     test_bug635835.xul \
     test_fileconstructor.xul \
     fileconstructor_file.png \
+    test_bug339494.xul \
+    test_bug357450.xul \
+    test_bug571390.xul \
     $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_CHROME_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
rename from content/base/test/test_bug339494.xul
rename to content/base/test/chrome/test_bug339494.xul
--- a/content/base/test/test_bug339494.xul
+++ b/content/base/test/chrome/test_bug339494.xul
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=339494
 -->
 <window title="Mozilla Bug 339494"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Test for Bug 339494</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="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">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=339494">Mozilla Bug 339494</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   <xul:hbox id="d"/>
   <xul:hbox id="s"/>
 </div>
rename from content/base/test/test_bug357450.xul
rename to content/base/test/chrome/test_bug357450.xul
--- a/content/base/test/test_bug357450.xul
+++ b/content/base/test/chrome/test_bug357450.xul
@@ -1,24 +1,24 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=357450
 -->
 
 <window title="Mozilla Bug 357450"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Test for Bug 357450</title>
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript" 
-	  src="/tests/SimpleTest/SimpleTest.js"></script>      
+	  src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
   <script type="text/javascript" src="test_bug357450.js"></script>     
 
 <body  xmlns="http://www.w3.org/1999/xhtml">
 
 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=357450"
    target="_blank">Mozilla Bug 357450</a>
 
 <p id="display"></p>
rename from content/base/test/test_bug571390.xul
rename to content/base/test/chrome/test_bug571390.xul
--- a/content/base/test/test_bug571390.xul
+++ b/content/base/test/chrome/test_bug571390.xul
@@ -1,19 +1,19 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=571390
 -->
 <window title="Mozilla Bug 571390"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         class="foo bar">
-  <script type="application/javascript" src="/MochiKit/packed.js"/>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=571390"
      target="_blank">Mozilla Bug 571390</a>
   </body>
 
   <!-- test code goes here -->
--- a/content/canvas/src/CanvasImageCache.cpp
+++ b/content/canvas/src/CanvasImageCache.cpp
@@ -128,25 +128,33 @@ public:
     mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
   }
 
   nsTHashtable<ImageCacheEntry> mCache;
 };
 
 static ImageCache* gImageCache = nsnull;
 
+class CanvasImageCacheShutdownObserver : public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+};
+
 void
 CanvasImageCache::NotifyDrawImage(nsIDOMElement* aImage,
                                   nsHTMLCanvasElement* aCanvas,
                                   imgIRequest* aRequest,
                                   gfxASurface* aSurface,
                                   const gfxIntSize& aSize)
 {
   if (!gImageCache) {
     gImageCache = new ImageCache();
+    nsContentUtils::RegisterShutdownObserver(new CanvasImageCacheShutdownObserver());
   }
 
   ImageCacheEntry* entry = gImageCache->mCache.PutEntry(ImageCacheKey(aImage, aCanvas));
   if (entry) {
     if (entry->mData->mSurface) {
       // We are overwriting an existing entry.
       gImageCache->RemoveObject(entry->mData);
     }
@@ -181,16 +189,26 @@ CanvasImageCache::Lookup(nsIDOMElement* 
     return nsnull;
 
   gImageCache->MarkUsed(entry->mData);
 
   *aSize = entry->mData->mSize;
   return entry->mData->mSurface;
 }
 
-void
-CanvasImageCache::Shutdown()
+NS_IMPL_ISUPPORTS1(CanvasImageCacheShutdownObserver, nsIObserver)
+
+NS_IMETHODIMP
+CanvasImageCacheShutdownObserver::Observe(nsISupports *aSubject,
+                                          const char *aTopic,
+                                          const PRUnichar *aData)
 {
-  delete gImageCache;
-  gImageCache = nsnull;
+  if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+    delete gImageCache;
+    gImageCache = nsnull;
+
+    nsContentUtils::UnregisterShutdownObserver(this);
+  }
+
+  return NS_OK;
 }
 
 }
--- a/content/canvas/src/CanvasImageCache.h
+++ b/content/canvas/src/CanvasImageCache.h
@@ -64,15 +64,13 @@ public:
    * Check whether aImage has recently been drawn into aCanvas. If we return
    * a non-null surface, then the image was recently drawn into the canvas
    * (with the same image request) and the returned surface contains the image
    * data, and the image size will be returned in aSize.
    */
   static gfxASurface* Lookup(nsIDOMElement* aImage,
                              nsHTMLCanvasElement* aCanvas,
                              gfxIntSize* aSize);
-
-  static void Shutdown();
 };
 
 }
 
 #endif /* CANVASIMAGECACHE_H_ */
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -292,19 +292,16 @@ WebGLContext::GetCanvas(nsIDOMHTMLCanvas
 
 //
 // nsICanvasRenderingContextInternal
 //
 
 NS_IMETHODIMP
 WebGLContext::SetCanvasElement(nsHTMLCanvasElement* aParentCanvas)
 {
-    if (aParentCanvas && !SafeToCreateCanvas3DContext(aParentCanvas))
-        return NS_ERROR_FAILURE;
-
     mCanvasElement = aParentCanvas;
 
     return NS_OK;
 }
 
 static bool
 GetBoolFromPropertyBag(nsIPropertyBag *bag, const char *propName, bool *boolResult)
 {
@@ -359,16 +356,18 @@ WebGLContext::SetContextOptions(nsIPrope
 
     mOptions = newOpts;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
 {
+    /*** early success return cases ***/
+  
     if (mCanvasElement) {
         HTMLCanvasElement()->InvalidateCanvas();
     }
 
     if (gl && mWidth == width && mHeight == height)
         return NS_OK;
 
     // Zero-sized surfaces can cause problems.
@@ -384,33 +383,58 @@ WebGLContext::SetDimensions(PRInt32 widt
     {
         // everything's good, we're done here
         mWidth = width;
         mHeight = height;
         mResetLayer = PR_TRUE;
         return NS_OK;
     }
 
+    /*** end of early success return cases ***/
+
     ScopedGfxFeatureReporter reporter("WebGL");
 
+    // At this point we know that the old context is not going to survive, even though we still don't
+    // know if creating the new context will succeed.
+    DestroyResourcesAndContext();
+
+    // Get some prefs for some preferred/overriden things
+    nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
+    NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
+
+    PRBool forceOSMesa = PR_FALSE;
+    PRBool preferEGL = PR_FALSE;
+    PRBool preferOpenGL = PR_FALSE;
+    PRBool forceEnabled = PR_FALSE;
+    PRBool disabled = PR_FALSE;
+    PRBool verbose = PR_FALSE;
+
+    prefService->GetBoolPref("webgl.force_osmesa", &forceOSMesa);
+    prefService->GetBoolPref("webgl.prefer-egl", &preferEGL);
+    prefService->GetBoolPref("webgl.prefer-native-gl", &preferOpenGL);
+    prefService->GetBoolPref("webgl.force-enabled", &forceEnabled);
+    prefService->GetBoolPref("webgl.disabled", &disabled);
+    prefService->GetBoolPref("webgl.verbose", &verbose);
+
+    if (disabled)
+        return NS_ERROR_FAILURE;
+
+    mVerbose = verbose;
+
     // We're going to create an entirely new context.  If our
     // generation is not 0 right now (that is, if this isn't the first
     // context we're creating), we may have to dispatch a context lost
     // event.
 
     // If incrementing the generation would cause overflow,
     // don't allow it.  Allowing this would allow us to use
     // resource handles created from older context generations.
     if (!(mGeneration+1).valid())
         return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
 
-    // We're going to recreate our context, so make sure we clean up
-    // after ourselves.
-    DestroyResourcesAndContext();
-
     gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);
     if (mOptions.depth) {
         format.depth = 24;
         format.minDepth = 16;
     }
 
     if (mOptions.stencil) {
         format.stencil = 8;
@@ -423,32 +447,16 @@ WebGLContext::SetDimensions(PRInt32 widt
         format.red = 5;
         format.green = 6;
         format.blue = 5;
 
         format.alpha = 0;
         format.minAlpha = 0;
     }
 
-    nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
-    NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
-
-    PRBool verbose = PR_FALSE;
-    prefService->GetBoolPref("webgl.verbose", &verbose);
-    mVerbose = verbose;
-
-    // Get some prefs for some preferred/overriden things
-    PRBool forceOSMesa = PR_FALSE;
-    PRBool preferEGL = PR_FALSE;
-    PRBool preferOpenGL = PR_FALSE;
-    PRBool forceEnabled = PR_FALSE;
-    prefService->GetBoolPref("webgl.force_osmesa", &forceOSMesa);
-    prefService->GetBoolPref("webgl.prefer-egl", &preferEGL);
-    prefService->GetBoolPref("webgl.prefer-native-gl", &preferOpenGL);
-    prefService->GetBoolPref("webgl.force-enabled", &forceEnabled);
     if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) {
         preferEGL = PR_TRUE;
     }
 
     // Ask GfxInfo about what we should use
     PRBool useOpenGL = PR_TRUE;
     PRBool useANGLE = PR_TRUE;
 
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -443,17 +443,16 @@ protected:
         WebGLExtensionID_Max
     };
     nsCOMPtr<nsIWebGLExtension> mEnabledExtensions[WebGLExtensionID_Max];
     PRBool IsExtensionEnabled(WebGLExtensionID ext) const {
         NS_ABORT_IF_FALSE(ext >= 0 && ext < WebGLExtensionID_Max, "bogus index!");
         return mEnabledExtensions[ext] != nsnull;
     }
 
-    PRBool SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement);
     PRBool InitAndValidateGL();
     PRBool ValidateBuffers(PRInt32* maxAllowedCount, const char *info);
     PRBool ValidateCapabilityEnum(WebGLenum cap, const char *info);
     PRBool ValidateBlendEquationEnum(WebGLenum cap, const char *info);
     PRBool ValidateBlendFuncDstEnum(WebGLenum mode, const char *info);
     PRBool ValidateBlendFuncSrcEnum(WebGLenum mode, const char *info);
     PRBool ValidateBlendFuncEnumsCompatibility(WebGLenum sfactor, WebGLenum dfactor, const char *info);
     PRBool ValidateTextureTargetEnum(WebGLenum target, const char *info);
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3476,24 +3476,61 @@ WebGLContext::DOMElementToImageSurface(n
         flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
     if (!mPixelStorePremultiplyAlpha)
         flags |= nsLayoutUtils::SFE_NO_PREMULTIPLY_ALPHA;
 
     nsLayoutUtils::SurfaceFromElementResult res =
         nsLayoutUtils::SurfaceFromElement(imageOrCanvas, flags);
     if (!res.mSurface)
         return NS_ERROR_FAILURE;
-
-    CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(), res.mPrincipal, res.mIsWriteOnly);
-
     if (res.mSurface->GetType() != gfxASurface::SurfaceTypeImage) {
         // SurfaceFromElement lied!
         return NS_ERROR_FAILURE;
     }
 
+    // Bug 656277 - Prevent loading WebGL textures from cross-domain images
+    //
+    // We disallow loading cross-domain images as WebGL textures. The reason for doing that
+    // is that timing attacks on WebGL shaders are able to retrieve approximations of the pixel values
+    // in WebGL textures, see bug 655987.
+    //
+    // To prevent a loophole where a Canvas2D would be used as a proxy to load cross-domain textures,
+    // we also disallow loading textures from write-only Canvas2D's.
+
+    // part 1: check that the DOM element is same-origin.
+    // if res.mPrincipal == null, no need for the origin check. See DoDrawImageSecurityCheck.
+    // this case happens in the mochitest for images served from mochi.test:8888
+    if (res.mPrincipal) {
+        PRBool subsumes;
+        nsresult rv = HTMLCanvasElement()->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
+        if (NS_FAILED(rv) || !subsumes) {
+            LogMessageIfVerbose("It is forbidden to load a WebGL texture from a cross-domain element. "
+                                "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
+            return NS_ERROR_DOM_SECURITY_ERR;
+        }
+    }
+
+    // part 2: if the DOM element is a canvas, check that it's not write-only. That would indicate a tainted canvas,
+    // i.e. a canvas that could contain cross-domain image data.
+    nsCOMPtr<nsIContent> maybeDOMCanvas = do_QueryInterface(imageOrCanvas);
+    if (maybeDOMCanvas && maybeDOMCanvas->IsHTML(nsGkAtoms::canvas)) {
+        nsHTMLCanvasElement *canvas = static_cast<nsHTMLCanvasElement*>(maybeDOMCanvas.get());
+        if (canvas->IsWriteOnly()) {
+            LogMessageIfVerbose("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden "
+                                "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example "
+                                "when a cross-domain image is drawn on it. "
+                                "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
+            return NS_ERROR_DOM_SECURITY_ERR;
+        }
+    }
+
+    // End of security checks, now we should be safe regarding cross-domain images
+    // Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
+    // texture sources in the first place.
+
     surf = static_cast<gfxImageSurface*>(res.mSurface.get());
 
     res.mSurface.forget();
     *imageOut = surf;
 
     switch (surf->Format()) {
         case gfxASurface::ImageFormatARGB32:
             *format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -62,148 +62,16 @@
 
 #if 0
 #include "nsIContentURIGrouper.h"
 #include "nsIContentPrefService.h"
 #endif
 
 using namespace mozilla;
 
-PRBool
-WebGLContext::SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement)
-{
-    nsresult rv;
-
-    // first see if we're a chrome context
-    PRBool is_caller_chrome = PR_FALSE;
-    nsCOMPtr<nsIScriptSecurityManager> ssm =
-        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    rv = ssm->SubjectPrincipalIsSystem(&is_caller_chrome);
-    if (NS_SUCCEEDED(rv) && is_caller_chrome)
-        return PR_TRUE;
-
-    // not chrome? check pref.
-
-    // first check our global pref
-    nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    PRBool disabled = PR_FALSE;
-    rv = prefService->GetBoolPref("webgl.disabled", &disabled);
-    if (NS_SUCCEEDED(rv) && !disabled) {
-        // the all-sites pref was set, we're good to go
-        return PR_TRUE;
-    }
-
-#if 0
-    // otherwise we'll check content prefs
-    nsCOMPtr<nsIContentPrefService> cpsvc = do_GetService("@mozilla.org/content-pref/service;1", &rv);
-    if (NS_FAILED(rv)) {
-        LogMessage("Canvas 3D: Failed to get Content Pref service, can't verify that canvas3d is ok for this site!");
-        return PR_FALSE;
-    }
-
-    // grab our content URI
-    nsCOMPtr<nsIURI> contentURI;
-
-    nsCOMPtr<nsIPrincipal> principal;
-    rv = ssm->GetSubjectPrincipal(getter_AddRefs(principal));
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    if (!principal) {
-        // seriously? no script executing, but not the system principal?
-        return PR_FALSE;
-    }
-    rv = principal->GetURI(getter_AddRefs(contentURI));
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    // our pref is 'webgl.enabled'
-    nsCOMPtr<nsIVariant> val;
-    rv = cpsvc->GetPref(contentURI, NS_LITERAL_STRING("webgl.enabled"), getter_AddRefs(val));
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    PRInt32 iv;
-    rv = val->GetAsInt32(&iv);
-    if (NS_SUCCEEDED(rv)) {
-        // 1 means "yes, allowed"
-        if (iv == 1)
-            return PR_TRUE;
-
-        // -1 means "no, don't ask me again"
-        if (iv == -1)
-            return PR_FALSE;
-
-        // otherwise, we'll throw an event and maybe ask the user
-    }
-
-    // grab the document that we can use to create the event
-    nsCOMPtr<nsIDOMNode> node = do_QueryInterface(canvasElement);
-    nsCOMPtr<nsIDOMDocument> domDoc;
-    rv = node->GetOwnerDocument(getter_AddRefs(domDoc));
-
-    /*
-    // figure out where to throw the event.  we just go for the outermost
-    // document.  ideally, I want to throw the event to the <browser> if one exists,
-    // otherwise the topmost document, but that's more work than I want to deal with.
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
-    while (doc->GetParentDocument())
-        doc = doc->GetParentDocument();
-    */
-
-    // set up the event
-    nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(domDoc);
-    NS_ENSURE_TRUE(docEvent, PR_FALSE);
-
-    nsCOMPtr<nsIDOMEvent> eventBase;
-    rv = docEvent->CreateEvent(NS_LITERAL_STRING("DataContainerEvent"), getter_AddRefs(eventBase));
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    rv = eventBase->InitEvent(NS_LITERAL_STRING("Canvas3DContextRequest"), PR_TRUE, PR_TRUE);
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    nsCOMPtr<nsIDOMDataContainerEvent> event = do_QueryInterface(eventBase);
-    nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(eventBase);
-    NS_ENSURE_TRUE(event && privateEvent, PR_FALSE);
-
-    // mark it as trusted, so that it'll bubble upwards into chrome
-    privateEvent->SetTrusted(PR_TRUE);
-
-    // set some extra data on the event
-    nsCOMPtr<nsIContentURIGrouper> grouper = do_GetService("@mozilla.org/content-pref/hostname-grouper;1", &rv);
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    nsAutoString group;
-    rv = grouper->Group(contentURI, group);
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    nsCOMPtr<nsIWritableVariant> groupVariant = do_CreateInstance(NS_VARIANT_CONTRACTID);
-    nsCOMPtr<nsIWritableVariant> uriVariant = do_CreateInstance(NS_VARIANT_CONTRACTID);
-
-    groupVariant->SetAsAString(group);
-    uriVariant->SetAsISupports(contentURI);
-
-    rv = event->SetData(NS_LITERAL_STRING("group"), groupVariant);
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    rv = event->SetData(NS_LITERAL_STRING("uri"), uriVariant);
-    NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-    // our target...
-    nsCOMPtr<nsIDOMEventTarget> targ = do_QueryInterface(canvasElement);
-
-    // and go.
-    PRBool defaultActionEnabled;
-    targ->DispatchEvent(event, &defaultActionEnabled);
-#endif
-
-    return PR_FALSE;
-}
-
 void
 WebGLContext::LogMessage(const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
 
     LogMessage(fmt, ap);
 
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -1177,16 +1177,17 @@ nsCanvasRenderingContext2D::InitializeWi
     mThebes->Rectangle(gfxRect(0, 0, mWidth, mHeight));
     mThebes->Fill();
 
     mThebes->SetLineWidth(1.0);
     mThebes->SetOperator(gfxContext::OPERATOR_OVER);
     mThebes->SetMiterLimit(10.0);
     mThebes->SetLineCap(gfxContext::LINE_CAP_BUTT);
     mThebes->SetLineJoin(gfxContext::LINE_JOIN_MITER);
+    mThebes->SetFillRule(gfxContext::FILL_RULE_WINDING);
 
     mThebes->NewPath();
 
     // always force a redraw, because if the surface dimensions were reset
     // then the surface became cleared, and we need to redraw everything.
     Redraw();
 
     return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
@@ -1595,16 +1596,47 @@ nsCanvasRenderingContext2D::SetFillStyle
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetFillStyle_multi(nsAString& aStr, nsISupports **aInterface, PRInt32 *aType)
 {
     return GetStyleAsStringOrInterface(aStr, aInterface, aType, STYLE_FILL);
 }
 
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::SetMozFillRule(const nsAString& aString)
+{
+    gfxContext::FillRule rule;
+
+    if (aString.EqualsLiteral("evenodd"))
+        rule = gfxContext::FILL_RULE_EVEN_ODD;
+    else if (aString.EqualsLiteral("nonzero"))
+        rule = gfxContext::FILL_RULE_WINDING;
+    else
+        // XXX ERRMSG we need to report an error to developers here! (bug 329026)
+        return NS_OK;
+
+    mThebes->SetFillRule(rule);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::GetMozFillRule(nsAString& aString)
+{
+    switch (mThebes->CurrentFillRule()) {
+    case gfxContext::FILL_RULE_WINDING:
+        aString.AssignLiteral("nonzero"); break;
+    case gfxContext::FILL_RULE_EVEN_ODD:
+        aString.AssignLiteral("evenodd"); break;
+    default:
+        return NS_ERROR_FAILURE;
+    }
+    return NS_OK;
+}
+
 //
 // gradients and patterns
 //
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreateLinearGradient(float x0, float y0, float x1, float y1,
                                                  nsIDOMCanvasGradient **_retval)
 {
     if (!FloatValidate(x0,y0,x1,y1))
--- a/content/canvas/test/webgl/conformance/00_test_list.txt
+++ b/content/canvas/test/webgl/conformance/00_test_list.txt
@@ -59,17 +59,17 @@ is-object.html
 methods.html
 more-than-65536-points.html
 null-object-behaviour.html
 null-uniform-location.html
 object-deletion-behaviour.html
 oes-standard-derivatives.html
 oes-texture-float.html
 oes-vertex-array-object.html
-origin-clean-conformance.html
+# origin-clean-conformance.html # is obsolete because of bug 656277
 point-size.html
 program-test.html
 read-pixels-pack-alignment.html
 read-pixels-test.html
 renderbuffer-initialization.html
 resource-sharing-test.html
 tex-image-and-sub-image-2d-with-array-buffer-view.html
 tex-image-and-sub-image-2d-with-image-data.html
--- a/content/canvas/test/webgl/conformance/more/functions/readPixelsBadArgs.html
+++ b/content/canvas/test/webgl/conformance/more/functions/readPixelsBadArgs.html
@@ -70,16 +70,18 @@ Tests.testReadPixels = function(gl) {
           new Uint8Array(4*4));});
   // we can't know if this is going to fail because of negative width
   // or because the buffer size doesn't match the dimensions.
   assertSomeGLError(gl, "bad type",
       function(){gl.readPixels(0,0,1,1, gl.ALPHA, gl.FLOAT,
           new Uint8Array(1*4));});
 }
 
+/* this part is obsolete because of bug 656277
+ *
 Tests.testReadPixelsSOPIMG = function(gl) {
     var img = document.getElementById("i");
     while (!img.complete) {}
     var tex = gl.createTexture();
     gl.bindTexture(gl.TEXTURE_2D, tex);
     gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
     gl.bindTexture(gl.TEXTURE_2D, null);
     // SOP failure
@@ -100,16 +102,17 @@ Tests.testReadPixelsSOPCanvas = function
     gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
     gl.bindTexture(gl.TEXTURE_2D, null);
     // SOP failure
     assertThrowNoGLError(gl, "throw because canvas is not origin clean",
       function(){gl.readPixels(0,0,1,1, gl.RGBA, gl.UNSIGNED_BYTE,
           new Uint8Array(4));});
     gl.deleteTexture(tex);
 }
+*/
 
 Tests.endUnit = function(gl) {
 }
 
 </script>
 </head><body>
 <canvas id="gl" width="16" height="16"></canvas>
 <canvas id="c" width="128" height="128"></canvas>
--- a/content/canvas/test/webgl/conformance/more/functions/texImage2DHTML.html
+++ b/content/canvas/test/webgl/conformance/more/functions/texImage2DHTML.html
@@ -141,11 +141,11 @@ void main()
     vec4 c = texture2D(Texture, texCoord0.st);
     gl_FragColor = c;
 }
 </script>
 </head><body>
 <canvas id="gl" width="256" height="256"></canvas>
 <canvas id="c" width="256" height="256"></canvas>
 <img id="i" width="256" height="256"  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAATVElEQVR4nO3d+VPUd57Hcf2b9k9Y+z44+qK7OZoGFVA5VfBGzah9cxpNzGEOoRua5lBEue/DK4fZ7MapmSm3Mlshu8xOdCpDJt3v/aEBAUHAOMG4z0fV53fqU/V6fd7fT/e32bEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwOvBkar7l+3+GwBsk8xUrT0rTb8vx2Q45janlu7YsWPnsgXgTeYwak85U3Xv5ZiM3+XbUh/l2dICBc6080WZ1ur92baSHRQB8GayGdUWu1HzoSNFO+ZM1f2cbTLM51lT5woc5rkDObbZ/Vm2SEm23VvsyjhV5nJQBsCbxGZQVtmN6p4Mo/YPdqNGHKlayUrXJ9zWlESh0xIvzsmYL3HZ54pzMm6VuRyRMpfTW+pyUAbAm8BmVNVnGNTTdqP6vzOMGrGnaMSZqpNsk17ybKlS6DTL/ixbotRlj5flOubL3I65MpfjVrnbEalYKINSl335vQGA3wKbUW2xGdWRDKP66wyjWhYLwJGiFWeaTrJNBnFbU2SP3ST7s6xSmmuXcrczUe52xstzHfPlbsdcudt5qyzX3lKWlxkszXGeK8mxnyzJySjeQRkArzebQVllM6p7bUb149UF4EjVSmaaTrLS9eKypMgee7ocyLZJmdshFXmZUpHnXFEGB/OzJsrdjqEyt/NmWa49XJbt9Ja6Mk4Vu7hEBF5LNr2q3mZQz9gM6u9XFEBqsgCcaTrJXJgEci0pstdhkv3ZNinNTZbAofwsOZSfJQfzMqU8z5kodzsSZbmOeIXb+XW52zFa5nLcKnPZI2ULl4jFfKIAvB7MOrXFZlBHbAb11zaj+kmGUbNuAWSm65dKYHdGmhRlWqQ8zyFHCnLk+L5cOV6UK0cKXVK5J1sO5mdKhdspZavKoDTX0VPiciTLIHtFGVAIwK/NYlBW2fTqXptB/dhmSJ7+LyqArHS95JiTJVDgNEllQZZ4KgulrrpU6qtLJXBsv5wt3yMn9rvlaIFLDi8vg1xH4mB+5p+Wl0Fpjr2lJMcRLM6ynyvOzjhxIIt7A+BXY9Gr6q0L4/9SAaRoxL7w/L9WAWSbDJJrTZFid4Z4jxZJU/1xufHhOem+ek6il0/LB74qaTxTJoGj++Vs2R45vj9XjhTkyOHdC48JC2VwaHfmnyrczn+vcDsmynLtQyU5GTeLczLCpTk2T3GW7VhxVsae7d4f4I1l1qktVoM6YjOovrYa1D8sFoB9WQE415kA8u1pcvRAjnwUOiLDLQG5190o9242ylRHnQyG/XLz6nmJXqqWD3yV0nC6VPxH98nZst1yfF+uHC10SdXebDmUnyyDqoLs7w7lZ35b7nb8scxt/7dSl32kJCejqyQn40pJTkbZDiYC4NWzaJVVVr2q12ZQPbYa1H9fuwB0SwWQla6XLFOyAAoyTfLW4T3SfuWM3L3RIA/7L8vD/svyZe8l+ezW23Kvu1EmO2ploNkn3VfPSevb1fK+t1Iaz5RJ7cli8R0pktOl+XKsKFkGBxfKoHJv1l8P5mf+uSLP8fvyXMdMmdsRKXc5qotdGQXbvV/AG8WiV9Vb9aoZq141azOoxWbcXAHkWlOkJC9Dak8Xy61PL8iDnotLBbBUBH2X5Yvbl+RBz0W5e6NBJtprpL/ZJzc/Oi/XP3hLWi6ekvc8h6WuukS8Vc/KYPEC8WhhzpOqguzvKvdmfXV4d2b3wfzM9w/lZTENAK+CWaewWHWqiE2v+tqqV/2w2QLINhkkP2Nh/K89ImNtIfmi99Kz8Pcl15dL65J80XtJPr/1tty/2Sh3uxvkzvV6GY+FpO+aV65/8DuJXDwpVzyHpO7UQhmU5MvRIpdU7c2RQ7uz5MR+9x+OFbnuHi3MiVQVuKoP784u2u79A37TLFpllVWn6rXqVY+tetWPGxbAsgvAvU6TvHVot8SunJY7N+rly761g/9lb3J9sWx9fvuSfH77bXnQc1HudTfITFedjLWFpPeaR7o+eEvCjSflyoVDUlddKsHjB+TC4UI5VZwnVQU5ibcq9nx1ujS/58QB99XqYnf5DqYB4OVYdM/Gf6te9Y/k8//GBeCyGKXEnSE11Qek55Pzcv9m48rQrxP8L25fki9uvy2fr1qf3bqYnAxuNMh0Z52MRINy+1OPXP/wd9J+5Yw015+Qd84flJqTxXLhcIGcLM77+UhBzt8uVBa2nqvce/ZsxZ6y7d5L4Ddlcfy36FVfW/SqH6wGlawugMWvATvTlhWAySB5GalydH+OfFRzREajQfn81tvrh/6FwV9cF+WzWxflwa2Lcr/notzrbpSZ6/Uy1VUnkx21MtwSkJ5PLkjHe2elqf64XD53UEInDiQuHC6Yry7Omz1W5HrY+FbF4R1MA8DmWLTKKsuy8d9qUL+wAJZ/C3CPM13OHtwtbe+elunr9fLFusF/PvSf31o7+A96nq37PRflfk+j3L+Z/Fjx7o0Gme6qk4n2Ghlq8UvPx+el/coZuVZ3XC6fq/i57lTx32pOHngUOlUc/jR4lEtCYCMWnareolfNWPSqWatB9dOaBbDGl4BcFqMUu20SOnVAbn58Tu52N27qtP98g9A/WAz9QvAX173FEuhukLvdDcnJoLNWxmM1Mhjxy82Pzknn+2cSsXdPz4cbT8x+GKh8+FHwSO0OSgBYm1mnsJh1qohFr1wY/5XxZwWw/teAs9KTvwtwZH+2XA1VyXBrUB70XFz/tF9nzN9K8O91N8i9hfAvrjs3GuTOjXqZXnhEGG+vkdFoUAbD/p97Pj7/t56r57/pu+b5pOXd6qPbvdfAa8ei3VVl0al6LXrlY4tO+aNFr0pstgD2ONLlzMHdEn2nWqY66+SzlxzzHywb858L/TrBv3vjWfgX18z15JruqpOpzlqZaA8lxmKhv49Gg3/oD/s+3u69Bl47Fp2i3qJVzVh0ylmrTvmTVZ+8AFz5HsDzBZBjNkpxrk2Cpw5I90fn5M6Nhhee9lsOfvfmg3/n+rPwz1yvk5muOpleWJMdtfHJjprvJjtqKABgueT4r4iYdcqvzbpdP1j0yvjqArCv9SJQul7ctlSp2pctHwYrZaglIPdvNq5/2r/gYm9Twb+x9eBPd9XJVHISmJ/qrP1murOGRwBgOZN2V5VFp+y1aBfGf50ysVQAa3wHYLEAstL1stuRLqcr8qX18imZ7KiVBz0XXxj6jZ/vNxn86xsHP/kIUCdTnXXx6c7av0x11PRs914Drx2TTlFv0ipmzDrlrEWn/MmiV8lmCiDbbJADuTYJntwvN67+Tmau1ydDvmbot36x9yz49S8Z/NrFNT/dVfv7qc66k9u918BrxaxePf4r4hsVgHPh9wBzrSlSVZQtHwQqZTDil7vdjVs77bcY/JmtB1+mOmsTkx21T6a6ake2e6+B145Ju6vKpFP2mrTKx2bts/F/8VuALyqA3fY0OV2eLy2XTspEe43cf8Gz/TYEXyY7amWyoyY+1VHz/VRnXfN27zXw2lka/7XKWYtW+ZNFp5TNFEC2ySD7XVYJnNgnXR++JdNddZs+7X+d4NfKZEeNTHbUzE921Dya5PIPWClNrbCYtcnx36Td9YNZp4hbdKqNC2Bh/K8szJL3/YdlIOyTOzcatvwx3sY3+r8o+DLZEUpMtNc8mehg/AeeY1LvqjJplb0mjeKxWav40axVJlYXwFpvAmam6STfnibVZXkSefukjMVCcrd7EyP+eqf9loJfu2HwJzpqZKK9RsbbQ/HJ9tD3k501jP/AaiaNot6kSY7/Zq3iJ7NOKYsXgC8qgCyTQfblWMV/fJ90fnBWJjtrV4z3Wzntn7vRv/586Lca/GcrND/RHno02c74D6yQplZYTFpFxKRVLI3/Kwvg+ReB7CnJ3wFwWVLkcGGWvOc/LP3NXpm5Xv/LT/tNBn9yE8EfT4Y/MR4LPRlvDzH+A6uZNYpKk3ZXb/rC+G/SKhKbLYC8jDQ5VZYn4YsnZLQtKHdubC70mx3zf0nwx9tDMh4LyVgsFB+PBb8fb2f8B56TrlHUp2sV0yaNYmn830wBZKXrZV+2RXzH90nH+2dloqMmWQCv4LR/+eCHloK/EH4ZjwXnx2PBR2PtQcZ/YDmTRpmarlY0mTS7vkrTKP5q0ip+NuuUYtmgABypWnFZjHKoIFOueA9JX5NHprvqNh36zZ72vyT4C+FPjLYFn4zHgoz/wGomza7d6ZpdMZNG8Y1Jo3hi1i48/2+iAPIyUuVkqVuaGk/ISDQoM9df3Wm/Mvg1Ww7+WCwkY21BGW0Lxkfbgt+PxUKM/8BqaZpdu9PUiiaTRvGVSav4y9InABsUQGa6XoqyLeI9ViTt752R8fbQqsC/4tN+i8EfawvKaDQoI9HA/Ghb8JuxKOM/8ByT5l9T09SKQLpGMWTSKv7TrFU8NeuUieUFYFv1YyCOVK3kmJPj/7veg9J7zSNTnbWv6LR/BcFfWCPRQHwkGvjLSDTAm3/AetLVyjyTRvmOSauYNOsU35p1yn9sVABuW6qcLM2Vaw3HZbg1INNdr+a0X/sz/K0FfzQalNFoIHn6RwO/H2kL8uYf8CImza5Ck27Xe2atcsqiU8bXLYAUjWSm66QwyyzeY4USu3JaxmKhtUP/i0/7mhWhXxH8tvWCH5SRaEBGo4HESKv/yWhrgMs/YDPSdcois1bxvkWnfGrRK+NrFYA9RSvZZoMc3OuUdzwH5fa1CzLRUfNPPe3H1zjt1wv+4hpuDcRHooHvR6IBLv+AzTLrlEVmnfKhRad8al3z58C04ralyImSXLnWcEyGWv0y2VkrU13Ph/6lTvsNgj+6QfBHWgMy3BqQ4Vb//HBr4NFI1M/lH7AVFr0qYNGrHlr1qqc2gyq+/E1AZ5pOCrNM4jlaIG1XTstoW/Cfd9q/VPADMtzqTwy3+J8MM/4DL2XnihIwquI2o1rsKRrJNhmkYq9DLl+okFufnJfx9ppnoV/vc/utnvaxNcb8TQU/IMOtfhlq8ceHW/zfD0cDF7Z7I4Hfqp02vSpg06se2gzqpxlGTdyeopFca4ocL3HJp/VHZTDik4mOzY34L33ab+7EXwz+wvLND7cEbo20BjK3exOB37KdNqM6YDOoH2YY1U+dabp4QaZJLhzZK9F3q2UkGpCJDU/70Ks77TcMvl+GWnyJwYjvyVBL4J3t3jzgTbDTZlQHMoyah9lm/dOKPc74pfPl0vPxORmLhX6d035TwV9YEV98sMU/NRDm8g94VXbaU7UBl8X48ESJ6+kn9Ud+Hgh7EuPtoVdz2rdtJvQvDv5gxLewvH8ciHg7hloClu3eNOBNstNtSw34jxc9bH2nenaoxTc33h6aH4uF4uPtwcR48n/u/RNO+80G3ydDEd//DIR99wbCvsbt3izgTbTzaqgy0PPxufBINBAbbw89Go+FZsdjobnx9tDcaCw4P9oWjI/FgomxWCAx+gpO++G1xvxVwR+M+GQw7P1xMOx7PBj29fZHvFXbvVHAm2rn4prsrKkd6wiFR9tDsfH2mthILPRorC04O9YWmhuNheZG2wLzI9FgfLQtkBiNBhLPhf4XnPaLayDik4GwTwbC3v8daPY+HIj4Pupv9jL+A7+CncvXeHtN7WgsGB6NhWKjsVBsJBp8NBoNzo5EA3MLa364NRAfafUnhpPr5U77lcGXgbD37wNhz5/7m70jA2HPmW3eE+D/rZWF0BasHW4LhkeigdhILBQbbg08Gm4NzA63+OeGW/xzQ63++aEWf3yoxZdIrmWhb3k+9INLoV8KvvQ3e+MDzd4f+ps9/9Ef9rYNRHyObd4DAAtWFMJoW7B2uDUYHooGYkPRQGyoxf9oqMU3OxTxzQ1FfHNDLb75oYgvPhjxJpZWeO3gJ8PvSfQ3eX8aCHtn+5u9M33NXP4Br7MVhTDcGqgdbvWHB1v9scFWf2ww4n80GPHNDoa9c4MR39xg2Ds3EPbOD4S98YGwJzEQ9iT6m73S3+yVvmbPfH+zZ76vyfO0v9n7p75mb29/M5d/wG/Jc4Uw1OIP90f8scGIP9Yf8ccGwr5HA2Hv7ECzd26g2TvXlwx9vK/Z821/s+e/+po83/Y3eT7ra/Y0cfkH/LbtXL2GWny1A2FfuC/sjfWHvbH+Zs+jvrD3Zm+TZ6i3yTPW1+yZ7GvyXO9r9vi3908H8M+wohB6m7xlt695Tw6EfecGw15ff5Pnnb5mT6D32oUD2/x3AvgV7dyxY8fOgSavu7/Jk9V3zave7j8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICV/g9tPJEQu1XvmQAAAABJRU5ErkJggg==">
-<img id="i2" src="http://example.com/tests/content/canvas/test/webgl/resources/thunderbird-logo-64x64.png">
+<img id="i2" src="http://mochi.test:8888/tests/content/canvas/test/webgl/resources/thunderbird-logo-64x64.png">
 
 </body></html>
--- a/content/canvas/test/webgl/conformance/more/functions/texSubImage2DHTML.html
+++ b/content/canvas/test/webgl/conformance/more/functions/texSubImage2DHTML.html
@@ -151,11 +151,11 @@ void main()
     vec4 c = texture2D(Texture, texCoord0.st);
     gl_FragColor = c;
 }
 </script>
 </head><body>
 <canvas id="gl" width="256" height="256"></canvas>
 <canvas id="c" width="256" height="256"></canvas>
 <img id="i" width="256" height="256"  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAATVElEQVR4nO3d+VPUd57Hcf2b9k9Y+z44+qK7OZoGFVA5VfBGzah9cxpNzGEOoRua5lBEue/DK4fZ7MapmSm3Mlshu8xOdCpDJt3v/aEBAUHAOMG4z0fV53fqU/V6fd7fT/e32bEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwOvBkar7l+3+GwBsk8xUrT0rTb8vx2Q45janlu7YsWPnsgXgTeYwak85U3Xv5ZiM3+XbUh/l2dICBc6080WZ1ur92baSHRQB8GayGdUWu1HzoSNFO+ZM1f2cbTLM51lT5woc5rkDObbZ/Vm2SEm23VvsyjhV5nJQBsCbxGZQVtmN6p4Mo/YPdqNGHKlayUrXJ9zWlESh0xIvzsmYL3HZ54pzMm6VuRyRMpfTW+pyUAbAm8BmVNVnGNTTdqP6vzOMGrGnaMSZqpNsk17ybKlS6DTL/ixbotRlj5flOubL3I65MpfjVrnbEalYKINSl335vQGA3wKbUW2xGdWRDKP66wyjWhYLwJGiFWeaTrJNBnFbU2SP3ST7s6xSmmuXcrczUe52xstzHfPlbsdcudt5qyzX3lKWlxkszXGeK8mxnyzJySjeQRkArzebQVllM6p7bUb149UF4EjVSmaaTrLS9eKypMgee7ocyLZJmdshFXmZUpHnXFEGB/OzJsrdjqEyt/NmWa49XJbt9Ja6Mk4Vu7hEBF5LNr2q3mZQz9gM6u9XFEBqsgCcaTrJXJgEci0pstdhkv3ZNinNTZbAofwsOZSfJQfzMqU8z5kodzsSZbmOeIXb+XW52zFa5nLcKnPZI2ULl4jFfKIAvB7MOrXFZlBHbAb11zaj+kmGUbNuAWSm65dKYHdGmhRlWqQ8zyFHCnLk+L5cOV6UK0cKXVK5J1sO5mdKhdspZavKoDTX0VPiciTLIHtFGVAIwK/NYlBW2fTqXptB/dhmSJ7+LyqArHS95JiTJVDgNEllQZZ4KgulrrpU6qtLJXBsv5wt3yMn9rvlaIFLDi8vg1xH4mB+5p+Wl0Fpjr2lJMcRLM6ynyvOzjhxIIt7A+BXY9Gr6q0L4/9SAaRoxL7w/L9WAWSbDJJrTZFid4Z4jxZJU/1xufHhOem+ek6il0/LB74qaTxTJoGj++Vs2R45vj9XjhTkyOHdC48JC2VwaHfmnyrczn+vcDsmynLtQyU5GTeLczLCpTk2T3GW7VhxVsae7d4f4I1l1qktVoM6YjOovrYa1D8sFoB9WQE415kA8u1pcvRAjnwUOiLDLQG5190o9242ylRHnQyG/XLz6nmJXqqWD3yV0nC6VPxH98nZst1yfF+uHC10SdXebDmUnyyDqoLs7w7lZ35b7nb8scxt/7dSl32kJCejqyQn40pJTkbZDiYC4NWzaJVVVr2q12ZQPbYa1H9fuwB0SwWQla6XLFOyAAoyTfLW4T3SfuWM3L3RIA/7L8vD/svyZe8l+ezW23Kvu1EmO2ploNkn3VfPSevb1fK+t1Iaz5RJ7cli8R0pktOl+XKsKFkGBxfKoHJv1l8P5mf+uSLP8fvyXMdMmdsRKXc5qotdGQXbvV/AG8WiV9Vb9aoZq141azOoxWbcXAHkWlOkJC9Dak8Xy61PL8iDnotLBbBUBH2X5Yvbl+RBz0W5e6NBJtprpL/ZJzc/Oi/XP3hLWi6ekvc8h6WuukS8Vc/KYPEC8WhhzpOqguzvKvdmfXV4d2b3wfzM9w/lZTENAK+CWaewWHWqiE2v+tqqV/2w2QLINhkkP2Nh/K89ImNtIfmi99Kz8Pcl15dL65J80XtJPr/1tty/2Sh3uxvkzvV6GY+FpO+aV65/8DuJXDwpVzyHpO7UQhmU5MvRIpdU7c2RQ7uz5MR+9x+OFbnuHi3MiVQVuKoP784u2u79A37TLFpllVWn6rXqVY+tetWPGxbAsgvAvU6TvHVot8SunJY7N+rly761g/9lb3J9sWx9fvuSfH77bXnQc1HudTfITFedjLWFpPeaR7o+eEvCjSflyoVDUlddKsHjB+TC4UI5VZwnVQU5ibcq9nx1ujS/58QB99XqYnf5DqYB4OVYdM/Gf6te9Y/k8//GBeCyGKXEnSE11Qek55Pzcv9m48rQrxP8L25fki9uvy2fr1qf3bqYnAxuNMh0Z52MRINy+1OPXP/wd9J+5Yw015+Qd84flJqTxXLhcIGcLM77+UhBzt8uVBa2nqvce/ZsxZ6y7d5L4Ddlcfy36FVfW/SqH6wGlawugMWvATvTlhWAySB5GalydH+OfFRzREajQfn81tvrh/6FwV9cF+WzWxflwa2Lcr/notzrbpSZ6/Uy1VUnkx21MtwSkJ5PLkjHe2elqf64XD53UEInDiQuHC6Yry7Omz1W5HrY+FbF4R1MA8DmWLTKKsuy8d9qUL+wAJZ/C3CPM13OHtwtbe+elunr9fLFusF/PvSf31o7+A96nq37PRflfk+j3L+Z/Fjx7o0Gme6qk4n2Ghlq8UvPx+el/coZuVZ3XC6fq/i57lTx32pOHngUOlUc/jR4lEtCYCMWnareolfNWPSqWatB9dOaBbDGl4BcFqMUu20SOnVAbn58Tu52N27qtP98g9A/WAz9QvAX173FEuhukLvdDcnJoLNWxmM1Mhjxy82Pzknn+2cSsXdPz4cbT8x+GKh8+FHwSO0OSgBYm1mnsJh1qohFr1wY/5XxZwWw/teAs9KTvwtwZH+2XA1VyXBrUB70XFz/tF9nzN9K8O91N8i9hfAvrjs3GuTOjXqZXnhEGG+vkdFoUAbD/p97Pj7/t56r57/pu+b5pOXd6qPbvdfAa8ei3VVl0al6LXrlY4tO+aNFr0pstgD2ONLlzMHdEn2nWqY66+SzlxzzHywb858L/TrBv3vjWfgX18z15JruqpOpzlqZaA8lxmKhv49Gg3/oD/s+3u69Bl47Fp2i3qJVzVh0ylmrTvmTVZ+8AFz5HsDzBZBjNkpxrk2Cpw5I90fn5M6Nhhee9lsOfvfmg3/n+rPwz1yvk5muOpleWJMdtfHJjprvJjtqKABgueT4r4iYdcqvzbpdP1j0yvjqArCv9SJQul7ctlSp2pctHwYrZaglIPdvNq5/2r/gYm9Twb+x9eBPd9XJVHISmJ/qrP1murOGRwBgOZN2V5VFp+y1aBfGf50ysVQAa3wHYLEAstL1stuRLqcr8qX18imZ7KiVBz0XXxj6jZ/vNxn86xsHP/kIUCdTnXXx6c7av0x11PRs914Drx2TTlFv0ipmzDrlrEWn/MmiV8lmCiDbbJADuTYJntwvN67+Tmau1ydDvmbot36x9yz49S8Z/NrFNT/dVfv7qc66k9u918BrxaxePf4r4hsVgHPh9wBzrSlSVZQtHwQqZTDil7vdjVs77bcY/JmtB1+mOmsTkx21T6a6ake2e6+B145Ju6vKpFP2mrTKx2bts/F/8VuALyqA3fY0OV2eLy2XTspEe43cf8Gz/TYEXyY7amWyoyY+1VHz/VRnXfN27zXw2lka/7XKWYtW+ZNFp5TNFEC2ySD7XVYJnNgnXR++JdNddZs+7X+d4NfKZEeNTHbUzE921Dya5PIPWClNrbCYtcnx36Td9YNZp4hbdKqNC2Bh/K8szJL3/YdlIOyTOzcatvwx3sY3+r8o+DLZEUpMtNc8mehg/AeeY1LvqjJplb0mjeKxWav40axVJlYXwFpvAmam6STfnibVZXkSefukjMVCcrd7EyP+eqf9loJfu2HwJzpqZKK9RsbbQ/HJ9tD3k501jP/AaiaNot6kSY7/Zq3iJ7NOKYsXgC8qgCyTQfblWMV/fJ90fnBWJjtrV4z3Wzntn7vRv/586Lca/GcrND/RHno02c74D6yQplZYTFpFxKRVLI3/Kwvg+ReB7CnJ3wFwWVLkcGGWvOc/LP3NXpm5Xv/LT/tNBn9yE8EfT4Y/MR4LPRlvDzH+A6uZNYpKk3ZXb/rC+G/SKhKbLYC8jDQ5VZYn4YsnZLQtKHdubC70mx3zf0nwx9tDMh4LyVgsFB+PBb8fb2f8B56TrlHUp2sV0yaNYmn830wBZKXrZV+2RXzH90nH+2dloqMmWQCv4LR/+eCHloK/EH4ZjwXnx2PBR2PtQcZ/YDmTRpmarlY0mTS7vkrTKP5q0ip+NuuUYtmgABypWnFZjHKoIFOueA9JX5NHprvqNh36zZ72vyT4C+FPjLYFn4zHgoz/wGomza7d6ZpdMZNG8Y1Jo3hi1i48/2+iAPIyUuVkqVuaGk/ISDQoM9df3Wm/Mvg1Ww7+WCwkY21BGW0Lxkfbgt+PxUKM/8BqaZpdu9PUiiaTRvGVSav4y9InABsUQGa6XoqyLeI9ViTt752R8fbQqsC/4tN+i8EfawvKaDQoI9HA/Ghb8JuxKOM/8ByT5l9T09SKQLpGMWTSKv7TrFU8NeuUieUFYFv1YyCOVK3kmJPj/7veg9J7zSNTnbWv6LR/BcFfWCPRQHwkGvjLSDTAm3/AetLVyjyTRvmOSauYNOsU35p1yn9sVABuW6qcLM2Vaw3HZbg1INNdr+a0X/sz/K0FfzQalNFoIHn6RwO/H2kL8uYf8CImza5Ck27Xe2atcsqiU8bXLYAUjWSm66QwyyzeY4USu3JaxmKhtUP/i0/7mhWhXxH8tvWCH5SRaEBGo4HESKv/yWhrgMs/YDPSdcois1bxvkWnfGrRK+NrFYA9RSvZZoMc3OuUdzwH5fa1CzLRUfNPPe3H1zjt1wv+4hpuDcRHooHvR6IBLv+AzTLrlEVmnfKhRad8al3z58C04ralyImSXLnWcEyGWv0y2VkrU13Ph/6lTvsNgj+6QfBHWgMy3BqQ4Vb//HBr4NFI1M/lH7AVFr0qYNGrHlr1qqc2gyq+/E1AZ5pOCrNM4jlaIG1XTstoW/Cfd9q/VPADMtzqTwy3+J8MM/4DL2XnihIwquI2o1rsKRrJNhmkYq9DLl+okFufnJfx9ppnoV/vc/utnvaxNcb8TQU/IMOtfhlq8ceHW/zfD0cDF7Z7I4Hfqp02vSpg06se2gzqpxlGTdyeopFca4ocL3HJp/VHZTDik4mOzY34L33ab+7EXwz+wvLND7cEbo20BjK3exOB37KdNqM6YDOoH2YY1U+dabp4QaZJLhzZK9F3q2UkGpCJDU/70Ks77TcMvl+GWnyJwYjvyVBL4J3t3jzgTbDTZlQHMoyah9lm/dOKPc74pfPl0vPxORmLhX6d035TwV9YEV98sMU/NRDm8g94VXbaU7UBl8X48ESJ6+kn9Ud+Hgh7EuPtoVdz2rdtJvQvDv5gxLewvH8ciHg7hloClu3eNOBNstNtSw34jxc9bH2nenaoxTc33h6aH4uF4uPtwcR48n/u/RNO+80G3ydDEd//DIR99wbCvsbt3izgTbTzaqgy0PPxufBINBAbbw89Go+FZsdjobnx9tDcaCw4P9oWjI/FgomxWCAx+gpO++G1xvxVwR+M+GQw7P1xMOx7PBj29fZHvFXbvVHAm2rn4prsrKkd6wiFR9tDsfH2mthILPRorC04O9YWmhuNheZG2wLzI9FgfLQtkBiNBhLPhf4XnPaLayDik4GwTwbC3v8daPY+HIj4Pupv9jL+A7+CncvXeHtN7WgsGB6NhWKjsVBsJBp8NBoNzo5EA3MLa364NRAfafUnhpPr5U77lcGXgbD37wNhz5/7m70jA2HPmW3eE+D/rZWF0BasHW4LhkeigdhILBQbbg08Gm4NzA63+OeGW/xzQ63++aEWf3yoxZdIrmWhb3k+9INLoV8KvvQ3e+MDzd4f+ps9/9Ef9rYNRHyObd4DAAtWFMJoW7B2uDUYHooGYkPRQGyoxf9oqMU3OxTxzQ1FfHNDLb75oYgvPhjxJpZWeO3gJ8PvSfQ3eX8aCHtn+5u9M33NXP4Br7MVhTDcGqgdbvWHB1v9scFWf2ww4n80GPHNDoa9c4MR39xg2Ds3EPbOD4S98YGwJzEQ9iT6m73S3+yVvmbPfH+zZ76vyfO0v9n7p75mb29/M5d/wG/Jc4Uw1OIP90f8scGIP9Yf8ccGwr5HA2Hv7ECzd26g2TvXlwx9vK/Z821/s+e/+po83/Y3eT7ra/Y0cfkH/LbtXL2GWny1A2FfuC/sjfWHvbH+Zs+jvrD3Zm+TZ6i3yTPW1+yZ7GvyXO9r9vi3908H8M+wohB6m7xlt695Tw6EfecGw15ff5Pnnb5mT6D32oUD2/x3AvgV7dyxY8fOgSavu7/Jk9V3zave7j8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICV/g9tPJEQu1XvmQAAAABJRU5ErkJggg==">
-<img id="i2" src="http://example.com/tests/content/canvas/test/webgl/resources/thunderbird-logo-64x64.png">
+<img id="i2" src="http://mochi.test:8888/tests/content/canvas/test/webgl/resources/thunderbird-logo-64x64.png">
 
 </body></html>
--- a/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
+++ b/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
@@ -229,17 +229,17 @@ function start() {
       this.currentPage = null;
       this.displayStats();
     }
   };
 
   Reporter.prototype.finishedTestSuite = function() {
       for (var i = 0; i < testsExpectedToFail.length; ++i)
         if (testsSuccessful.indexOf(testsExpectedToFail[i]) != -1)
-          ok(false, 'Test expected to fail, but passed: ' + testsExpectedToFail[i]);
+          todo(true, 'Test expected to fail, but passed: ' + testsExpectedToFail[i]);
       statusTextNode.textContent = 'Finished';
       SimpleTest.finish();
   }
 
   Reporter.prototype.reportFunc = function(type, msg, success) {
     switch (type) {
       case reportType.ADD_PAGE:
         return this.addPage(msg);
@@ -358,16 +358,23 @@ function start() {
     failingTestsFilename = 'failing_tests_linux.txt';
   else if (kIsMac)
     failingTestsFilename = 'failing_tests_mac.txt';
 
   var testsExpectedToFail = loadTextFileSynchronous(failingTestsFilename)
                             .replace(/\r/g, '') // convert to unix line breaks
                             .split('\n');
 
+  if (kIsWindows && !kIsWindowsVistaOrHigher) {
+    testsExpectedToFail.push('conformance/framebuffer-object-attachment.html'); // NVIDIA 190.42 doesnt support DEPTH_STENCIL
+    testsExpectedToFail.push('conformance/gl-get-active-attribute.html'); // bug in NVIDIA 190.42, fixed in newer drivers
+    testsExpectedToFail.push('conformance/gl-uniform-bool.html'); // bug in NVIDIA 190.42, fixed in newer drivers
+    testsExpectedToFail.push('conformance/tex-image-and-sub-image-2d-with-array-buffer-view.html'); // ???
+  }
+
   var testsToIgnore = [];
 
   var testsSuccessful = [];
 
   runTestSuite();
 }
 
 </script>
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -55,19 +55,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug288392.html \
 		test_bug299673-1.html \
 		test_bug299673-2.html \
 		     bug299673.js \
 		test_bug322588.html \
 		     bug322588-popup.html \
 		test_bug328885.html \
 		test_bug336682_1.html \
-		test_bug336682_2.xul \
 		test_bug336682.js \
-		test_bug350471.xul \
 		test_bug367781.html \
 		test_bug368835.html \
 		test_bug379120.html \
 		test_bug391568.xhtml \
 		test_bug402089.html \
 		test_bug405632.html \
 		test_bug409604.html \
 		test_bug412567.html \
@@ -87,17 +85,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug508906.html \
 		test_bug517851.html \
 		test_bug534833.html \
 		test_bug545268.html \
 		test_bug547996-1.html \
 		test_bug547996-2.xhtml \
 		test_bug556493.html \
 		test_bug574663.html \
-		test_bug586961.xul \
 		test_clickevent_on_input.html \
 		test_bug593959.html \
 		test_bug591815.html \
 		test_bug605242.html \
 		test_bug613634.html \
 		test_bug607464.html \
 		test_bug624127.html \
 		test_bug650493.html \
@@ -119,16 +116,20 @@ endif
 # bug 565245
 ifneq (Linux,$(OS_ARCH))
 _TEST_FILES += \
 		test_bug493251.html \
 		$(NULL)
 endif
 
 _CHROME_FILES = \
+		test_bug336682_2.xul \
+		test_bug336682.js \
+		test_bug350471.xul \
+		test_bug586961.xul \
 		test_bug415498.xul \
 		bug415498-doc1.html \
 		bug415498-doc2.html \
 		bug602962.xul \
 		test_bug602962.xul \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
--- a/content/events/test/test_bug336682_2.xul
+++ b/content/events/test/test_bug336682_2.xul
@@ -1,26 +1,26 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 Bug 336682: online/offline events tests.
 
 Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/licenses/publicdomain/
 -->
 <window title="Mozilla Bug 336682"
   onoffline="trace('lt;body onoffline=...'); windowOnoffline(this, event)"
   ononline="trace('lt;body ononline=...'); windowOnonline(this, event)"
 
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>      
+  <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">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=336682">
 Mozilla Bug 336682 (online/offline events)</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 </body>
--- a/content/events/test/test_bug350471.xul
+++ b/content/events/test/test_bug350471.xul
@@ -1,21 +1,21 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=350471
 -->
 <window title="Mozilla Bug 350471"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Test for Bug 350471</title>
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
 <body  xmlns="http://www.w3.org/1999/xhtml">
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=350471">Mozilla Bug 350471</a>
 
   <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 </body>
 
--- a/content/events/test/test_bug586961.xul
+++ b/content/events/test/test_bug586961.xul
@@ -1,21 +1,21 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=586961
 -->
 <window title="Mozilla Bug 586961"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Test for Bug 586961</title>
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
 <body  xmlns="http://www.w3.org/1999/xhtml">
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=586961">Mozilla Bug 586961</a>
 
   <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 </body>
 
--- a/content/html/content/public/Makefile.in
+++ b/content/html/content/public/Makefile.in
@@ -55,17 +55,16 @@ EXPORTS = \
 		nsIFormControl.h \
 		nsIForm.h \
 		nsIFormProcessor.h \
 		nsILink.h \
 		nsIRadioVisitor.h \
 		nsIRadioGroupContainer.h \
 		nsITextControlElement.h \
 		nsFormSubmission.h \
-		nsIFrameSetElement.h \
 		nsHTMLAudioElement.h \
 		nsHTMLCanvasElement.h \
 		nsHTMLMediaElement.h \
 		nsHTMLVideoElement.h \
 		nsIHTMLCollection.h \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/content/html/content/public/nsHTMLCanvasElement.h
+++ b/content/html/content/public/nsHTMLCanvasElement.h
@@ -172,18 +172,17 @@ public:
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   nsIntSize GetWidthHeight();
 
   nsresult UpdateContext(nsIPropertyBag *aNewContextOptions = nsnull);
   nsresult ExtractData(const nsAString& aType,
                        const nsAString& aOptions,
-                       char*& aData,
-                       PRUint32& aSize,
+                       nsIInputStream** aStream,
                        bool& aFellBackToPNG);
   nsresult ToDataURLImpl(const nsAString& aMimeType,
                          nsIVariant* aEncoderOptions,
                          nsAString& aDataURL);
   nsresult MozGetAsFileImpl(const nsAString& aName,
                             const nsAString& aType,
                             nsIDOMFile** aResult);
   nsresult GetContextHelper(const nsAString& aContextId,
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -32,17 +32,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHTMLCanvasElement.h"
 
-#include "plbase64.h"
+#include "mozilla/Base64.h"
 #include "nsNetUtil.h"
 #include "prmem.h"
 #include "nsDOMFile.h"
 #include "CheckedInt.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
@@ -206,18 +206,17 @@ nsHTMLCanvasElement::ToDataURL(const nsA
   }
 
   return ToDataURLImpl(aType, aParams, aDataURL);
 }
 
 nsresult
 nsHTMLCanvasElement::ExtractData(const nsAString& aType,
                                  const nsAString& aOptions,
-                                 char*& aResult,
-                                 PRUint32& aSize,
+                                 nsIInputStream** aStream,
                                  bool& aFellBackToPNG)
 {
   // note that if we don't have a current context, the spec says we're
   // supposed to just return transparent black pixels of the canvas
   // dimensions.
   nsRefPtr<gfxImageSurface> emptyCanvas;
   nsIntSize size = GetWidthHeight();
   if (!mCurrentContext) {
@@ -260,55 +259,19 @@ nsHTMLCanvasElement::ExtractData(const n
   if (NS_FAILED(rv) && !aFellBackToPNG) {
     // Try image/png instead.
     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
     aFellBackToPNG = true;
     encoderType.AssignLiteral("image/png");
     goto try_again;
   }
 
-  // at this point, we either need to succeed or bail.
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Generally, there will be only one chunk of data, and it will be available
-  // for us to read right away, so optimize this case.
-  PRUint32 bufSize;
-  rv = imgStream->Available(&bufSize);
-  CheckedUint32 safeBufSize(bufSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // ...leave a little extra room so we can call read again and make sure we
-  // got everything. 16 bytes for better padding (maybe)
-  safeBufSize += 16;
-  NS_ENSURE_TRUE(safeBufSize.valid(), NS_ERROR_FAILURE);
-  aSize = 0;
-  aResult = (char*)PR_Malloc(safeBufSize.value());
-  if (!aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
-  PRUint32 numReadThisTime = 0;
-  while ((rv = imgStream->Read(&aResult[aSize], safeBufSize.value() - aSize,
-                               &numReadThisTime)) == NS_OK &&
-         numReadThisTime > 0) {
-    aSize += numReadThisTime;
-    if (aSize == safeBufSize.value()) {
-      // need a bigger buffer, just double
-      safeBufSize *= 2;
-      if (!safeBufSize.valid()) {
-        PR_Free(aResult);
-        return NS_ERROR_FAILURE;
-      }
-      char* newImgData = (char*)PR_Realloc(aResult, safeBufSize.value());
-      if (! newImgData) {
-        PR_Free(aResult);
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-      aResult = newImgData;
-    }
-  }
-
+  return CallQueryInterface(imgStream, aStream);
   return NS_OK;
 }
 
 nsresult
 nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
                                    nsIVariant* aEncoderOptions,
                                    nsAString& aDataURL)
 {
@@ -338,39 +301,33 @@ nsHTMLCanvasElement::ToDataURLImpl(const
       if (NS_SUCCEEDED(aEncoderOptions->GetAsDouble(&quality)) &&
           quality >= 0.0 && quality <= 1.0) {
         params.AppendLiteral("quality=");
         params.AppendInt(NS_lround(quality * 100.0));
       }
     }
   }
 
-  PRUint32 imgSize = 0;
-  char* imgData;
-
-  nsresult rv = ExtractData(type, params, imgData, imgSize, fallbackToPNG);
+  nsCOMPtr<nsIInputStream> stream;
+  nsresult rv = ExtractData(type, params, getter_AddRefs(stream),
+                            fallbackToPNG);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // base 64, result will be NULL terminated
-  char* encodedImg = PL_Base64Encode(imgData, imgSize, nsnull);
-  PR_Free(imgData);
-  if (!encodedImg) // not sure why this would fail
-    return NS_ERROR_OUT_OF_MEMORY;
-
   // build data URL string
   if (fallbackToPNG)
-    aDataURL = NS_LITERAL_STRING("data:image/png;base64,") +
-      NS_ConvertUTF8toUTF16(encodedImg);
+    aDataURL = NS_LITERAL_STRING("data:image/png;base64,");
   else
     aDataURL = NS_LITERAL_STRING("data:") + type +
-      NS_LITERAL_STRING(";base64,") + NS_ConvertUTF8toUTF16(encodedImg);
+      NS_LITERAL_STRING(";base64,");
 
-  PR_Free(encodedImg);
+  PRUint32 count;
+  rv = stream->Available(&count);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  return NS_OK;
+  return Base64EncodeInputStream(stream, aDataURL, count, aDataURL.Length());
 }
 
 NS_IMETHODIMP
 nsHTMLCanvasElement::MozGetAsFile(const nsAString& aName,
                                   const nsAString& aType,
                                   PRUint8 optional_argc,
                                   nsIDOMFile** aResult)
 {
@@ -384,31 +341,38 @@ nsHTMLCanvasElement::MozGetAsFile(const 
 }
 
 nsresult
 nsHTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
                                       const nsAString& aType,
                                       nsIDOMFile** aResult)
 {
   bool fallbackToPNG = false;
-  PRUint32 imgSize = 0;
-  char* imgData;
 
-  nsresult rv = ExtractData(aType, EmptyString(), imgData,
-                            imgSize, fallbackToPNG);
+  nsCOMPtr<nsIInputStream> stream;
+  nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
+                            fallbackToPNG);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString type(aType);
   if (fallbackToPNG) {
     type.AssignLiteral("image/png");
   }
 
+  PRUint32 imgSize;
+  rv = stream->Available(&imgSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  void* imgData = nsnull;
+  rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // The DOMFile takes ownership of the buffer
   nsRefPtr<nsDOMMemoryFile> file =
-    new nsDOMMemoryFile((void*)imgData, imgSize, aName, type);
+    new nsDOMMemoryFile(imgData, imgSize, aName, type);
 
   return CallQueryInterface(file, aResult);
 }
 
 nsresult
 nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
                                       nsICanvasRenderingContextInternal **aContext)
 {
--- a/content/html/content/src/nsHTMLFrameSetElement.cpp
+++ b/content/html/content/src/nsHTMLFrameSetElement.cpp
@@ -29,99 +29,18 @@
  * 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 "nsIDOMHTMLFrameSetElement.h"
-#include "nsIDOMEventTarget.h"
-#include "nsGenericHTMLElement.h"
-#include "nsGkAtoms.h"
-#include "nsStyleConsts.h"
-#include "nsIFrameSetElement.h"
-#include "nsIHTMLDocument.h"
-#include "nsIDocument.h"
 
-class nsHTMLFrameSetElement : public nsGenericHTMLElement,
-                              public nsIDOMHTMLFrameSetElement,
-                              public nsIFrameSetElement
-{
-public:
-  nsHTMLFrameSetElement(already_AddRefed<nsINodeInfo> aNodeInfo);
-  virtual ~nsHTMLFrameSetElement();
-
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIDOMNode
-  NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
-
-  // nsIDOMElement
-  NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
-
-  // nsIDOMHTMLElement
-  NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
-
-  // nsIDOMHTMLFrameSetElement
-  NS_DECL_NSIDOMHTMLFRAMESETELEMENT
-
-  // These override the SetAttr methods in nsGenericHTMLElement (need
-  // both here to silence compiler warnings).
-  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                   const nsAString& aValue, PRBool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
-  }
-  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                           nsIAtom* aPrefix, const nsAString& aValue,
-                           PRBool aNotify);
-
-  // nsIFramesetElement
-  NS_IMETHOD GetRowSpec(PRInt32 *aNumValues, const nsFramesetSpec** aSpecs);
-  NS_IMETHOD GetColSpec(PRInt32 *aNumValues, const nsFramesetSpec** aSpecs);
-
-  virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
-                                nsIAtom* aAttribute,
-                                const nsAString& aValue,
-                                nsAttrValue& aResult);
-  virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
-                                              PRInt32 aModType) const;
-
-  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
-  virtual nsXPCClassInfo* GetClassInfo();
-private:
-  nsresult ParseRowCol(const nsAString& aValue,
-                       PRInt32&         aNumSpecs,
-                       nsFramesetSpec** aSpecs);
-
-  /**
-   * The number of size specs in our "rows" attr
-   */
-  PRInt32          mNumRows;
-  /**
-   * The number of size specs in our "cols" attr
-   */
-  PRInt32          mNumCols;
-  /**
-   * The style hint to return for the rows/cols attrs in
-   * GetAttributeChangeHint
-   */
-  nsChangeHint      mCurrentRowColHint;
-  /**
-   * The parsed representation of the "rows" attribute
-   */
-  nsAutoArrayPtr<nsFramesetSpec>  mRowSpecs; // parsed, non-computed dimensions
-  /**
-   * The parsed representation of the "cols" attribute
-   */
-  nsAutoArrayPtr<nsFramesetSpec>  mColSpecs; // parsed, non-computed dimensions
-};
+#include "nsHTMLFrameSetElement.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
 
 
 nsHTMLFrameSetElement::nsHTMLFrameSetElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo), mNumRows(0), mNumCols(0),
     mCurrentRowColHint(NS_STYLE_HINT_REFLOW)
 {
@@ -135,19 +54,18 @@ nsHTMLFrameSetElement::~nsHTMLFrameSetEl
 NS_IMPL_ADDREF_INHERITED(nsHTMLFrameSetElement, nsGenericElement) 
 NS_IMPL_RELEASE_INHERITED(nsHTMLFrameSetElement, nsGenericElement) 
 
 
 DOMCI_NODE_DATA(HTMLFrameSetElement, nsHTMLFrameSetElement)
 
 // QueryInterface implementation for nsHTMLFrameSetElement
 NS_INTERFACE_TABLE_HEAD(nsHTMLFrameSetElement)
-  NS_HTML_CONTENT_INTERFACE_TABLE2(nsHTMLFrameSetElement,
-                                   nsIDOMHTMLFrameSetElement,
-                                   nsIFrameSetElement)
+  NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLFrameSetElement,
+                                   nsIDOMHTMLFrameSetElement)
   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLFrameSetElement,
                                                nsGenericHTMLElement)
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLFrameSetElement)
 
 
 NS_IMPL_ELEMENT_CLONE(nsHTMLFrameSetElement)
 
 
@@ -189,17 +107,17 @@ nsHTMLFrameSetElement::SetAttr(PRInt32 a
   
   rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aAttribute, aPrefix,
                                      aValue, aNotify);
   mCurrentRowColHint = NS_STYLE_HINT_REFLOW;
   
   return rv;
 }
 
-NS_IMETHODIMP
+nsresult
 nsHTMLFrameSetElement::GetRowSpec(PRInt32 *aNumValues,
                                   const nsFramesetSpec** aSpecs)
 {
   NS_PRECONDITION(aNumValues, "Must have a pointer to an integer here!");
   NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
   *aNumValues = 0;
   *aSpecs = nsnull;
   
@@ -223,17 +141,17 @@ nsHTMLFrameSetElement::GetRowSpec(PRInt3
     }
   }
 
   *aSpecs = mRowSpecs;
   *aNumValues = mNumRows;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsHTMLFrameSetElement::GetColSpec(PRInt32 *aNumValues,
                                   const nsFramesetSpec** aSpecs)
 {
   NS_PRECONDITION(aNumValues, "Must have a pointer to an integer here!");
   NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
   *aNumValues = 0;
   *aSpecs = nsnull;
 
@@ -424,9 +342,8 @@ nsHTMLFrameSetElement::ParseRowCol(const
   }
 
   aNumSpecs = count;
   // Transfer ownership to caller here
   *aSpecs = specs;
   
   return NS_OK;
 }
-
rename from content/html/content/public/nsIFrameSetElement.h
rename to content/html/content/src/nsHTMLFrameSetElement.h
--- a/content/html/content/public/nsIFrameSetElement.h
+++ b/content/html/content/src/nsHTMLFrameSetElement.h
@@ -7,49 +7,52 @@
  * 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 Original Code is Mozilla Communicator client code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2002
+ * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Boris Zbarsky <bzbarsky@mit.edu>  (Original author)
+ * Boris Zbarsky <bzbarsky@mit.edu>  (Original author)
+ * Sebastian Kromp <46b@gulli.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef nsIFramesetElement_h___
-#define nsIFramesetElement_h___
+#ifndef nsHTMLFrameSetElement_h
+#define nsHTMLFrameSetElement_h
 
 #include "nsISupports.h"
-
-// IID for the nsIFramesetElement interface
-#define NS_IFRAMESETELEMENT_IID \
-{ 0xeefe0fe5, 0x44ac, 0x4d7f, \
-  { 0xa7, 0x51, 0xf4, 0xaa, 0x5f, 0x22, 0xb0, 0xbf } }
+#include "nsIDOMHTMLFrameSetElement.h"
+#include "nsIDOMEventTarget.h"
+#include "nsGenericHTMLElement.h"
+#include "nsGkAtoms.h"
+#include "nsStyleConsts.h"
+#include "nsIHTMLDocument.h"
+#include "nsIDocument.h"
 
 /**
  * The nsFramesetUnit enum is used to denote the type of each entry
  * in the row or column spec.
  */
 enum nsFramesetUnit {
   eFramesetUnit_Fixed = 0,
   eFramesetUnit_Percent,
@@ -66,41 +69,104 @@ struct nsFramesetSpec {
 };
 
 /**
  * The maximum number of entries allowed in the frame set element row
  * or column spec.
  */
 #define NS_MAX_FRAMESET_SPEC_COUNT 16000
 
-/**
- * This interface is used by the nsFramesetFrame to access the parsed
- * values of the "rows" and "cols" attributes
- */
-class nsIFrameSetElement : public nsISupports {
+class nsHTMLFrameSetElement : public nsGenericHTMLElement,
+                              public nsIDOMHTMLFrameSetElement
+{
 public:
+  nsHTMLFrameSetElement(already_AddRefed<nsINodeInfo> aNodeInfo);
+  virtual ~nsHTMLFrameSetElement();
 
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFRAMESETELEMENT_IID)
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMNode
+  NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
+
+  // nsIDOMElement
+  NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
+
+  // nsIDOMHTMLElement
+  NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
+
+  // nsIDOMHTMLFrameSetElement
+  NS_DECL_NSIDOMHTMLFRAMESETELEMENT
+
+  // These override the SetAttr methods in nsGenericHTMLElement (need
+  // both here to silence compiler warnings).
+  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                   const nsAString& aValue, PRBool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
+  }
+  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                           nsIAtom* aPrefix, const nsAString& aValue,
+                           PRBool aNotify);
+
+   /**
+    * GetRowSpec is used to get the "rows" spec.
+    * @param out PRInt32 aNumValues The number of row sizes specified.
+    * @param out nsFramesetSpec* aSpecs The array of size specifications.
+             This is _not_ owned by the caller, but by the nsFrameSetElement
+             implementation.  DO NOT DELETE IT.
+    */
+  nsresult GetRowSpec(PRInt32 *aNumValues, const nsFramesetSpec** aSpecs);
+   /**
+    * GetColSpec is used to get the "cols" spec
+    * @param out PRInt32 aNumValues The number of row sizes specified.
+    * @param out nsFramesetSpec* aSpecs The array of size specifications.
+             This is _not_ owned by the caller, but by the nsFrameSetElement
+             implementation.  DO NOT DELETE IT.
+    */
+  nsresult GetColSpec(PRInt32 *aNumValues, const nsFramesetSpec** aSpecs);
+
+
+  virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
+                                nsIAtom* aAttribute,
+                                const nsAString& aValue,
+                                nsAttrValue& aResult);
+  virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
+                                              PRInt32 aModType) const;
+
+  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+  virtual nsXPCClassInfo* GetClassInfo();
+  static nsHTMLFrameSetElement* FromContent(nsIContent *aContent)
+  {
+    if (aContent->IsHTML(nsGkAtoms::frameset))
+      return static_cast<nsHTMLFrameSetElement*>(aContent);
+    return nsnull;
+  }
+
+private:
+  nsresult ParseRowCol(const nsAString& aValue,
+                       PRInt32&         aNumSpecs,
+                       nsFramesetSpec** aSpecs);
 
   /**
-   * GetRowSpec is used to get the "rows" spec.
-   * @param out PRInt32 aNumValues The number of row sizes specified.
-   * @param out nsFramesetSpec* aSpecs The array of size specifications.
-            This is _not_ owned by the caller, but by the nsIFrameSetElement
-            implementation.  DO NOT DELETE IT.
-   * @exceptions NS_ERROR_OUT_OF_MEMORY
+   * The number of size specs in our "rows" attr
+   */
+  PRInt32          mNumRows;
+  /**
+   * The number of size specs in our "cols" attr
    */
-  NS_IMETHOD GetRowSpec(PRInt32 *aNumValues, const nsFramesetSpec** aSpecs) = 0;
-
+  PRInt32          mNumCols;
+  /**
+   * The style hint to return for the rows/cols attrs in
+   * GetAttributeChangeHint
+   */
+  nsChangeHint      mCurrentRowColHint;
   /**
-   * GetColSpec is used to get the "cols" spec
-   * @param out PRInt32 aNumValues The number of row sizes specified.
-   * @param out nsFramesetSpec* aSpecs The array of size specifications.
-            This is _not_ owned by the caller, but by the nsIFrameSetElement
-            implementation.  DO NOT DELETE IT.
-   * @exceptions NS_ERROR_OUT_OF_MEMORY
+   * The parsed representation of the "rows" attribute
    */
-  NS_IMETHOD GetColSpec(PRInt32 *aNumValues, const nsFramesetSpec** aSpecs) = 0;
+  nsAutoArrayPtr<nsFramesetSpec>  mRowSpecs; // parsed, non-computed dimensions
+  /**
+   * The parsed representation of the "cols" attribute
+   */
+  nsAutoArrayPtr<nsFramesetSpec>  mColSpecs; // parsed, non-computed dimensions
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIFrameSetElement, NS_IFRAMESETELEMENT_IID)
-
-#endif // nsIFramesetElement_h___
+#endif nsHTMLFrameSetElement_h
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -3047,29 +3047,23 @@ nsHTMLInputElement::SaveState()
   nsresult rv = NS_OK;
 
   nsRefPtr<nsHTMLInputElementState> inputState = nsnull;
 
   switch (mType) {
     case NS_FORM_INPUT_CHECKBOX:
     case NS_FORM_INPUT_RADIO:
       {
-        PRBool checked = GetChecked();
-        PRBool defaultChecked = PR_FALSE;
-        GetDefaultChecked(&defaultChecked);
-        // Only save if checked != defaultChecked (bug 62713)
-        // (always save if it's a radio button so that the checked
-        // state of all radio buttons is restored)
-        if (mType == NS_FORM_INPUT_RADIO || checked != defaultChecked) {
+        if (GetCheckedChanged()) {
           inputState = new nsHTMLInputElementState();
           if (!inputState) {
             return NS_ERROR_OUT_OF_MEMORY;
           }
 
-          inputState->SetChecked(checked);
+          inputState->SetChecked(GetChecked());
         }
         break;
       }
 
     // Never save passwords in session history
     case NS_FORM_INPUT_PASSWORD:
       break;
     case NS_FORM_INPUT_EMAIL:
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -46,16 +46,19 @@ include $(DEPTH)/config/autoconf.mk
 ifdef ENABLE_TESTS
 # This extra subdirectory is needed due to the nature of this test.
 # With the bug, the test loads the base URL of the bug649134/file_*.sjs
 # files, and the mochitest server responds with the contents of index.html if
 # it exists in that case, which we use to detect failure.
 # We can't have index.html in this directory because it would prevent
 # running the tests here.
 DIRS		+= bug649134
+
+# For form-related test suite.
+DIRS		+= forms
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
 		test_hidden.html \
 		test_bug589.html \
 		test_bug691.html \
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/forms/Makefile.in
@@ -0,0 +1,53 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla code.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Mounir Lamouri <mounir.lamouri@mozilla.com> (original author)
+#
+# 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 *****
+
+DEPTH          = ../../../../..
+topsrcdir      = @top_srcdir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+relativesrcdir = content/html/content/test/forms
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = \
+		save_restore_radio_groups.sjs \
+		test_save_restore_radio_groups.html \
+		$(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/forms/save_restore_radio_groups.sjs
@@ -0,0 +1,44 @@
+var pages = [
+  "<!DOCTYPE html>" +
+  "<html><body>" +
+  "<form>" +
+  "<input name='a' type='radio' checked><input name='a' type='radio'><input name='a' type='radio'>" +
+  "</form>" +
+  "</body></html>",
+  "<!DOCTYPE html>" +
+  "<html><body>" +
+  "<form>" +
+  "<input name='a' type='radio'><input name='a' type='radio' checked><input name='a' type='radio'>" +
+  "</form>" +
+  "</body></html>",
+  ];
+
+/**
+ * This SJS is going to send the same page the two first times it will be called
+ * and another page the two following times. After that, the response will have
+ * no content.
+ * The use case is to have two iframes using this SJS and both being reloaded
+ * once.
+ */
+
+function handleRequest(request, response)
+{
+  var counter = +getState("counter"); // convert to number; +"" === 0
+
+  response.setStatusLine(request.httpVersion, 200, "Ok");
+  response.setHeader("Content-Type", "text/html");
+  response.setHeader("Cache-Control", "no-cache");
+
+  switch (counter) {
+    case 0:
+    case 1:
+      response.write(pages[0]);
+      break;
+    case 2:
+    case 3:
+      response.write(pages[1]);
+      break;
+  }
+  setState("counter", "" + ++counter);
+}
+
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/forms/test_save_restore_radio_groups.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=350022
+-->
+<head>
+  <title>Test for Bug 350022</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=350022">Mozilla Bug 350022</a>
+<p id="display"></p>
+<div id="content"><!-- style="display: none">-->
+  <iframe src="save_restore_radio_groups.sjs"></iframe>
+  <iframe src="save_restore_radio_groups.sjs"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 350022 **/
+
+function checkRadioGroup(aFrame, aResults)
+{
+  var radios = frames[aFrame].document.getElementsByTagName('input');
+
+  is(radios.length, aResults.length,
+     "Radio group should have " + aResults.length + "elements");
+
+  for (var i=0; i<aResults.length; ++i) {
+    is(radios[i].checked, aResults[i],
+       "Radio checked state should be " + aResults[i]);
+  }
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  /**
+   * We have two iframes each containing one radio button group.
+   * We are going to change the selected radio button in one group.
+   * Then, both iframes will be reloaded and the new groups will have another
+   * radio checked by default.
+   * For the first group (which had a selection change), nothing should change.
+   * For the second, the selected radio button should change.
+   */
+  checkRadioGroup(0, [true, false, false]);
+  checkRadioGroup(1, [true, false, false]);
+
+  frames[0].document.getElementsByTagName('input')[2].checked = true;
+  checkRadioGroup(0, [false, false, true]);
+
+  framesElts = document.getElementsByTagName('iframe');
+  framesElts[0].addEventListener("load", function() {
+    framesElts[0].removeEventListener("load", arguments.callee, false);
+    checkRadioGroup(0, [false, false, true]);
+
+    framesElts[1].addEventListener("load", function() {
+      framesElts[1].removeEventListener("load", arguments.callee, false);
+
+      checkRadioGroup(1, [false, true, false]);
+      SimpleTest.finish();
+    }, false);
+
+    frames[1].location.reload();
+  }, false);
+
+  frames[0].location.reload();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -916,17 +916,17 @@ nsHTMLDocument::StartDocumentLoad(const 
   if (muCV && !muCVIsParent)
     muCV->SetPrevDocCharacterSet(charset);
 
   if (cachingChan) {
     NS_ASSERTION(charset == parserCharset,
                  "How did those end up different here?  wyciwyg channels are "
                  "not nsICachingChannel");
     rv = cachingChan->SetCacheTokenCachedCharset(charset);
-    NS_ASSERTION(NS_SUCCEEDED(rv),"cannot SetMetaDataElement");
+    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "cannot SetMetaDataElement");
   }
 
   // Set the parser as the stream listener for the document loader...
   if (mParser) {
     rv = mParser->GetStreamListener(aDocListener);
     if (NS_FAILED(rv)) {
       return rv;
     }
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -422,17 +422,17 @@ PRBool nsOggReader::DecodeAudioData()
     // be no more samples.
     mAudioQueue.Finish();
     return PR_FALSE;
   }
 
   return PR_TRUE;
 }
 
-nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket)
+nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket, PRInt64 aTimeThreshold)
 {
   NS_ASSERTION(aPacket->granulepos >= TheoraVersion(&mTheoraState->mInfo,3,2,1),
     "Packets must have valid granulepos and packetno");
 
   int ret = th_decode_packetin(mTheoraState->mCtx, aPacket, 0);
   if (ret != 0 && ret != TH_DUPFRAME) {
     return NS_ERROR_FAILURE;
   }
@@ -442,16 +442,22 @@ nsresult nsOggReader::DecodeTheora(ogg_p
   // start time in the skeleton track. Note we still must submit the frame
   // to the decoder (via th_decode_packetin), as the frames which are
   // presentable may depend on this frame's data.
   if (mSkeletonState && !mSkeletonState->IsPresentable(time)) {
     return NS_OK;
   }
 
   PRInt64 endTime = mTheoraState->Time(aPacket->granulepos);
+  if (endTime < aTimeThreshold) {
+    // The end time of this frame is already before the current playback
+    // position. It will never be displayed, don't bother enqueing it.
+    return NS_OK;
+  }
+
   if (ret == TH_DUPFRAME) {
     VideoData* v = VideoData::CreateDuplicate(mPageOffset,
                                               time,
                                               endTime,
                                               aPacket->granulepos);
     mVideoQueue.Push(v);
   } else if (ret == 0) {
     th_ycbcr_buffer buffer;
@@ -518,17 +524,17 @@ PRBool nsOggReader::DecodeVideoFrame(PRB
   NS_ASSERTION(packet && packet->granulepos != -1,
                 "Must know first packet's granulepos");
   PRBool eos = packet->e_o_s;
   PRInt64 frameEndTime = mTheoraState->Time(packet->granulepos);
   if (!aKeyframeSkip ||
      (th_packet_iskeyframe(packet) && frameEndTime >= aTimeThreshold))
   {
     aKeyframeSkip = PR_FALSE;
-    nsresult res = DecodeTheora(packet);
+    nsresult res = DecodeTheora(packet, aTimeThreshold);
     decoded++;
     if (NS_FAILED(res)) {
       return PR_FALSE;
     }
   }
 
   if (eos) {
     // We've encountered an end of bitstream packet. Inform the queue that
--- a/content/media/ogg/nsOggReader.h
+++ b/content/media/ogg/nsOggReader.h
@@ -226,18 +226,20 @@ private:
 private:
 
   // Decodes a packet of Vorbis data, and inserts its samples into the 
   // audio queue.
   nsresult DecodeVorbis(ogg_packet* aPacket);
 
   // Decodes a packet of Theora data, and inserts its frame into the
   // video queue. May return NS_ERROR_OUT_OF_MEMORY. Caller must have obtained
-  // the reader's monitor.
-  nsresult DecodeTheora(ogg_packet* aPacket);
+  // the reader's monitor. aTimeThreshold is the current playback position
+  // in media time in microseconds. Frames with an end time before this will
+  // not be enqueued.
+  nsresult DecodeTheora(ogg_packet* aPacket, PRInt64 aTimeThreshold);
 
   // Read a page of data from the Ogg file. Returns the offset of the start
   // of the page, or -1 if the page read failed.
   PRInt64 ReadOggPage(ogg_page* aPage);
 
   // Reads and decodes header packets for aState, until either header decode
   // fails, or is complete. Initializes the codec state before returning.
   // Returns PR_TRUE if reading headers and initializtion of the stream
--- a/content/xbl/test/Makefile.in
+++ b/content/xbl/test/Makefile.in
@@ -42,28 +42,24 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/xbl/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =	\
-		test_bug296375.xul \
 		test_bug310107.html \
 		bug310107-resource.xhtml \
 		test_bug366770.html \
 		test_bug371724.xhtml \
 		test_bug372769.xhtml \
-		test_bug378518.xul \
 		test_bug378866.xhtml \
 		test_bug397934.xhtml \
 		test_bug389322.xhtml \
-		test_bug398135.xul \
-		test_bug398492.xul \
 		test_bug400705.xhtml \
 		test_bug401907.xhtml \
 		test_bug403162.xhtml \
 		test_bug379959.html \
 		file_bug379959_data.html \
 		file_bug379959_cross.html \
 		file_bug379959_xbl.xml \
 		test_bug468210.xhtml \
@@ -73,10 +69,21 @@ include $(topsrcdir)/config/rules.mk
 		test_bug526178.xhtml \
 		test_bug542406.xhtml \
 		test_bug591198.html \
 		file_bug591198_xbl.xml \
 		file_bug591198_inner.html \
 		test_bug639338.xhtml \
 		$(NULL)
 
+_CHROME_FILES = \
+		test_bug296375.xul \
+		test_bug378518.xul \
+		test_bug398135.xul \
+		test_bug398492.xul \
+		$(NULL)
+
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
+libs:: $(_CHROME_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
+
--- a/content/xbl/test/test_bug296375.xul
+++ b/content/xbl/test/test_bug296375.xul
@@ -1,21 +1,21 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=296375
 -->
 <window title="Mozilla Bug 296375"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Test for Bug 296375</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="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">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=296375">Mozilla Bug 296375</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
--- a/content/xbl/test/test_bug378518.xul
+++ b/content/xbl/test/test_bug378518.xul
@@ -1,20 +1,20 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=378518
 -->
 <window title="Mozilla Bug 378518"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
     
-  <script type="application/javascript" src="/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
   <script type="application/javascript"
-    src="/tests/SimpleTest/SimpleTest.js"/>
+    src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <bindings xmlns="http://www.mozilla.org/xbl"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
       <binding id="mybinding" extends="xul:checkbox">
           <content>
           </content>
       </binding>
--- a/content/xbl/test/test_bug398135.xul
+++ b/content/xbl/test/test_bug398135.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=398135
 -->
 <window title="Mozilla Bug 398135"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="/MochiKit/packed.js"/>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <script type="application/javascript">window.log = ""</script>
   <bindings xmlns="http://www.mozilla.org/xbl">
     <binding id="ancestor">
       <implementation>
         <constructor>
           window.log += "ancestorConstructor:";
         </constructor>
         <destructor>
--- a/content/xbl/test/test_bug398492.xul
+++ b/content/xbl/test/test_bug398492.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=398492
 -->
 <window title="Mozilla Bug 398492"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <bindings xmlns="http://www.mozilla.org/xbl">
     <binding id="test">
       <content>
         <xul:hbox id="xxx"
             xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
           <children/>
         </xul:hbox>
       </content>
--- a/content/xslt/src/xslt/txEXSLTRegExFunctions.js
+++ b/content/xslt/src/xslt/txEXSLTRegExFunctions.js
@@ -35,57 +35,36 @@
  * 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 ***** */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const EXSLT_REGEXP_CID = Components.ID("{18a03189-067b-4978-b4f1-bafe35292ed6}");
+const EXSLT_REGEXP_CONTRACTID = "@mozilla.org/exslt/regexp;1";
 
-const CATMAN_CONTRACTID = "@mozilla.org/categorymanager;1";
 const NODESET_CONTRACTID = "@mozilla.org/transformiix-nodeset;1";
 
 const Ci = Components.interfaces;
 
 function txEXSLTRegExFunctions()
 {
 }
 
 var SingletonInstance = null;
 
 txEXSLTRegExFunctions.prototype = {
     classID: EXSLT_REGEXP_CID,
 
-    QueryInterface: function(iid) {
-        if (iid.equals(Ci.nsISupports) ||
-            iid.equals(Ci.nsIClassInfo) ||
-            iid.equals(Ci.txIEXSLTRegExFunctions))
-            return this;
-
-        throw Components.results.NS_ERROR_NO_INTERFACE;
-    },
+    QueryInterface: XPCOMUtils.generateQI([Ci.txIEXSLTRegExFunctions]),
 
-    // nsIClassInfo
-    getInterfaces: function(countRef) {
-        var interfaces = [
-            Ci.txIEXSLTRegExFunctions
-        ];
-        countRef.value = interfaces.length;
-
-        return interfaces;
-    },
-
-    getHelperForLanguage: function(language) {
-        return null;
-    },
-
-    implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
-    flags: 0,
-
+    classInfo: XPCOMUtils.generateCI({classID: EXSLT_REGEXP_CID,
+                                      contractID: EXSLT_REGEXP_CONTRACTID,
+                                      interfaces: [Ci.txIEXSLTRegExFunctions]}),
 
     // txIEXSLTRegExFunctions
     match: function(context, str, regex, flags) {
         var nodeset = Components.classes[NODESET_CONTRACTID]
                                 .createInstance(Ci.txINodeSet);
 
         var re = new RegExp(regex, flags);
         var matches = str.match(re);
--- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp
@@ -1073,18 +1073,19 @@ txTransformNotifier::SetOutputDocument(n
 
     // Notify the contentsink that the document is created
     return mObserver->OnDocumentCreated(mDocument);
 }
 
 void
 txTransformNotifier::SignalTransformEnd(nsresult aResult)
 {
-    if (mInTransform || (NS_SUCCEEDED(aResult) &&
-        mScriptElements.Count() > 0 || mPendingStylesheetCount > 0)) {
+    if (mInTransform ||
+        (NS_SUCCEEDED(aResult) &&
+         (mScriptElements.Count() > 0 || mPendingStylesheetCount > 0))) {
         return;
     }
 
     // mPendingStylesheetCount is nonzero at this point only if aResult is an
     // error.  Set it to 0 so we won't reenter this code when we stop the
     // CSSLoader.
     mPendingStylesheetCount = 0;
     mScriptElements.Clear();
--- a/content/xul/content/test/Makefile.in
+++ b/content/xul/content/test/Makefile.in
@@ -39,22 +39,23 @@ DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/xul/content/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-_TEST_FILES = 	test_bug330705-2.xul \
-		test_bug233643.xul \
+_TEST_FILES = 	\
 		test_bug486990.xul \
 		$(NULL)
-	
+
 _CHROME_FILES = \
+		test_bug330705-2.xul \
+		test_bug233643.xul \
  		test_bug398289.html \
  		398289-resource.xul \
  		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_CHROME_FILES)
--- a/content/xul/content/test/test_bug233643.xul
+++ b/content/xul/content/test/test_bug233643.xul
@@ -1,19 +1,19 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml">
         title="Test for Bug 233643">
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=233643
 -->
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <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>
 
   <!-- NOTE: This testcase depends on the patch for bug 366770
        (ability to apply bindings with data: URIs). -->
 
   <!-- The data URI: below corresponds to:
     <?xml version="1.0"?>
     <bindings xmlns="http://www.mozilla.org/xbl"
               xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
--- a/content/xul/content/test/test_bug330705-2.xul
+++ b/content/xul/content/test/test_bug330705-2.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
   title="Test for Bug 330705">
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=330705
 -->
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>         
+  <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">
     <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=330705">Mozilla Bug 330705</a>
     <p id="display">
       <box tabindex="1" style="-moz-user-focus:normal;" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
       <box tabindex="1" style="-moz-user-focus:normal;" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
     </p>
     <div id="content" style="display: none">
       <script class="testbody" type="text/javascript">
--- a/content/xul/document/test/Makefile.in
+++ b/content/xul/document/test/Makefile.in
@@ -39,35 +39,29 @@ DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/xul/document/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-_TEST_FILES	= \
+_CHROME_FILES	= \
 		test_bug311681.xul \
 		test_bug199692.xul \
 		test_bug391002.xul \
 		test_bug403868.xul \
 		test_bug414907.xul \
 		test_bug418216.xul \
 		test_bug445177.xul \
 		test_bug449457.xul \
 		test_bug468176.xul \
-		$(NULL)
-
-_CHROME_FILES = \
 		test_bug583948.xul \
 		window_bug583948.xul \
 		test_bug497875.xul \
-		     bug497875-iframe.xul \
+		bug497875-iframe.xul \
 		test_bug335375.xul \
 		overlay1_bug335375.xul \
 		overlay2_bug335375.xul \
 		$(NULL)
 
-libs:: $(_TEST_FILES)
-	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
-
 libs:: $(_CHROME_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
--- a/content/xul/document/test/test_bug199692.xul
+++ b/content/xul/document/test/test_bug199692.xul
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=199692
 -->
 <window title="Test for Bug 199692"
   id="test_bug199692_xul"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <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>
   <bindings xmlns="http://www.mozilla.org/xbl"
               xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
     <binding id="anon">
       <content>
         <xul:label id="anon-label" value="ANON"/>
       </content>
     </binding>
   </bindings>
--- a/content/xul/document/test/test_bug311681.xul
+++ b/content/xul/document/test/test_bug311681.xul
@@ -1,21 +1,21 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=311681
 -->
 <window title="Mozilla Bug 311681"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Test for Bug 311681</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="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">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=311681">Mozilla Bug 311681</a>
 <script class="testbody" type="text/javascript">
 <![CDATA[
   // Setup script
   SimpleTest.waitForExplicitFinish();
 
--- a/content/xul/document/test/test_bug335375.xul
+++ b/content/xul/document/test/test_bug335375.xul
@@ -1,11 +1,11 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <?xul-overlay href="overlay1_bug335375.xul"?>
 <?xul-overlay href="overlay2_bug335375.xul"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=335375
 -->
 <window title="Mozilla Bug 335375"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         onload="RunTest();">
--- a/content/xul/document/test/test_bug391002.xul
+++ b/content/xul/document/test/test_bug391002.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=391002
 -->
 <window title="Mozilla Bug 391002"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=391002"
      target="_blank">Mozilla Bug 391002</a>
   </body>
 
   <button id="btn1" command="cmd1"/>
--- a/content/xul/document/test/test_bug403868.xul
+++ b/content/xul/document/test/test_bug403868.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=403868
 -->
 <window title="Mozilla Bug 403868"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=403868"
      target="_blank">Mozilla Bug 403868</a>
     <div id="content" style="display: none"/>
   </body>
 
--- a/content/xul/document/test/test_bug414907.xul
+++ b/content/xul/document/test/test_bug414907.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=414907
 -->
 <window title="Mozilla Bug 414907"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <bindings xmlns="http://www.mozilla.org/xbl"
               xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
     <binding id="anon">
     <implementation>
       <constructor>
         <![CDATA[
           var node = this.firstChild;
--- a/content/xul/document/test/test_bug418216.xul
+++ b/content/xul/document/test/test_bug418216.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=418216
 -->
 <window title="Mozilla Bug 418216"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=418216"
      target="_blank">Mozilla Bug 418216</a>
   </body>
 
   <!-- test code goes here -->
--- a/content/xul/document/test/test_bug445177.xul
+++ b/content/xul/document/test/test_bug445177.xul
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=445177
 -->
 <window title="Test for Bug 445177"
   id="test_bug445177_xul"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <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 id="body" xmlns="http://www.w3.org/1999/xhtml">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=445177">Mozilla Bug 445177</a>
 
 
 <hbox id="b1" value="foo"/>
 <hbox id="o1" observes="b1"/>
 
--- a/content/xul/document/test/test_bug449457.xul
+++ b/content/xul/document/test/test_bug449457.xul
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=449457
 -->
 <window title="Mozilla Bug 449457"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="/MochiKit/packed.js" />
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=449457"
      target="_blank">Mozilla Bug 449457</a>
   </body>
 
   <!-- test code goes here -->
--- a/content/xul/document/test/test_bug468176.xul
+++ b/content/xul/document/test/test_bug468176.xul
@@ -1,22 +1,22 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=468176
 -->
 <window title="Test for Bug 468176"
   id="test_bug468176_xul"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <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 id="body" xmlns="http://www.w3.org/1999/xhtml">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=468176">Mozilla Bug 468176</a>
 
 <xul:hbox id="b1" value="foo"/>
 
 <xul:hbox id="o1">
   <xul:observes id="inner" element="b1" attribute="*"/>
--- a/content/xul/templates/tests/Makefile.in
+++ b/content/xul/templates/tests/Makefile.in
@@ -40,19 +40,10 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir = content/xul/templates/tests
 
 include $(DEPTH)/config/autoconf.mk
 
 DIRS = chrome
 
-_TEST_FILES = \
-		test_bug441785.xul \
-		bug441785-1.rdf \
-		bug441785-2.rdf \
-		test_sortservice.xul \
-		$(NULL)
-
 include $(topsrcdir)/config/rules.mk
 
-libs:: $(_TEST_FILES)
-	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/xul/templates/tests/chrome/Makefile.in
+++ b/content/xul/templates/tests/chrome/Makefile.in
@@ -254,12 +254,16 @@ include $(topsrcdir)/config/rules.mk
 		test_tmpl_xmlquerywithsortotherfield.xul \
 		test_tmpl_xmlquerywithmultiplequeries.xul \
 		test_tmpl_xmlquerywithothertypes.xul \
 		test_tmpl_xmlquerywithinlinedata.xul \
 		test_tmpl_xmlquerywithinlinedatawithmultiplequeries.xul \
 		test_tmpl_invalidqp.xul \
 		test_tmpl_errors.xul \
 		test_tmpl_regenerate.xul \
+		test_bug441785.xul \
+		bug441785-1.rdf \
+		bug441785-2.rdf \
+		test_sortservice.xul \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
rename from content/xul/templates/tests/bug441785-1.rdf
rename to content/xul/templates/tests/chrome/bug441785-1.rdf
rename from content/xul/templates/tests/bug441785-2.rdf
rename to content/xul/templates/tests/chrome/bug441785-2.rdf
rename from content/xul/templates/tests/test_bug441785.xul
rename to content/xul/templates/tests/chrome/test_bug441785.xul
--- a/content/xul/templates/tests/test_bug441785.xul
+++ b/content/xul/templates/tests/chrome/test_bug441785.xul
@@ -1,11 +1,11 @@
 <?xml version="1.0" ?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <tree flex="20" id="t" ref="urn:data:row" datasources="rdf:null" seltype="single">
      <treecols> 
       <treecol flex="1" id="id" label="id" sort="rdf:http://dummy/rdf#id" />
       <splitter class="tree-splitter"/>
       <treecol flex="1" id="title" label="title" sort="rdf:http://dummy/rdf#title" sortActive="true" sortDirection="ascending" /><splitter class="tree-splitter"/>
      </treecols>
@@ -35,18 +35,18 @@
            </treerow>
          </treeitem>
        </treechildren>
      </template>
    </tree>
 
 <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
 
-<script type="application/javascript" src="/MochiKit/packed.js"></script>
-<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>      
+<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
 
 <script type="application/x-javascript">
 <![CDATA[
 
 var buildCount = 0;
 
 SimpleTest.waitForExplicitFinish();
 
rename from content/xul/templates/tests/test_sortservice.xul
rename to content/xul/templates/tests/chrome/test_sortservice.xul
--- a/content/xul/templates/tests/test_sortservice.xul
+++ b/content/xul/templates/tests/chrome/test_sortservice.xul
@@ -1,20 +1,20 @@
 <?xml version="1.0" ?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
 <vbox id="box"/>
 
 <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
 
-<script type="application/javascript" src="/MochiKit/packed.js"></script>
-<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>      
+<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
 
 <script type="application/x-javascript">
 <![CDATA[
 
 var tests = [
   [["One", "Two", "Three", "Four"], "", ["Four One Three Two"]],
   [["One", "Two", "Three", "Four"], "integer", ["Four One Three Two"]],
   [["One", "Two", "Three", "Four"], "descending", ["Two Three One Four"]],
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1721,27 +1721,30 @@ NS_IMETHODIMP
 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
 {
     NS_ENSURE_ARG_POINTER(aChromeEventHandler);
     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mChromeEventHandler);
     target.swap(*aChromeEventHandler);
     return NS_OK;
 }
 
-/* [noscript] void setCurrentURI (in nsIURI uri); */
+/* void setCurrentURI (in nsIURI uri); */
 NS_IMETHODIMP
 nsDocShell::SetCurrentURI(nsIURI *aURI)
 {
-    SetCurrentURI(aURI, nsnull, PR_TRUE);
+    // Note that securityUI will set STATE_IS_INSECURE, even if
+    // the scheme of |aURI| is "https".
+    SetCurrentURI(aURI, nsnull, PR_TRUE,
+                  nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
     return NS_OK;
 }
 
 PRBool
 nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
-                          PRBool aFireOnLocationChange)
+                          PRBool aFireOnLocationChange, PRUint32 aLocationFlags)
 {
 #ifdef PR_LOGGING
     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
         nsCAutoString spec;
         if (aURI)
             aURI->GetSpec(spec);
         PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
     }
@@ -1775,17 +1778,17 @@ nsDocShell::SetCurrentURI(nsIURI *aURI, 
        * We don't want to send OnLocationChange notifications when
        * a subframe is being loaded for the first time, while
        * visiting a frameset page
        */
       return PR_FALSE; 
     }
 
     if (aFireOnLocationChange) {
-        FireOnLocationChange(this, aRequest, aURI);
+        FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
     }
     return !aFireOnLocationChange;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetCharset(char** aCharset)
 {
     NS_ENSURE_ARG_POINTER(aCharset);
@@ -3940,16 +3943,20 @@ nsDocShell::DisplayLoadError(nsresult aE
         {
             error.AssignLiteral("remoteXUL");
             break;
         }
         case NS_ERROR_UNSAFE_CONTENT_TYPE:
             // Channel refused to load from an unrecognized content type.
             error.AssignLiteral("unsafeContentType");
             break;
+        case NS_ERROR_CORRUPTED_CONTENT:
+            // Broken Content Detected. e.g. Content-MD5 check failure.
+            error.AssignLiteral("corruptedContentError");
+            break;
         }
     }
 
     // Test if the error should be displayed
     if (error.IsEmpty()) {
         return NS_OK;
     }
 
@@ -5865,17 +5872,18 @@ nsDocShell::OnStateChange(nsIWebProgress
                 }
 
                 // This is a document.write(). Get the made-up url
                 // from the channel and store it in session history.
                 // Pass false for aCloneChildren, since we're creating
                 // a new DOM here.
                 rv = AddToSessionHistory(uri, wcwgChannel, nsnull, PR_FALSE,
                                          getter_AddRefs(mLSHE));
-                SetCurrentURI(uri, aRequest, PR_TRUE);
+                SetCurrentURI(uri, aRequest, PR_TRUE,
+                              nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
                 // Save history state of the previous page
                 rv = PersistLayoutHistoryState();
                 // We'll never get an Embed() for this load, so just go ahead
                 // and SetHistoryEntry now.
                 SetHistoryEntry(&mOSHE, mLSHE);
             }
         
         }
@@ -6119,16 +6127,17 @@ nsDocShell::EndPageLoad(nsIWebProgress *
     //      encoding error.
     //   2. Send the URI to a keyword server (if enabled)
     //   3. If the error was DNS failure, then add www and .com to the URI
     //      (if appropriate).
     //   4. Throw an error dialog box...
     //
     if (url && NS_FAILED(aStatus)) {
         if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
+            aStatus == NS_ERROR_CORRUPTED_CONTENT ||
             aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
             DisplayLoadError(aStatus, url, nsnull, aChannel);
             return NS_OK;
         }
 
         if (sURIFixup) {
             //
             // Try and make an alternative URI from the old one
@@ -6518,17 +6527,18 @@ nsDocShell::CreateAboutBlankContentViewe
       docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
                     blankDoc, "view", getter_AddRefs(viewer));
 
       // hook 'em up
       if (viewer) {
         viewer->SetContainer(static_cast<nsIContentViewerContainer *>(this));
         Embed(viewer, "", 0);
 
-        SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, PR_TRUE);
+        SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, PR_TRUE,
+                      nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
         rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
       }
     }
   }
   mCreatingDocument = PR_FALSE;
 
   // The transient about:blank viewer doesn't have a session history entry.
   SetHistoryEntry(&mOSHE, nsnull);
@@ -7169,17 +7179,18 @@ nsDocShell::RestoreFromHistory()
 
         // Use the uri from the mLSHE we had when we entered this function
         // (which need not match the document's URI if anchors are involved),
         // since that's the history entry we're loading.  Note that if we use
         // origLSHE we don't have to worry about whether the entry in question
         // is still mLSHE or whether it's now mOSHE.
         nsCOMPtr<nsIURI> uri;
         origLSHE->GetURI(getter_AddRefs(uri));
-        SetCurrentURI(uri, document->GetChannel(), PR_TRUE);
+        SetCurrentURI(uri, document->GetChannel(), PR_TRUE,
+                      nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
     }
 
     // This is the end of our CreateContentViewer() replacement.
     // Now we simulate a load.  First, we restore the state of the javascript
     // window object.
     nsCOMPtr<nsPIDOMWindow> privWin =
         do_GetInterface(static_cast<nsIInterfaceRequestor*>(this));
     NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
@@ -7508,17 +7519,18 @@ nsDocShell::CreateContentViewer(const ch
     if (++gNumberOfDocumentsLoading == 1) {
       // Hint to favor performance for the plevent notification mechanism.
       // We want the pages to load as fast as possible even if its means 
       // native messages might be starved.
       FavorPerformanceHint(PR_TRUE, NS_EVENT_STARVATION_DELAY_HINT);
     }
 
     if (onLocationChangeNeeded) {
-      FireOnLocationChange(this, request, mCurrentURI);
+      FireOnLocationChange(this, request, mCurrentURI,
+                           nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
     }
   
     return NS_OK;
 }
 
 nsresult
 nsDocShell::NewContentViewerObj(const char *aContentType,
                                 nsIRequest * request, nsILoadGroup * aLoadGroup,
@@ -8280,22 +8292,24 @@ nsDocShell::InternalLoad(nsIURI * aURI,
 
     if (aLoadType == LOAD_NORMAL ||
         aLoadType == LOAD_STOP_CONTENT ||
         LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
         aLoadType == LOAD_HISTORY ||
         aLoadType == LOAD_LINK) {
 
         // Split mCurrentURI and aURI on the '#' character.  Make sure we read
-        // the return values of SplitURIAtHash; it might fail because
-        // mCurrentURI is null, for instance, and we don't want to allow a
-        // short-circuited navigation in that case.
+        // the return values of SplitURIAtHash; if it fails, we don't want to
+        // allow a short-circuited navigation.
         nsCAutoString curBeforeHash, curHash, newBeforeHash, newHash;
         nsresult splitRv1, splitRv2;
-        splitRv1 = nsContentUtils::SplitURIAtHash(mCurrentURI, curBeforeHash, curHash);
+        splitRv1 = mCurrentURI ?
+            nsContentUtils::SplitURIAtHash(mCurrentURI,
+                                           curBeforeHash, curHash) :
+            NS_ERROR_FAILURE;
         splitRv2 = nsContentUtils::SplitURIAtHash(aURI, newBeforeHash, newHash);
 
         PRBool sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
                                   NS_SUCCEEDED(splitRv2) &&
                                   curBeforeHash.Equals(newBeforeHash);
 
         PRBool sameDocIdent = PR_FALSE;
         if (mOSHE && aSHEntry) {
@@ -8348,21 +8362,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
             nscoord cx = 0, cy = 0;
             GetCurScrollPos(ScrollOrientation_X, &cx);
             GetCurScrollPos(ScrollOrientation_Y, &cy);
 
             // We scroll whenever we're not doing a history load.  Note that
             // sometimes we might scroll even if we don't fire a hashchange
             // event!  See bug 653741.
             if (!aSHEntry) {
-                // Take the '#' off the hashes before passing them to
-                // ScrollToAnchor.
-                nsDependentCSubstring curHashName(curHash, 1);
-                nsDependentCSubstring newHashName(newHash, 1);
-                rv = ScrollToAnchor(curHashName, newHashName, aLoadType);
+                rv = ScrollToAnchor(curHash, newHash, aLoadType);
                 NS_ENSURE_SUCCESS(rv, rv);
             }
 
             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
@@ -8377,16 +8387,21 @@ nsDocShell::InternalLoad(nsIURI * aURI,
              */
             nsCOMPtr<nsISupports> owner;
             if (mOSHE) {
                 mOSHE->GetOwner(getter_AddRefs(owner));
             }
             // Pass true for aCloneSHChildren, since we're not
             // changing documents here, so all of our subframes are
             // still relevant to the new session history entry.
+            //
+            // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
+            // flag on firing onLocationChange(...).
+            // Anyway, aCloneSHChildren param is simply reflecting
+            // doShortCircuitedLoad in this scope.
             OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE, PR_TRUE, PR_TRUE);
 
             nsCOMPtr<nsIInputStream> postData;
             PRUint64 docIdent = PRUint64(-1);
             nsCOMPtr<nsISupports> cacheKey;
 
             if (mOSHE) {
                 /* save current position of scroller(s) (bug 59774) */
@@ -9147,26 +9162,30 @@ nsDocShell::ScrollToAnchor(nsACString & 
     // current anchor and we are doing a history load.  So return if we have no
     // new anchor, and there is no current anchor or the load is not a history
     // load.
     if ((aCurHash.IsEmpty() || aLoadType != LOAD_HISTORY) &&
         aNewHash.IsEmpty()) {
         return NS_OK;
     }
 
+    // Take the '#' off aNewHash to get the ref name.  (aNewHash might be empty,
+    // but that's fine.)
+    nsDependentCSubstring newHashName(aNewHash, 1);
+
     // Both the new and current URIs refer to the same page. We can now
     // browse to the hash stored in the new URI.
 
-    if (!aNewHash.IsEmpty()) {
+    if (!newHashName.IsEmpty()) {
         // anchor is there, but if it's a load from history,
         // we don't have any anchor jumping to do
         PRBool scroll = aLoadType != LOAD_HISTORY &&
                         aLoadType != LOAD_RELOAD_NORMAL;
 
-        char *str = ToNewCString(aNewHash);
+        char *str = ToNewCString(newHashName);
         if (!str) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
 
         // nsUnescape modifies the string that is passed into it.
         nsUnescape(str);
 
         // We assume that the bytes are in UTF-8, as it says in the
@@ -9198,17 +9217,17 @@ nsDocShell::ScrollToAnchor(nsACString & 
             nsCOMPtr<nsITextToSubURI> textToSubURI =
                 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
             NS_ENSURE_SUCCESS(rv, rv);
 
             // Unescape and convert to unicode
             nsXPIDLString uStr;
 
             rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
-                                                  PromiseFlatCString(aNewHash).get(),
+                                                  PromiseFlatCString(newHashName).get(),
                                                   getter_Copies(uStr));
             NS_ENSURE_SUCCESS(rv, rv);
 
             // Ignore return value of GoToAnchor, since it will return an error
             // if there is no such anchor in the document, which is actually a
             // success condition for us (we want to update the session history
             // with the new URI no matter whether we actually scrolled
             // somewhere).
@@ -9438,32 +9457,38 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
                 (void)NS_GetReferrerFromChannel(aChannel,
                                                 getter_AddRefs(referrer));
 
                 AddURIVisit(aURI, referrer, previousURI, previousFlags);
             }
         }
     }
 
-    // If this was a history load, update the index in 
-    // SH. 
-    if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) {
+    // If this was a history load or a refresh,
+    // update the index in SH. 
+    if (rootSH && (mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD))) {
         nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
         if (shInternal) {
             rootSH->GetIndex(&mPreviousTransIndex);
             shInternal->UpdateIndex();
             rootSH->GetIndex(&mLoadedTransIndex);
 #ifdef DEBUG_PAGE_CACHE
             printf("Previous index: %d, Loaded index: %d\n\n",
                    mPreviousTransIndex, mLoadedTransIndex);
 #endif
         }
     }
+
+    // aCloneSHChildren exactly means "we are not loading a new document".
+    PRUint32 locationFlags = aCloneSHChildren?
+        PRUint32(nsIWebProgressListener2::LOCATION_CHANGE_SAME_DOCUMENT) :
+        PRUint32(nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
     PRBool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
-                                                  aFireOnLocationChange);
+                                                  aFireOnLocationChange,
+                                                  locationFlags);
     // Make sure to store the referrer from the channel, if any
     SetupReferrerFromChannel(aChannel);
     return onLocationChangeNeeded;
 }
 
 PRBool
 nsDocShell::OnLoadingSite(nsIChannel * aChannel, PRBool aFireOnLocationChange,
                           PRBool aAddToGlobalHistory)
@@ -9757,18 +9782,25 @@ nsDocShell::AddState(nsIVariant *aData, 
 
     // Step 6: If the document's URI changed, update document's URI and update
     // global history.
     //
     // We need to call FireOnLocationChange so that the browser's address bar
     // gets updated and the back button is enabled, but we only need to
     // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
     // since SetCurrentURI will call FireOnLocationChange for us.
+    //
+    // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
+    // nsnull for aRequest param to FireOnLocationChange(...). Such an update
+    // notification is allowed only when we know docshell is not loading a new
+    // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
+    // FireOnLocationChange(...) breaks security UI.
     if (!equalURIs) {
-        SetCurrentURI(newURI, nsnull, PR_TRUE);
+        SetCurrentURI(newURI, nsnull, PR_TRUE,
+                      nsIWebProgressListener2::LOCATION_CHANGE_SAME_DOCUMENT);
         document->SetDocumentURI(newURI);
 
         AddURIVisit(newURI, oldURI, oldURI, 0);
 
         // AddURIVisit doesn't set the title for the new URI in global history,
         // so do that here.
         if (mUseGlobalHistory) {
             nsCOMPtr<IHistory> history = services::GetHistoryService();
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -89,17 +89,17 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptGlobalObjectOwner.h"
 #include "nsISHistory.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIStringBundle.h"
 #include "nsISupportsArray.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebPageDescriptor.h"
-#include "nsIWebProgressListener.h"
+#include "nsIWebProgressListener2.h"
 #include "nsISHContainer.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDocShellHistory.h"
 #include "nsIURIFixup.h"
 #include "nsIWebBrowserFind.h"
 #include "nsIHttpChannel.h"
 #include "nsDocShellTransferableHooks.h"
 #include "nsIAuthPromptProvider.h"
@@ -263,20 +263,23 @@ public:
     // ForceRefreshURI method on nsIRefreshURI, but makes sure to take
     // the timer involved out of mRefreshURIList if it's there.
     // aTimer must not be null.
     nsresult ForceRefreshURIFromTimer(nsIURI * aURI, PRInt32 aDelay,
                                       PRBool aMetaRefresh, nsITimer* aTimer);
 
     friend class OnLinkClickEvent;
 
-    // We need dummy OnLocationChange in some cases to update the UI.
+    // We need dummy OnLocationChange in some cases to update the UI without
+    // updating security info.
     void FireDummyOnLocationChange()
     {
-      FireOnLocationChange(this, nsnull, mCurrentURI);
+        FireOnLocationChange
+            (this, nsnull, mCurrentURI, 
+             nsIWebProgressListener2::LOCATION_CHANGE_SAME_DOCUMENT);
     }
 
     nsresult HistoryTransactionRemoved(PRInt32 aIndex);
 protected:
     // Object Management
     virtual ~nsDocShell();
     virtual void DestroyChildren();
 
@@ -587,17 +590,18 @@ protected:
                                  nsIDocShellTreeItem* aTargetTreeItem);
 
     // 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 SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
-                         PRBool aFireOnLocationChange);
+                         PRBool aFireOnLocationChange,
+                         PRUint32 aLocationFlags);
 
     // The following methods deal with saving and restoring content viewers
     // in session history.
 
     // mContentViewer points to the current content viewer associated with
     // this docshell.  When loading a new document, the content viewer is
     // either destroyed or stored into a session history entry.  To make sure
     // that destruction happens in a controlled fashion, a given content viewer
--- a/docshell/resources/content/netError.xhtml
+++ b/docshell/resources/content/netError.xhtml
@@ -324,16 +324,17 @@
         <h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1>
         <h1 id="et_contentEncodingError">&contentEncodingError.title;</h1>
         <h1 id="et_unsafeContentType">&unsafeContentType.title;</h1>
         <h1 id="et_nssFailure2">&nssFailure2.title;</h1>
         <h1 id="et_nssBadCert">&nssBadCert.title;</h1>
         <h1 id="et_malwareBlocked">&malwareBlocked.title;</h1>
         <h1 id="et_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.title;</h1>
         <h1 id="et_remoteXUL">&remoteXUL.title;</h1>
+        <h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
       </div>
       <div id="errorDescriptionsContainer">
         <div id="ed_generic">&generic.longDesc;</div>
         <div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
         <div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
         <div id="ed_malformedURI">&malformedURI.longDesc;</div>
         <div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div>
         <div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
@@ -348,16 +349,17 @@
         <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div>
         <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
         <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
         <div id="ed_nssFailure2">&nssFailure2.longDesc;</div>
         <div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
         <div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div>
         <div id="ed_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.longDesc;</div>
         <div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
+        <div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
       </div>
     </div>
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer">
     
       <!-- Error Title -->
       <div id="errorTitle">
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -711,33 +711,45 @@ nsSHistory::EvictAllContentViewers()
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsSHistory::GetCanGoBack(PRBool * aCanGoBack)
 {
   NS_ENSURE_ARG_POINTER(aCanGoBack);
   *aCanGoBack = PR_FALSE;
 
+  // If there is already a pending navigation, we cannot go back.
   PRInt32 index = -1;
+  NS_ENSURE_SUCCESS(GetRequestedIndex(&index), NS_ERROR_FAILURE);
+
+  if(index != -1)
+    return NS_OK;
+
   NS_ENSURE_SUCCESS(GetIndex(&index), NS_ERROR_FAILURE);
   if(index > 0)
      *aCanGoBack = PR_TRUE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHistory::GetCanGoForward(PRBool * aCanGoForward)
 {
   NS_ENSURE_ARG_POINTER(aCanGoForward);
   *aCanGoForward = PR_FALSE;
 
+  // If there is already a pending navigation, we cannot go forward.
   PRInt32 index = -1;
   PRInt32 count = -1;
 
+  NS_ENSURE_SUCCESS(GetRequestedIndex(&index), NS_ERROR_FAILURE);
+
+  if(index != -1)
+    return NS_OK;
+
   NS_ENSURE_SUCCESS(GetIndex(&index), NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(GetCount(&count), NS_ERROR_FAILURE);
 
   if((index >= 0) && (index < (count - 1)))
     *aCanGoForward = PR_TRUE;
 
   return NS_OK;
 }
--- a/docshell/test/Makefile.in
+++ b/docshell/test/Makefile.in
@@ -104,16 +104,18 @@ include $(topsrcdir)/config/rules.mk
 		test_bug653741.html \
 		file_bug653741.html \
 		test_framedhistoryframes.html \
 		test_windowedhistoryframes.html \
 		historyframes.html \
 		test_bug660404.html \
 		file_bug660404 \
 		file_bug660404^headers^ \
+		test_bug662170.html \
+		file_bug662170.html \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 _TEST_FILES += \
 		test_bug511449.html \
 		file_bug511449.html \
 		$(NULL)
 endif
--- a/docshell/test/browser/browser_bug554155.js
+++ b/docshell/test/browser/browser_bug554155.js
@@ -1,14 +1,16 @@
 function test() {
   waitForExplicitFinish();
 
   let tab = gBrowser.addTab("http://example.com");
 
-  tab.linkedBrowser.addEventListener('load', function() {
+  tab.linkedBrowser.addEventListener("load", function() {
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+
     let numLocationChanges = 0;
 
     let listener = {
       onLocationChange: function() {
         numLocationChanges++;
       }
     };
 
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/662200a.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>A</title>
+  </head>
+  <body>
+  <a id="link" href="662200b.html">Next</a>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/662200b.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>B</title>
+  </head>
+  <body>
+  <a id="link" href="662200c.html">Next</a>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/662200c.html
@@ -0,0 +1,7 @@
+<html>
+  <head>
+    <title>C</title>
+  </head>
+  <body>
+  </body>
+</html>
--- a/docshell/test/chrome/Makefile.in
+++ b/docshell/test/chrome/Makefile.in
@@ -104,16 +104,21 @@ include $(topsrcdir)/config/rules.mk
 		bug608669.xul \
 		test_bug449778.xul \
 		bug449778_window.xul \
 		test_bug449780.xul \
 		bug449780_window.xul \
 		test_bug454235.xul \
 		bug454235-subframe.xul \
 		test_bug456980.xul \
+		test_bug662200.xul \
+		bug662200_window.xul \
+		662200a.html \
+		662200b.html \
+		662200c.html \
 		$(NULL)
 
 _DOCSHELL_SUBHARNESS = \
     docshell_helpers.js \
     generic.html \
     $(NULL)
 
 libs:: $(_HTTP_FILES)
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/bug662200_window.xul
@@ -0,0 +1,129 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window id="303267Test"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        width="600"
+        height="600"
+        onload="setTimeout(nextTest,0);"
+        title="bug 662200 test">
+
+  <script type="application/javascript"
+  src="docshell_helpers.js">
+  </script>
+  <script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
+  <script type="application/javascript"><![CDATA[
+  
+    // Define the generator-iterator for the tests.
+    var tests = testIterator();
+
+    ////
+    // Execute the next test in the generator function.
+    //
+    function nextTest() {
+      tests.next();
+    }
+
+    ////
+    // Generator function for test steps for bug 662200:  
+    // Description goes here.
+    //
+    function testIterator()
+    {
+      // Load the first test page
+      var navData = {
+        uri: getHttpUrl("662200a.html"),
+        eventsToListenFor: ["pageshow"],
+        expectedEvents: [ {type: "pageshow", title: "A"} ],
+        onNavComplete: nextTest
+      };
+      doPageNavigation(navData);
+      yield;
+      
+      // Load the second test page.
+      navData = {
+        eventsToListenFor: ["pageshow", "pagehide"],
+        expectedEvents: [ {type: "pagehide", 
+                           title: "A"},
+                          {type: "pageshow", 
+                           title: "B"} ],
+        onNavComplete: nextTest
+      }
+      waitForPageEvents(navData);
+      var link = TestWindow.getDocument().getElementById("link");
+      var event = TestWindow.getDocument().createEvent("MouseEvents");
+      event.initMouseEvent("click", true, true, TestWindow.getWindow(),
+                           0, 0, 0, 0, 0, false, false, false, false, 0, null);
+      link.dispatchEvent(event);
+      yield;
+
+      // Load the third test page.
+      navData = {
+        eventsToListenFor: ["pageshow", "pagehide"],
+        expectedEvents: [ {type: "pagehide", 
+                           title: "B"},
+                          {type: "pageshow", 
+                           title: "C"} ],
+        onNavComplete: nextTest
+      };
+      waitForPageEvents(navData);
+      var link = TestWindow.getDocument().getElementById("link");
+      var event = TestWindow.getDocument().createEvent("MouseEvents");
+      event.initMouseEvent("click", true, true, TestWindow.getWindow(),
+                           0, 0, 0, 0, 0, false, false, false, false, 0, null);
+      link.dispatchEvent(event);
+      yield;
+      
+      // Go back.
+      navData = {
+        back: true,
+        eventsToListenFor: ["pageshow", "pagehide"],
+        expectedEvents: [ {type: "pagehide", 
+                           title: "C"},
+                          {type: "pageshow", 
+                           title: "B"} ],
+        onNavComplete: nextTest
+      };
+      doPageNavigation(navData);
+      yield;
+
+      var Ci = Components.interfaces;
+      var docshell = TestWindow.getWindow()
+                               .QueryInterface(Ci.nsIInterfaceRequestor)
+                               .getInterface(Ci.nsIWebNavigation)
+                               .QueryInterface(Ci.nsIDocShell);
+      var shistory = docshell.QueryInterface(Ci.nsIInterfaceRequestor)
+                             .getInterface(Ci.nsISHistory)
+                             .QueryInterface(Ci.nsIWebNavigation);
+
+      // Reload.
+      navData = {
+        eventsToListenFor: ["pageshow", "pagehide"],
+        expectedEvents: [ {type: "pagehide", 
+                           title: "B"},
+                          {type: "pageshow", 
+                           title: "B"} ],
+        onNavComplete: nextTest
+      };
+      // Asking the docshell harness to reload for us will call reload on
+      // nsDocShell which has different behavior than the reload on nsSHistory
+      // so we call reload explicitly here
+      waitForPageEvents(navData);
+      shistory.reload(0);
+      yield;
+
+      // After this sequence of events, we should be able to go back and forward
+      is(TestWindow.getBrowser().canGoBack, true, "Should be able to go back!");
+      is(TestWindow.getBrowser().canGoForward, true, "Should be able to go forward!");
+      is(shistory.requestedIndex, -1, "Requested index should be cleared!");
+
+      // Tell the framework the test is finished.  Include the final 'yield' 
+      // statement to prevent a StopIteration exception from being thrown.
+      finish();
+      yield;
+    }
+    
+  ]]></script>
+
+  <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+</window>
--- a/docshell/test/chrome/docshell_helpers.js
+++ b/docshell/test/chrome/docshell_helpers.js
@@ -36,16 +36,18 @@ var gExtractedPath = null;    //used to 
  * object with the following properties:
  * 
  *                uri: if !undefined, the browser will navigate to this uri
  *
  *               back: if true, the browser will execute goBack()
  *
  *            forward: if true, the browser will execute goForward()
  *
+ *             reload: if true, the browser will execute reload()
+ *
  *  eventsToListenFor: an array containing one or more of the following event  
  *                     types to listen for:  "pageshow", "pagehide", "onload",
  *                     "onunload".  If this property is undefined, only a 
  *                     single "pageshow" events will be listened for.  If this 
  *                     property is explicitly empty, [], then no events will 
  *                     be listened for.
  *
  *     expectedEvents: an array of one or more expectedEvent objects, 
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/test_bug662200.xul
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+  href="chrome://mochikit/content/tests/SimpleTest/test.css"
+  type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=662200.xul
+-->
+<window title="Mozilla Bug 662200"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <title>Test for Bug 662200</title>
+  <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">
+<a target="_blank"
+   href="https://bugzilla.mozilla.org/show_bug.cgi?id=662200">
+   Mozilla Bug 662200</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 662200 **/
+
+SimpleTest.waitForExplicitFinish();
+window.open("bug662200_window.xul", "bug662200",
+            "chrome,width=600,height=600");
+
+]]>
+</script>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug662170.html
@@ -0,0 +1,13 @@
+<html>
+<body onload='(parent || opener).childLoad()'>
+
+<div style='height:500px; background:yellow'>
+<a id='#top'>Top of the page</a>
+</div>
+
+<div id='bottom'>
+<a id='#bottom'>Bottom of the page</a>
+</div>
+
+</body>
+</html>
--- a/docshell/test/navigation/browser_bug343515.js
+++ b/docshell/test/navigation/browser_bug343515.js
@@ -9,32 +9,24 @@ var ctx = {};
 // Helper function to check if a window is active
 function isActive(aWindow) {
   var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIWebNavigation)
                         .QueryInterface(Ci.nsIDocShell);
   return docshell.isActive;
 }
 
-// Returns a closure that will remove itself as a listener from
-// aElem and then call aCallback. aCallback is executed asynchronously,
-// which is handy because load events fire before mIsDocumentLoaded is actually
-// set to true. :(
-function autoRemovedListener(aElem, aType, aCallback) {
+function oneShotListener(aElem, aType, aCallback) {
+  aElem.addEventListener(aType, function () {
+    aElem.removeEventListener(aType, arguments.callee, true);
 
-  var elem = aElem;
-  var type = aType;
-  var callback = aCallback;
-
-  function remover() {
-    elem.removeEventListener(type, remover, true);
-    executeSoon(callback);
-  }
-
-  return remover;
+    // aCallback is executed asynchronously, which is handy because load
+    // events fire before mIsDocumentLoaded is actually set to true. :(
+    executeSoon(aCallback);
+  }, true);
 }
 
 // Returns a closure that iteratively (BFS) waits for all
 // of the descendant frames of aInitialWindow to finish loading,
 // then calls aFinalCallback.
 function frameLoadWaiter(aInitialWindow, aFinalCallback) {
 
   // The window we're currently waiting on
@@ -53,17 +45,17 @@ function frameLoadWaiter(aInitialWindow,
       waitQueue.push(curr.frames[i]);
 
     // Handle the next window in the queue
     if (waitQueue.length >= 1) {
       curr = waitQueue.shift();
       if (curr.document.readyState == "complete")
         frameLoadCallback();
       else
-        curr.addEventListener("load", autoRemovedListener(curr, "load", frameLoadCallback), true);
+        oneShotListener(curr, "load", frameLoadCallback);
       return;
     }
 
     // Otherwise, we're all done. Call the final callback
     finalCallback();
   }
 
   return frameLoadCallback;
@@ -88,19 +80,17 @@ function step1() {
 
   // Our current tab should be active
   ok(isActive(ctx.tab0Window), "Tab 0 should be active at test start");
 
   // Open a New Tab
   ctx.tab1 = gBrowser.addTab(testPath + "bug343515_pg1.html");
   ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1);
   ctx.tab1Window = ctx.tab1Browser.contentWindow;
-  ctx.tab1Browser.addEventListener("load",
-                                   autoRemovedListener(ctx.tab1Browser, "load", step2),
-                                   true);
+  oneShotListener(ctx.tab1Browser, "load", step2);
 }
 
 function step2() {
 
   // Our current tab should still be active
   ok(isActive(ctx.tab0Window), "Tab 0 should still be active");
   ok(!isActive(ctx.tab1Window), "Tab 1 should not be active");
 
@@ -110,40 +100,34 @@ function step2() {
   // Tab 1 should now be active
   ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
   ok(isActive(ctx.tab1Window), "Tab 1 should be active");
 
   // Open another tab
   ctx.tab2 = gBrowser.addTab(testPath + "bug343515_pg2.html");
   ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2);
   ctx.tab2Window = ctx.tab2Browser.contentWindow;
-  ctx.tab2Browser.addEventListener("load",
-                                   autoRemovedListener(ctx.tab2Browser, "load",
-                                                       frameLoadWaiter(ctx.tab2Window, step3)),
-                                   true);
+  oneShotListener(ctx.tab2Browser, "load", frameLoadWaiter(ctx.tab2Window, step3));
 }
 
 function step3() {
 
   // Tab 0 should be inactive, Tab 1 should be active
   ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
   ok(isActive(ctx.tab1Window), "Tab 1 should be active");
 
   // Tab 2's window _and_ its iframes should be inactive
   ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
   is(ctx.tab2Window.frames.length, 2, "Tab 2 should have 2 iframes");
   ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
   ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
 
   // Navigate tab 2 to a different page
   ctx.tab2Window.location = testPath + "bug343515_pg3.html";
-  ctx.tab2Browser.addEventListener("load",
-                                  autoRemovedListener(ctx.tab2Browser, "load",
-                                                      frameLoadWaiter(ctx.tab2Window, step4)),
-                                  true);
+  oneShotListener(ctx.tab2Browser, "load", frameLoadWaiter(ctx.tab2Window, step4));
 }
 
 function step4() {
 
   // Tab 0 should be inactive, Tab 1 should be active
   ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
   ok(isActive(ctx.tab1Window), "Tab 1 should be active");
 
@@ -162,20 +146,17 @@ function step4() {
   ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
   ok(!isActive(ctx.tab1Window), "Tab 1 should be inactive");
   ok(isActive(ctx.tab2Window), "Tab 2 should be active");
   ok(isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be active");
   ok(isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be active");
   ok(isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be active");
 
   // Go back
-  ctx.tab2Browser.addEventListener("pageshow",
-                                   autoRemovedListener(ctx.tab2Browser, "pageshow",
-                                                       frameLoadWaiter(ctx.tab2Window, step5)),
-                                   true);
+  oneShotListener(ctx.tab2Browser, "pageshow", frameLoadWaiter(ctx.tab2Window, step5));
   ctx.tab2Browser.goBack();
 
 }
 
 function step5() {
 
   // Check everything
   ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
@@ -184,39 +165,33 @@ function step5() {
   ok(isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be active");
   ok(isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be active");
 
   // Switch to tab 1
   gBrowser.selectedTab = ctx.tab1;
 
   // Navigate to page 3
   ctx.tab1Window.location = testPath + "bug343515_pg3.html";
-  ctx.tab1Browser.addEventListener("load",
-                                   autoRemovedListener(ctx.tab1Browser, "load",
-                                                       frameLoadWaiter(ctx.tab1Window, step6)),
-                                   true);
+  oneShotListener(ctx.tab1Browser, "load", frameLoadWaiter(ctx.tab1Window, step6));
 }
 
 function step6() {
 
   // Check everything
   ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
   ok(isActive(ctx.tab1Window), "Tab 1 should be active");
   ok(isActive(ctx.tab1Window.frames[0]), "Tab1 iframe 0 should be active");
   ok(isActive(ctx.tab1Window.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active");
   ok(isActive(ctx.tab1Window.frames[1]), "Tab1 iframe 1 should be active");
   ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
   ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
   ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
 
   // Go forward on tab 2
-  ctx.tab2Browser.addEventListener("pageshow",
-                                   autoRemovedListener(ctx.tab2Browser, "pageshow",
-                                                       frameLoadWaiter(ctx.tab2Window, step7)),
-                                   true);
+  oneShotListener(ctx.tab2Browser, "pageshow", frameLoadWaiter(ctx.tab2Window, step7));
   var tab2docshell = ctx.tab2Window.QueryInterface(Ci.nsIInterfaceRequestor)
                                    .getInterface(Ci.nsIWebNavigation);
   tab2docshell.goForward();
 }
 
 function step7() {
 
   ctx.tab2Window = ctx.tab2Browser.contentWindow;
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug662170.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=662170
+-->
+<head>
+  <title>Test for Bug 662170</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.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=662170">Mozilla Bug 662170</a>
+
+<script type="application/javascript;version=1.7">
+
+/** Test for Bug 662170 **/
+SimpleTest.waitForExplicitFinish();
+
+function childLoad() {
+  // Spin the event loop so we leave the onload handler.
+  SimpleTest.executeSoon(childLoad2);
+}
+
+function childLoad2() {
+  let cw = $('iframe').contentWindow;
+
+  // When we initially load the page, we should be at the top.
+  is(cw.pageYOffset, 0, 'Initial Y offset should be 0.');
+  
+  // Scroll the iframe to the bottom.
+  cw.scrollTo(0, 300);
+
+  // Did we actually scroll somewhere?
+  isnot(cw.pageYOffset, 0, 'Y offset should be non-zero after scrolling.');
+
+  // Now load file_bug662170.html#, which should take us to the top of the
+  // page.
+  cw.location = cw.location + '#';
+
+  is(cw.pageYOffset, 0, 'Correct Y offset after loading #.');
+  SimpleTest.finish();
+}
+
+</script>
+
+<!-- When the iframe loads, it calls childLoad(). -->
+<iframe height='100px' id='iframe' src='file_bug662170.html'></iframe>
+
+</body>
+</html>
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8661,17 +8661,17 @@ nsGlobalWindow::OpenInternal(const nsASt
   if (!chrome) {
     // No chrome means we don't want to go through with this open call
     // -- see nsIWindowWatcher.idl
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ASSERTION(mDocShell, "Must have docshell here");
 
-  const PRBool checkForPopup =
+  const PRBool checkForPopup = !nsContentUtils::IsCallerChrome() &&
     !aDialog && !WindowExists(aName, !aCalledNoScript);
 
   // Note: it's very important that this be an nsXPIDLCString, since we want
   // .get() on it to return nsnull until we write stuff to it.  The window
   // watcher expects a null URL string if there is no URL to load.
   nsXPIDLCString url;
   nsresult rv = NS_OK;
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1004,17 +1004,17 @@ nsJSContext::JSOptionChangedCallback(con
   ::JS_SetOptions(context->mContext, newDefaultJSOptions & JSRUNOPTION_MASK);
 
   // Save the new defaults for the next page load (InitContext).
   context->mDefaultJSOptions = newDefaultJSOptions;
 
 #ifdef JS_GC_ZEAL
   PRInt32 zeal = Preferences::GetInt(js_zeal_option_str, -1);
   if (zeal >= 0)
-    ::JS_SetGCZeal(context->mContext, (PRUint8)zeal);
+    ::JS_SetGCZeal(context->mContext, (PRUint8)zeal, JS_DEFAULT_ZEAL_FREQ, JS_FALSE);
 #endif
 
   return 0;
 }
 
 nsJSContext::nsJSContext(JSRuntime *aRuntime)
   : mGCOnDestruction(PR_TRUE),
     mExecuteDepth(0)
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -98,17 +98,17 @@ ConvertCloneBuffersToArrayInternal(
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     jsint count = jsint(aBuffers.Length());
     for (jsint index = 0; index < count; index++) {
       JSAutoStructuredCloneBuffer& buffer = aBuffers[index];
 
       jsval val;
-      if (!buffer.read(&val, aCx)) {
+      if (!IDBObjectStore::DeserializeValue(aCx, buffer, &val)) {
         NS_WARNING("Failed to decode!");
         return NS_ERROR_DOM_DATA_CLONE_ERR;
       }
 
       if (!JS_SetElement(aCx, array, index, &val)) {
         NS_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
@@ -488,45 +488,16 @@ AsyncConnectionHelper::WrapNative(JSCont
     nsContentUtils::WrapNative(aCx, global, aNative, aResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 // static
 nsresult
-AsyncConnectionHelper::ConvertCloneBufferToJSVal(
-                                           JSContext* aCx,
-                                           JSAutoStructuredCloneBuffer& aBuffer,
-                                           jsval* aResult)
-{
-  NS_ASSERTION(aCx, "Null context!");
-  NS_ASSERTION(aResult, "Null pointer!");
-
-  JSAutoRequest ar(aCx);
-
-  if (aBuffer.data()) {
-    JSBool ok = aBuffer.read(aResult, aCx);
-
-    aBuffer.clear(aCx);
-
-    if (!ok) {
-      NS_ERROR("Failed to decode!");
-      return NS_ERROR_DOM_DATA_CLONE_ERR;
-    }
-  }
-  else {
-    *aResult = JSVAL_VOID;
-  }
-
-  return NS_OK;
-}
-
-// static
-nsresult
 AsyncConnectionHelper::ConvertCloneBuffersToArray(
                                 JSContext* aCx,
                                 nsTArray<JSAutoStructuredCloneBuffer>& aBuffers,
                                 jsval* aResult)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aResult, "Null pointer!");
 
--- a/dom/indexedDB/AsyncConnectionHelper.h
+++ b/dom/indexedDB/AsyncConnectionHelper.h
@@ -161,24 +161,16 @@ protected:
    * Helper to wrap a native into a jsval. Uses the global object of the request
    * to parent the native.
    */
   nsresult WrapNative(JSContext* aCx,
                       nsISupports* aNative,
                       jsval* aResult);
 
   /**
-   * Helper to decode a clone buffer to a jsval.
-   */
-  static nsresult ConvertCloneBufferToJSVal(
-                                           JSContext* aCx,
-                                           JSAutoStructuredCloneBuffer& aBuffer,
-                                           jsval* aResult);
-
-  /**
    * Helper to make a JS array object out of an array of clone buffers.
    */
   static nsresult ConvertCloneBuffersToArray(
                                 JSContext* aCx,
                                 nsTArray<JSAutoStructuredCloneBuffer>& aBuffers,
                                 jsval* aResult);
 
 protected:
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -465,19 +465,17 @@ IDBCursor::GetValue(JSContext* aCx,
   }
 
   if (!mHaveCachedValue) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBCursor);
       mRooted = true;
     }
 
-    JSAutoRequest ar(aCx);
-
-    if (!mCloneBuffer.read(&mCachedValue, aCx)) {
+    if (!IDBObjectStore::DeserializeValue(aCx, mCloneBuffer, &mCachedValue)) {
       mCachedValue = JSVAL_VOID;
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
 
     mCloneBuffer.clear(aCx);
     mHaveCachedValue = true;
   }
 
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -775,21 +775,21 @@ GetHelper::DoDatabaseWork(mozIStorageCon
 
   return NS_OK;
 }
 
 nsresult
 GetHelper::GetSuccessResult(JSContext* aCx,
                             jsval* aVal)
 {
-  nsresult rv = ConvertCloneBufferToJSVal(aCx, mCloneBuffer, aVal);
+  bool result = IDBObjectStore::DeserializeValue(aCx, mCloneBuffer, aVal);
 
   mCloneBuffer.clear(aCx);
 
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -829,16 +829,53 @@ IDBObjectStore::ClearStructuredCloneBuff
       NS_WARNING("Couldn't get safe JSContext! Leaking data!");
       uint64* data;
       size_t length;
       aBuffer.steal(&data, &length);
     }
   }
 }
 
+// static
+bool
+IDBObjectStore::DeserializeValue(JSContext* aCx,
+                                 JSAutoStructuredCloneBuffer& aBuffer,
+                                 jsval* aValue)
+{
+  /*
+   *  This function can be called on multiple threads!  Be careful!
+   */
+  NS_ASSERTION(aCx, "A JSContext is required!");
+
+  if (!aBuffer.data()) {
+    *aValue = JSVAL_VOID;
+    return true;
+  }
+
+  JSAutoRequest ar(aCx);
+
+  return aBuffer.read(aValue, aCx, nsnull);
+}
+
+// static
+bool
+IDBObjectStore::SerializeValue(JSContext* aCx,
+                               JSAutoStructuredCloneBuffer& aBuffer,
+                               jsval aValue)
+{
+  /*
+   *  This function can be called on multiple threads!  Be careful!
+   */
+  NS_ASSERTION(aCx, "A JSContext is required!");
+
+  JSAutoRequest ar(aCx);
+
+  return aBuffer.write(aCx, aValue, nsnull);
+}
+
 IDBObjectStore::IDBObjectStore()
 : mId(LL_MININT),
   mAutoIncrement(PR_FALSE)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBObjectStore::~IDBObjectStore()
@@ -890,17 +927,17 @@ IDBObjectStore::GetAddInfo(JSContext* aC
   ObjectStoreInfo* info;
   if (!ObjectStoreInfo::Get(mTransaction->Database()->Id(), mName, &info)) {
     NS_ERROR("This should never fail!");
   }
 
   rv = GetIndexUpdateInfo(info, aCx, aValue, aUpdateInfoArray);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  if (!aCloneBuffer.write(aCx, aValue)) {
+  if (!IDBObjectStore::SerializeValue(aCx, aCloneBuffer, aValue)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::AddOrPut(const jsval& aValue,
@@ -1745,24 +1782,24 @@ AddHelper::ModifyValueForNewKey()
 {
   NS_ASSERTION(mObjectStore->IsAutoIncrement() &&
                !mObjectStore->KeyPath().IsEmpty() &&
                mKey.IsInt(),
                "Don't call me!");
 
   const nsString& keyPath = mObjectStore->KeyPath();
 
-  JSContext* cx;
+  JSContext* cx = nsnull;
   nsresult rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSAutoRequest ar(cx);
 
   jsval clone;
-  if (!mCloneBuffer.read(&clone, cx)) {
+  if (!IDBObjectStore::DeserializeValue(cx, mCloneBuffer, &clone)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   NS_ASSERTION(!JSVAL_IS_PRIMITIVE(clone), "We should have an object!");
 
   JSObject* obj = JSVAL_TO_OBJECT(clone);
   JSBool ok;
 
@@ -1780,17 +1817,17 @@ AddHelper::ModifyValueForNewKey()
   jsval key;
   ok = JS_NewNumberValue(cx, mKey.IntValue(), &key);
   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
   ok = JS_DefineUCProperty(cx, obj, keyPathChars, keyPathLen, key, nsnull,
                            nsnull, JSPROP_ENUMERATE);
   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
-  if (!mCloneBuffer.write(cx, OBJECT_TO_JSVAL(obj))) {
+  if (!IDBObjectStore::SerializeValue(cx, mCloneBuffer, OBJECT_TO_JSVAL(obj))) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   return NS_OK;
 }
 
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
@@ -1835,21 +1872,21 @@ GetHelper::DoDatabaseWork(mozIStorageCon
 
   return NS_OK;
 }
 
 nsresult
 GetHelper::GetSuccessResult(JSContext* aCx,
                             jsval* aVal)
 {
-  nsresult rv = ConvertCloneBufferToJSVal(aCx, mCloneBuffer, aVal);
+  bool result = IDBObjectStore::DeserializeValue(aCx, mCloneBuffer, aVal);
 
   mCloneBuffer.clear(aCx);
 
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
 nsresult
 DeleteHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(aConnection, "Passed a null connection!");
 
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -111,16 +111,26 @@ public:
   static nsresult
   GetStructuredCloneDataFromStatement(mozIStorageStatement* aStatement,
                                       PRUint32 aIndex,
                                       JSAutoStructuredCloneBuffer& aBuffer);
 
   static void
   ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer);
 
+  static bool
+  DeserializeValue(JSContext* aCx,
+                   JSAutoStructuredCloneBuffer& aBuffer,
+                   jsval* aValue);
+
+  static bool
+  SerializeValue(JSContext* aCx,
+                 JSAutoStructuredCloneBuffer& aBuffer,
+                 jsval aValue);
+
   const nsString& Name() const
   {
     return mName;
   }
 
   bool IsAutoIncrement() const
   {
     return mAutoIncrement;
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -295,27 +295,30 @@ IDBRequest::GetOnerror(nsIDOMEventListen
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest,
                                                   nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnSuccessListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
+                                                       nsPIDOMEventTarget)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
                                                 nsDOMEventTargetHelper)
   if (tmp->mResultValRooted) {
     tmp->mResultVal = JSVAL_VOID;
     tmp->UnrootResultVal();
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnSuccessListener)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBRequest)
   if (JSVAL_IS_GCTHING(tmp->mResultVal)) {
     void *gcThing = JSVAL_TO_GCTHING(tmp->mResultVal);
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResultVal")
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
--- a/dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
+++ b/dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
@@ -57,17 +57,17 @@ interface nsIDOMCanvasPattern : nsISuppo
 };
 
 [scriptable, uuid(2d01715c-ec7d-424a-ab85-e0fd70c8665c)]
 interface nsIDOMTextMetrics : nsISupports
 {
   readonly attribute float width;
 };
 
-[scriptable, uuid(408be1b9-4d75-4873-b50b-9b651626e41d)]
+[scriptable, uuid(bf5e52a3-6ec1-4a6e-8364-9f9222ec8edb)]
 interface nsIDOMCanvasRenderingContext2D : nsISupports
 {
   // back-reference to the canvas element for which
   // this context was created
   readonly attribute nsIDOMHTMLCanvasElement canvas;
 
   // state
   void save();
@@ -101,16 +101,19 @@ enum CanvasMultiGetterType {
       CMG_STYLE_GRADIENT = 2
 };
 %}
   [noscript] void setStrokeStyle_multi(in DOMString str, in nsISupports iface);
   [noscript] void getStrokeStyle_multi(out DOMString str, out nsISupports iface, out long type);
   [noscript] void setFillStyle_multi(in DOMString str, in nsISupports iface);
   [noscript] void getFillStyle_multi(out DOMString str, out nsISupports iface, out long type);
 
+  //attribute DOMString fillRule;
+  attribute DOMString mozFillRule; /* "evenodd", "nonzero" (default) */
+
   nsIDOMCanvasGradient createLinearGradient (in float x0, in float y0, in float x1, in float y1);
   nsIDOMCanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1);
   nsIDOMCanvasPattern createPattern(in nsIDOMHTMLElement image, in DOMString repetition);
   attribute float lineWidth; /* default 1 */
   attribute DOMString lineCap; /* "butt", "round", "square" (default) */
   attribute DOMString lineJoin; /* "round", "bevel", "miter" (default) */
   attribute float miterLimit; /* default 10 */
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -839,17 +839,16 @@ TabChild::InitTabChildGlobal()
   NS_ENSURE_TRUE(cx, false);
 
   mCx = cx;
 
   nsContentUtils::XPConnect()->SetSecurityManagerForJSContext(cx, nsContentUtils::GetSecurityManager(), 0);
   nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
 
   JS_SetNativeStackQuota(cx, 128 * sizeof(size_t) * 1024);
-  JS_SetScriptStackQuota(cx, 25 * sizeof(size_t) * 1024 * 1024);
 
   JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_ANONFUNFIX | JSOPTION_PRIVATE_IS_NSISUPPORTS);
   JS_SetVersion(cx, JSVERSION_LATEST);
   JS_SetErrorReporter(cx, ContentScriptErrorReporter);
 
   xpc_LocalizeContext(cx);
 
   JSAutoRequest ar(cx);
--- a/dom/ipc/tests/process_error.xul
+++ b/dom/ipc/tests/process_error.xul
@@ -8,23 +8,45 @@
   <script type="application/javascript"><![CDATA[
     Components.utils.import("resource://gre/modules/Services.jsm");
 
     const ok = window.opener.wrappedJSObject.ok;
     const is = window.opener.wrappedJSObject.is;
     const done = window.opener.wrappedJSObject.done;
     const SimpleTest = window.opener.wrappedJSObject.SimpleTest;
 
+    function getMinidumpDirectory() {
+      var dir = Services.dirsvc.get('ProfD', Components.interfaces.nsIFile);
+      dir.append("minidumps");
+      return dir;
+    }
+
+    function removeFile(directory, filename) {
+      var file = directory.clone();
+      file.append(filename);
+      if (file.exists()) {
+        file.remove(false);
+      }
+    }
+
     function crashObserver(subject, topic, data) {
       is(topic, 'ipc:content-shutdown', 'Received correct observer topic.');
       ok(subject instanceof Components.interfaces.nsIPropertyBag2,
          'Subject implements nsIPropertyBag2.');
-      
+
+      var dumpID;
       if ('nsICrashReporter' in Components.interfaces) {
-        ok(subject.getPropertyAsAString('dumpID'), "dumpID is present and not an empty string");
+        dumpID = subject.getPropertyAsAString('dumpID');
+        ok(dumpID, "dumpID is present and not an empty string");
+      }
+
+      if (dumpID) {
+        var minidumpDirectory = getMinidumpDirectory();
+        removeFile(minidumpDirectory, dumpID + '.dmp');
+        removeFile(minidumpDirectory, dumpID + '.extra');
       }
 
       Services.obs.removeObserver(crashObserver, 'ipc:content-shutdown');
       done();
     }
     Services.obs.addObserver(crashObserver, 'ipc:content-shutdown', false);
 
     document.getElementById('thebrowser').
--- a/dom/locales/en-US/chrome/appstrings.properties
+++ b/dom/locales/en-US/chrome/appstrings.properties
@@ -57,9 +57,10 @@ externalProtocolTitle=External Protocol 
 externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n
 #LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined
 externalProtocolUnknown=<Unknown>
 externalProtocolChkMsg=Remember my choice for all links of this type.
 externalProtocolLaunchBtn=Launch application
 malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
 phishingBlocked=The web site at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
 cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
+corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
 remoteXUL=This page uses an unsupported technology that is no longer available by default.
--- a/dom/locales/en-US/chrome/netError.dtd
+++ b/dom/locales/en-US/chrome/netError.dtd
@@ -79,16 +79,19 @@
 <!ENTITY phishingBlocked.longDesc "
 <p>Entering any personal information on this page may result in identity theft or other fraud.</p>
 <p>These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.</p>
 ">
 
 <!ENTITY cspFrameAncestorBlocked.title "Blocked by Content Security Policy">
 <!ENTITY cspFrameAncestorBlocked.longDesc "<p>The browser prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
 
+<!ENTITY corruptedContentError.title "Corrupted Content Error">
+<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
+
 <!ENTITY remoteXUL.title "Remote XUL">
 <!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
 
 <!-- Include app-specific error messages - do not change this in localization!
      Some applications might override netErrorApp.dtd with their specific version,
      this inclusion needs to be intact for that approach to work correctly.
      Please, try to keep this at the end of the file. -->
 <!ENTITY % netErrorAppDTD SYSTEM "chrome://global/locale/netErrorApp.dtd">
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -2295,16 +2295,21 @@ NPObjectMember_Call(JSContext *cx, uintN
 static void
 NPObjectMember_Trace(JSTracer *trc, JSObject *obj)
 {
   NPObjectMemberPrivate *memberPrivate =
     (NPObjectMemberPrivate *)::JS_GetPrivate(trc->context, obj);
   if (!memberPrivate)
     return;
 
+  // Our NPIdentifier is not always interned, so we must root it explicitly.
+  jsid id = NPIdentifierToJSId(memberPrivate->methodName);
+  if (JSID_IS_STRING(id))
+    JS_CALL_STRING_TRACER(trc, JSID_TO_STRING(id), "NPObjectMemberPrivate.methodName");
+
   if (!JSVAL_IS_PRIMITIVE(memberPrivate->fieldValue)) {
     JS_CALL_VALUE_TRACER(trc, memberPrivate->fieldValue,
                          "NPObject Member => fieldValue");
   }
 
   // There's no strong reference from our private data to the
   // NPObject, so make sure to mark the NPObject wrapper to keep the
   // NPObject alive as long as this NPObjectMember is alive.
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2299,21 +2299,16 @@ NPError NP_CALLBACK
         return NS_SUCCEEDED(rv) ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
       }
 
     case NPPVpluginKeepLibraryInMemory: {
       NPBool bCached = (result != nsnull);
       return inst->SetCached(bCached);
     }
 
-    case NPPVpluginWantsAllNetworkStreams: {
-      PRBool bWantsAllNetworkStreams = (result != nsnull);
-      return inst->SetWantsAllNetworkStreams(bWantsAllNetworkStreams);
-    }
-
     case NPPVpluginUsesDOMForCursorBool: {
       PRBool useDOMForCursor = (result != nsnull);
       return inst->SetUsesDOMForCursor(useDOMForCursor);
     }
 
 #ifdef XP_MACOSX
     case NPPVpluginDrawingModel: {
       if (inst) {
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -77,17 +77,16 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
     mDrawingModel(NPDrawingModelQuickDraw),
 #endif
 #endif
     mRunning(NOT_STARTED),
     mWindowless(PR_FALSE),
     mWindowlessLocal(PR_FALSE),
     mTransparent(PR_FALSE),
     mCached(PR_FALSE),
-    mWantsAllNetworkStreams(PR_FALSE),
     mUsesDOMForCursor(PR_FALSE),
     mInPluginInitCall(PR_FALSE),
     mPlugin(plugin),
     mMIMEType(nsnull),
     mOwner(nsnull),
     mCurrentPluginEvent(nsnull),
 #if defined(MOZ_X11) || defined(XP_WIN)
     mUsePluginLayersPref(PR_TRUE)
@@ -675,22 +674,16 @@ NPError nsNPAPIPluginInstance::SetWindow
 }
 
 NPError nsNPAPIPluginInstance::SetTransparent(PRBool aTransparent)
 {
   mTransparent = aTransparent;
   return NPERR_NO_ERROR;
 }
 
-NPError nsNPAPIPluginInstance::SetWantsAllNetworkStreams(PRBool aWantsAllNetworkStreams)
-{
-  mWantsAllNetworkStreams = aWantsAllNetworkStreams;
-  return NPERR_NO_ERROR;
-}
-
 NPError nsNPAPIPluginInstance::SetUsesDOMForCursor(PRBool aUsesDOMForCursor)
 {
   mUsesDOMForCursor = aUsesDOMForCursor;
   return NPERR_NO_ERROR;
 }
 
 PRBool
 nsNPAPIPluginInstance::UsesDOMForCursor()
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -219,17 +219,16 @@ protected:
   } mRunning;
 
   // these are used to store the windowless properties
   // which the browser will later query
   PRPackedBool mWindowless;
   PRPackedBool mWindowlessLocal;
   PRPackedBool mTransparent;
   PRPackedBool mCached;
-  PRPackedBool mWantsAllNetworkStreams;
   PRPackedBool mUsesDOMForCursor;
 
 public:
   // True while creating the plugin, or calling NPP_SetWindow() on it.
   PRPackedBool mInPluginInitCall;
 
   nsXPIDLCString mFakeURL;
 
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -97,19 +97,23 @@ rpc protocol PPluginInstance
   manages PStreamNotify;
   manages PPluginSurface;
 
 child:
   rpc __delete__();
 
   rpc NPP_SetWindow(NPRemoteWindow window);
 
+  rpc NPP_GetValue_NPPVpluginWantsAllNetworkStreams()
+    returns (bool value, NPError result);
+
   // this message is not used on non-X platforms
   rpc NPP_GetValue_NPPVpluginNeedsXEmbed()
     returns (bool value, NPError result);
+
   rpc NPP_GetValue_NPPVpluginScriptableNPObject()
     returns (nullable PPluginScriptableObject value, NPError result);
 
   rpc NPP_SetValue_NPNVprivateModeBool(bool value) returns (NPError result);
   rpc NPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId()
     returns (nsCString plug_id, NPError result);
 
   rpc NPP_HandleEvent(NPRemoteEvent event)
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -509,16 +509,34 @@ PluginInstanceChild::NPN_SetValue(NPPVar
         PR_LOG(gPluginLog, PR_LOG_WARNING,
                ("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)",
                 (int) aVar, NPPVariableToString(aVar)));
         return NPERR_GENERIC_ERROR;
     }
 }
 
 bool
+PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(
+    bool* wantsAllStreams, NPError* rv)
+{
+    AssertPluginThread();
+
+    PRBool value = 0;
+    if (!mPluginIface->getvalue) {
+        *rv = NPERR_GENERIC_ERROR;
+    }
+    else {
+        *rv = mPluginIface->getvalue(GetNPP(), NPPVpluginWantsAllNetworkStreams,
+                                     &value);
+    }
+    *wantsAllStreams = value;
+    return true;
+}
+
+bool
 PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(
     bool* needs, NPError* rv)
 {
     AssertPluginThread();
 
 #ifdef MOZ_X11
     // The documentation on the types for many variables in NP(N|P)_GetValue
     // is vague.  Often boolean values are NPBool (1 byte), but
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -83,16 +83,18 @@ class PluginInstanceChild : public PPlug
                                                      WPARAM wParam,
                                                      LPARAM lParam);
 #endif
 
 protected:
     virtual bool AnswerNPP_SetWindow(const NPRemoteWindow& window);
 
     virtual bool
+    AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv);
+    virtual bool
     AnswerNPP_GetValue_NPPVpluginNeedsXEmbed(bool* needs, NPError* rv);
     virtual bool
     AnswerNPP_GetValue_NPPVpluginScriptableNPObject(PPluginScriptableObjectChild** value,
                                                     NPError* result);
     virtual bool
     AnswerNPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId(nsCString* aPlugId,
                                                      NPError* aResult);
     virtual bool
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -915,16 +915,32 @@ PluginInstanceParent::NPP_SetWindow(cons
 }
 
 NPError
 PluginInstanceParent::NPP_GetValue(NPPVariable aVariable,
                                    void* _retval)
 {
     switch (aVariable) {
 
+    case NPPVpluginWantsAllNetworkStreams: {
+        bool wantsAllStreams;
+        NPError rv;
+
+        if (!CallNPP_GetValue_NPPVpluginWantsAllNetworkStreams(&wantsAllStreams, &rv)) {
+            return NPERR_GENERIC_ERROR;
+        }
+
+        if (NPERR_NO_ERROR != rv) {
+            return rv;
+        }
+
+        (*(NPBool*)_retval) = wantsAllStreams;
+        return NPERR_NO_ERROR;
+    }
+
 #ifdef MOZ_X11
     case NPPVpluginNeedsXEmbed: {
         bool needsXEmbed;
         NPError rv;
 
         if (!CallNPP_GetValue_NPPVpluginNeedsXEmbed(&needsXEmbed, &rv)) {
             return NPERR_GENERIC_ERROR;
         }
--- a/dom/plugins/test/mochitest/Makefile.in
+++ b/dom/plugins/test/mochitest/Makefile.in
@@ -95,16 +95,17 @@ include $(topsrcdir)/config/rules.mk
   test_bug539565-1.html \
   test_bug539565-2.html \
   test_enumerate.html \
   test_npruntime_construct.html \
   307-xo-redirect.sjs \
   test_redirect_handling.html \
   test_clear_site_data.html \
   test_zero_opacity.html \
+  test_NPPVpluginWantsAllNetworkStreams.html \
   $(NULL)
 
 #  test_plugin_scroll_painting.html \ bug 596491
 #  test_npruntime_npnsetexception.html \ Disabled for e10s
 
 ifeq ($(OS_ARCH),WINNT)
 _MOCHITEST_FILES += \
   test_windowed_invalidate.html \
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_NPPVpluginWantsAllNetworkStreams.html
@@ -0,0 +1,71 @@
+<html>
+<head>
+  <title>Test NPPVpluginWantsAllNetworkStreams</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body onload="runNextTest()">
+  <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+
+  <script class="testbody" type="application/javascript">
+    SimpleTest.waitForExplicitFinish();
+
+    var p = document.getElementById("plugin1");
+
+    var missingDoc = "not-found.html";
+
+    var expectedWriteURL = "";
+    var expectedNotifyStatus = -1;
+
+    var writeHappened = false;
+    var expectedWrite = false;
+
+    function writeCallback(url) {
+      writeHappened = true;
+    }
+
+    function notifyCallback(status, data) {
+      is(writeHappened, expectedWrite, "Test for expected write.");
+      is(status, expectedNotifyStatus, "Test for expected stream notification status.");
+      runNextTest();
+    }
+
+    function test1() {
+      // In this test we do not expect a stream for the missing document.
+      p.setPluginWantsAllStreams(false);
+
+      expectedWriteURL = missingDoc;
+      expectedNotifyStatus = 1;
+
+      writeHappened = false;
+      expectedWrite = false;
+
+      p.streamTest(missingDoc, false, null, writeCallback, notifyCallback, null, false);
+    }
+
+    function test2() {
+      // In this test we expect a stream for the missing document.
+      p.setPluginWantsAllStreams(true);
+
+      expectedWriteURL = missingDoc;
+      expectedNotifyStatus = 0;
+
+      writeHappened = false;
+      expectedWrite = true;
+
+      p.streamTest(missingDoc, false, null, writeCallback, notifyCallback, null, false);
+    }
+
+    var tests = [test1, test2];
+    var currentTest = -1;
+    function runNextTest() {
+      currentTest++;
+      if (currentTest < tests.length) {
+        tests[currentTest]();
+      } else {
+        SimpleTest.finish();
+      }
+    }
+  </script>
+</body>
+</html>
--- a/dom/plugins/test/testplugin/README
+++ b/dom/plugins/test/testplugin/README
@@ -349,28 +349,31 @@ The attributes which control stream test
 
 "failurecode": one of the NPError constants.  Used to specify the error
   that will be returned by the "functiontofail".
 
 If the plugin is instantiated as a full-page plugin, the following defaults
 are used:
   streammode="seek" frame="testframe" range="100,100"
 
-The streamTest(url, doPost, postData, writeCallback, notifyCallback, redirectCallback, allowRedirects)
-function will test how NPN_GetURLNotify and NPN_PostURLNotify behave when they are
+* streamTest(url, doPost, postData, writeCallback, notifyCallback, redirectCallback, allowRedirects)
+This will test how NPN_GetURLNotify and NPN_PostURLNotify behave when they are
 called with arbitrary (malformed) URLs. The function will return `true` if
 NPN_[Get/Post]URLNotify succeeds, and `false` if it fails.
 @url url to request
 @param doPost whether to call NPN_PostURLNotify
 @param postData null, or a string to send a postdata
 @writeCallback will be called when data is received for the stream
 @notifyCallback will be called when the urlnotify is received with the notify result
 @redirectCallback will be called from urlredirectnotify if a redirect is attempted
 @allowRedirects boolean value indicating whether or not to allow redirects
 
+* setPluginWantsAllStreams(wantsAllStreams)
+Set the value returned by the plugin for NPPVpluginWantsAllNetworkStreams.
+
 == Internal consistency ==
 
 * doInternalConsistencyCheck()
 Does internal consistency checking, returning an empty string if everything is
 OK, otherwise returning some kind of error string. On Windows, in windowed
 mode, this checks that the position of the plugin's internal child
 window has not been disturbed relative to the plugin window.