Merge mozilla-central to Places
authorShawn Wilsher <me@shawnwilsher.com>
Wed, 10 Nov 2010 09:38:08 -0800
changeset 59328 e2735288ed68bfd0f33a570bf1dbd6eb44e68ef6
parent 59327 4626f19fa27e9f847116eae92a9eeeee000d7b4f (current diff)
parent 57201 212a391d3b79caa2e953bb70e4a00460089e844e (diff)
child 59329 c8d8af0fcc3869ad5ee71154b8f5c021ff2b3b7f
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
milestone2.0b8pre
Merge mozilla-central to Places
browser/base/content/tabview/infoitems.js
browser/base/content/test/browser_tabMatchesInAwesomebar.js
browser/components/places/tests/browser/Makefile.in
browser/installer/package-manifest.in
browser/installer/removed-files.in
configure.in
content/svg/content/src/nsSVGPathSeg.cpp
content/svg/content/src/nsSVGPathSeg.h
content/svg/content/src/nsSVGPathSegList.cpp
content/svg/content/src/nsSVGPathSegList.h
media/libtheora/bug559343.patch
media/libtheora/include/theora/config.h
media/libtheora/lib/cpu.c
media/libtheora/lib/cpu.h
media/libtheora/lib/encint.h
media/libtheora/lib/encoder_disabled.c
media/libtheora/lib/enquant.h
media/libtheora/lib/huffenc.h
media/libtheora/lib/x86/mmxfrag.h
media/libtheora/lib/x86_vc/mmxfrag.h
media/libvpx/frame_buf_ref.patch
media/libvpx/reduce-warnings-1.patch
media/libvpx/subpixel-qword.patch
media/libvpx/vp8/common/segmentation_common.h
media/libvpx/vp8/decoder/demode.c
media/libvpx/vp8/decoder/demode.h
testing/mochitest/runtests.py.in
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -77,17 +77,16 @@
 /* For documentation of the accessibility architecture, 
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
  */
 
 nsIStringBundle *nsAccessNode::gStringBundle = 0;
 nsIStringBundle *nsAccessNode::gKeyStringBundle = 0;
 nsINode *nsAccessNode::gLastFocusedNode = nsnull;
 
-PRBool nsAccessNode::gIsCacheDisabled = PR_FALSE;
 PRBool nsAccessNode::gIsFormFillEnabled = PR_FALSE;
 
 nsApplicationAccessible *nsAccessNode::gApplicationAccessible = nsnull;
 
 /*
  * Class nsAccessNode
  */
  
@@ -212,17 +211,16 @@ void nsAccessNode::InitXPAccessibility()
     stringBundleService->CreateBundle(PLATFORM_KEYS_BUNDLE_URL, 
                                       &gKeyStringBundle);
   }
 
   nsAccessibilityAtoms::AddRefAtoms();
 
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefBranch) {
-    prefBranch->GetBoolPref("accessibility.disablecache", &gIsCacheDisabled);
     prefBranch->GetBoolPref("browser.formfill.enable", &gIsFormFillEnabled);
   }
 
   NotifyA11yInitOrShutdown(PR_TRUE);
 }
 
 // nsAccessNode protected static
 void nsAccessNode::NotifyA11yInitOrShutdown(PRBool aIsInit)
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -151,17 +151,17 @@ public:
     return DOMNode;
   }
 
   /**
    * Return DOM node associated with the accessible.
    */
   virtual nsINode* GetNode() const { return mContent; }
   nsIContent* GetContent() const { return mContent; }
-  nsIDocument* GetDocumentNode() const
+  virtual nsIDocument* GetDocumentNode() const
     { return mContent ? mContent->GetOwnerDoc() : nsnull; }
 
   /**
    * Return node type information of DOM node associated with the accessible.
    */
   PRBool IsContent() const
   {
     return GetNode() && GetNode()->IsNodeOfType(nsINode::eCONTENT);
@@ -207,17 +207,16 @@ protected:
      * Notify global nsIObserver's that a11y is getting init'd or shutdown
      */
     static void NotifyA11yInitOrShutdown(PRBool aIsInit);
 
     // Static data, we do our own refcounting for our static data
     static nsIStringBundle *gStringBundle;
     static nsIStringBundle *gKeyStringBundle;
 
-    static PRBool gIsCacheDisabled;
     static PRBool gIsFormFillEnabled;
 
 private:
   static nsApplicationAccessible *gApplicationAccessible;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsAccessNode,
                               NS_ACCESSNODE_IMPL_CID)
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -95,28 +95,31 @@ ACCESSIBILITY_ATOM(tableOuterFrame, "Tab
 ACCESSIBILITY_ATOM(tableRowGroupFrame, "TableRowGroupFrame")
 ACCESSIBILITY_ATOM(tableRowFrame, "TableRowFrame")
 
   // Alphabetical list of tag names
 ACCESSIBILITY_ATOM(a, "a")
 ACCESSIBILITY_ATOM(abbr, "abbr")
 ACCESSIBILITY_ATOM(acronym, "acronym")
 ACCESSIBILITY_ATOM(area, "area")
+ACCESSIBILITY_ATOM(article, "article") // HTML landmark
 ACCESSIBILITY_ATOM(autocomplete, "autocomplete")
 ACCESSIBILITY_ATOM(blockquote, "blockquote")
 ACCESSIBILITY_ATOM(br, "br")
 ACCESSIBILITY_ATOM(body, "body")
 ACCESSIBILITY_ATOM(caption, "caption") // XUL
 ACCESSIBILITY_ATOM(choices, "choices") // XForms
 ACCESSIBILITY_ATOM(description, "description")    // XUL
 ACCESSIBILITY_ATOM(dd, "dd")
 ACCESSIBILITY_ATOM(div, "div")
 ACCESSIBILITY_ATOM(dl, "dl")
 ACCESSIBILITY_ATOM(dt, "dt")
+ACCESSIBILITY_ATOM(footer, "footer") // HTML landmark
 ACCESSIBILITY_ATOM(form, "form")
+ACCESSIBILITY_ATOM(header, "header") // HTML landmark
 ACCESSIBILITY_ATOM(h1, "h1")
 ACCESSIBILITY_ATOM(h2, "h2")
 ACCESSIBILITY_ATOM(h3, "h3")
 ACCESSIBILITY_ATOM(h4, "h4")
 ACCESSIBILITY_ATOM(h5, "h5")
 ACCESSIBILITY_ATOM(h6, "h6")
 ACCESSIBILITY_ATOM(item, "item") // XForms
 ACCESSIBILITY_ATOM(itemset, "itemset") // XForms
@@ -130,16 +133,17 @@ ACCESSIBILITY_ATOM(listcell, "listcell")
 ACCESSIBILITY_ATOM(listcols, "listcols") // XUL
 ACCESSIBILITY_ATOM(listcol, "listcol") // XUL
 ACCESSIBILITY_ATOM(listhead, "listhead") // XUL
 ACCESSIBILITY_ATOM(listheader, "listheader") // XUL
 ACCESSIBILITY_ATOM(map, "map")
 ACCESSIBILITY_ATOM(math, "math")
 ACCESSIBILITY_ATOM(menupopup, "menupopup")     // XUL
 ACCESSIBILITY_ATOM(object, "object")
+ACCESSIBILITY_ATOM(nav, "nav") // HTML landmark
 ACCESSIBILITY_ATOM(ol, "ol")
 ACCESSIBILITY_ATOM(optgroup, "optgroup")
 ACCESSIBILITY_ATOM(option, "option")
 ACCESSIBILITY_ATOM(output, "output")
 ACCESSIBILITY_ATOM(panel, "panel") // XUL
 ACCESSIBILITY_ATOM(q, "q")
 ACCESSIBILITY_ATOM(select, "select")
 ACCESSIBILITY_ATOM(select1, "select1") // XForms
@@ -191,16 +195,17 @@ ACCESSIBILITY_ATOM(longDesc, "longdesc")
 ACCESSIBILITY_ATOM(max, "max") // XUL
 ACCESSIBILITY_ATOM(maxpos, "maxpos") // XUL
 ACCESSIBILITY_ATOM(minpos, "minpos") // XUL
 ACCESSIBILITY_ATOM(_moz_menuactive, "_moz-menuactive") // XUL
 ACCESSIBILITY_ATOM(multiline, "multiline") // XUL
 ACCESSIBILITY_ATOM(name, "name")
 ACCESSIBILITY_ATOM(onclick, "onclick")
 ACCESSIBILITY_ATOM(popup, "popup")
+ACCESSIBILITY_ATOM(placeholder, "placeholder")
 ACCESSIBILITY_ATOM(readonly, "readonly")
 ACCESSIBILITY_ATOM(scope, "scope") // HTML table
 ACCESSIBILITY_ATOM(seltype, "seltype") // XUL listbox
 ACCESSIBILITY_ATOM(simple, "simple") // XLink
 ACCESSIBILITY_ATOM(src, "src")
 ACCESSIBILITY_ATOM(selected, "selected")
 ACCESSIBILITY_ATOM(summary, "summary")
 ACCESSIBILITY_ATOM(tabindex, "tabindex")
@@ -284,8 +289,9 @@ ACCESSIBILITY_ATOM(containerBusy, "conta
 ACCESSIBILITY_ATOM(containerLive, "container-live")
 ACCESSIBILITY_ATOM(containerLiveRole, "container-live-role")
 ACCESSIBILITY_ATOM(containerRelevant, "container-relevant")
 ACCESSIBILITY_ATOM(level, "level")
 ACCESSIBILITY_ATOM(live, "live")
 ACCESSIBILITY_ATOM(lineNumber, "line-number")
 ACCESSIBILITY_ATOM(posinset, "posinset") 
 ACCESSIBILITY_ATOM(setsize, "setsize")
+ACCESSIBILITY_ATOM(xmlroles, "xml-roles")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -472,64 +472,78 @@ nsAccessibilityService::CreateHTMLCaptio
 }
 
 void
 nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
                                              nsIContent* aContainer,
                                              nsIContent* aStartChild,
                                              nsIContent* aEndChild)
 {
-#ifdef DEBUG_A11Y
+#ifdef DEBUG_CONTENTMUTATION
   nsAutoString tag;
   aStartChild->Tag()->ToString(tag);
-  nsIAtom* id = aStartChild->GetID();
-  nsCAutoString strid;
-  if (id)
-    id->ToUTF8String(strid);
+
+  nsIAtom* atomid = aStartChild->GetID();
+  nsCAutoString id;
+  if (atomid)
+    atomid->ToUTF8String(id);
+
   nsAutoString ctag;
-  aContainer->Tag()->ToString(ctag);
-  nsIAtom* cid = aContainer->GetID();
-  nsCAutoString strcid;
-  if (cid)
-    cid->ToUTF8String(strcid);
+  nsCAutoString cid;
+  nsIAtom* catomid = nsnull;
+  if (aContainer) {
+    aContainer->Tag()->ToString(ctag);
+    catomid = aContainer->GetID();
+    if (catomid)
+      catomid->ToUTF8String(cid);
+  }
+
   printf("\ncontent inserted: %s@id='%s', container: %s@id='%s', end node: %p\n\n",
-         NS_ConvertUTF16toUTF8(tag).get(), strid.get(),
-         NS_ConvertUTF16toUTF8(ctag).get(), strcid.get(), aEndChild);
+         NS_ConvertUTF16toUTF8(tag).get(), id.get(),
+         NS_ConvertUTF16toUTF8(ctag).get(), cid.get(), aEndChild);
 #endif
 
-  // XXX: bug 606082. aContainer is null when root element is inserted into
-  // document, we need to handle this and update the tree, also we need to
-  // update a content node of the document accessible.
-  if (aContainer) {
-    nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
-    if (docAccessible)
-      docAccessible->UpdateTree(aContainer, aStartChild, aEndChild, PR_TRUE);
-  }
+  nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
+  if (docAccessible)
+    docAccessible->UpdateTree(aContainer, aStartChild, aEndChild, PR_TRUE);
 }
 
 void
 nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
                                        nsIContent* aContainer,
                                        nsIContent* aChild)
 {
-#ifdef DEBUG_A11Y
-  nsAutoString id;
-  aChild->Tag()->ToString(id);
-  printf("\ncontent removed: %s\n", NS_ConvertUTF16toUTF8(id).get());
+#ifdef DEBUG_CONTENTMUTATION
+  nsAutoString tag;
+  aChild->Tag()->ToString(tag);
+
+  nsIAtom* atomid = aChild->GetID();
+  nsCAutoString id;
+  if (atomid)
+    atomid->ToUTF8String(id);
+
+  nsAutoString ctag;
+  nsCAutoString cid;
+  nsIAtom* catomid = nsnull;
+  if (aContainer) {
+    aContainer->Tag()->ToString(ctag);
+    catomid = aContainer->GetID();
+    if (catomid)
+      catomid->ToUTF8String(cid);
+  }
+
+  printf("\ncontent removed: %s@id='%s', container: %s@id='%s'\n\n",
+           NS_ConvertUTF16toUTF8(tag).get(), id.get(),
+           NS_ConvertUTF16toUTF8(ctag).get(), cid.get());
 #endif
 
-  // XXX: bug 606082. aContainer is null when root element is inserted into
-  // document, we need to handle this and update the tree, perhaps destroy
-  // the document accessible.
-  if (aContainer) {
-    nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
-    if (docAccessible)
-      docAccessible->UpdateTree(aContainer, aChild, aChild->GetNextSibling(),
-                                PR_FALSE);
-  }
+  nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
+  if (docAccessible)
+    docAccessible->UpdateTree(aContainer, aChild, aChild->GetNextSibling(),
+                              PR_FALSE);
 }
 
 void
 nsAccessibilityService::PresShellDestroyed(nsIPresShell *aPresShell)
 {
   // Presshell destruction will automatically destroy shells for descendant
   // documents, so no need to worry about those. Just shut down the accessible
   // for this one document. That keeps us from having bad behavior in case of
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -462,19 +462,16 @@ nsAccessible::GetPreviousSibling(nsIAcce
 
   /* readonly attribute nsIAccessible firstChild; */
 NS_IMETHODIMP
 nsAccessible::GetFirstChild(nsIAccessible **aFirstChild) 
 {
   NS_ENSURE_ARG_POINTER(aFirstChild);
   *aFirstChild = nsnull;
 
-  if (gIsCacheDisabled)
-    InvalidateChildren();
-
   PRInt32 childCount = GetChildCount();
   NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE);
 
   if (childCount > 0)
     NS_ADDREF(*aFirstChild = GetChildAt(0));
 
   return NS_OK;
 }
@@ -2728,64 +2725,77 @@ nsAccessible::InvalidateChildren()
   mEmbeddedObjCollector = nsnull;
   mChildren.Clear();
   mChildrenFlags = eChildrenUninitialized;
 }
 
 PRBool
 nsAccessible::AppendChild(nsAccessible* aChild)
 {
+  if (!aChild)
+    return PR_FALSE;
+
   if (!mChildren.AppendElement(aChild))
     return PR_FALSE;
 
   if (!nsAccUtils::IsEmbeddedObject(aChild))
     mChildrenFlags = eMixedChildren;
 
   aChild->BindToParent(this, mChildren.Length() - 1);
   return PR_TRUE;
 }
 
 PRBool
 nsAccessible::InsertChildAt(PRUint32 aIndex, nsAccessible* aChild)
 {
+  if (!aChild)
+    return PR_FALSE;
+
   if (!mChildren.InsertElementAt(aIndex, aChild))
     return PR_FALSE;
 
-  for (PRUint32 idx = aIndex + 1; idx < mChildren.Length(); idx++)
-    mChildren[idx]->mIndexInParent++;
+  for (PRUint32 idx = aIndex + 1; idx < mChildren.Length(); idx++) {
+    NS_ASSERTION(mChildren[idx]->mIndexInParent == idx - 1, "Accessible child index doesn't match");
+    mChildren[idx]->mIndexInParent = idx;
+  }
 
   if (nsAccUtils::IsText(aChild))
     mChildrenFlags = eMixedChildren;
 
   mEmbeddedObjCollector = nsnull;
 
   aChild->BindToParent(this, aIndex);
   return PR_TRUE;
 }
 
 PRBool
 nsAccessible::RemoveChild(nsAccessible* aChild)
 {
-  if (aChild->mParent != this || aChild->mIndexInParent == -1)
+  if (!aChild)
     return PR_FALSE;
 
-  if (aChild->mIndexInParent >= mChildren.Length() ||
-      mChildren[aChild->mIndexInParent] != aChild) {
+  PRInt32 index = aChild->mIndexInParent;
+  if (aChild->mParent != this || index == -1)
+    return PR_FALSE;
+
+  if (index >= mChildren.Length() || mChildren[index] != aChild) {
     NS_ERROR("Child is bound to parent but parent hasn't this child at its index!");
     aChild->UnbindFromParent();
     return PR_FALSE;
   }
 
-  for (PRUint32 idx = aChild->mIndexInParent + 1; idx < mChildren.Length(); idx++)
-    mChildren[idx]->mIndexInParent--;
-
-  mChildren.RemoveElementAt(aChild->mIndexInParent);
-  mEmbeddedObjCollector = nsnull;
+  for (PRUint32 idx = index + 1; idx < mChildren.Length(); idx++) {
+    NS_ASSERTION(mChildren[idx]->mIndexInParent == idx, "Accessible child index doesn't match");
+    mChildren[idx]->mIndexInParent = idx - 1;
+  }
 
   aChild->UnbindFromParent();
+  mChildren.RemoveElementAt(index);
+  mEmbeddedObjCollector = nsnull;
+
   return PR_TRUE;
 }
 
 nsAccessible*
 nsAccessible::GetParent()
 {
   if (mParent)
     return mParent;
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -280,18 +280,22 @@ nsDocAccessible::GetStateInternal(PRUint
 
   if (IsDefunct()) {
     if (aExtraState)
       *aExtraState = nsIAccessibleStates::EXT_STATE_DEFUNCT;
 
     return NS_OK_DEFUNCT_OBJECT;
   }
 
-  if (aExtraState)
-    *aExtraState = 0;
+  if (aExtraState) {
+    // The root content of the document might be removed so that mContent is
+    // out of date.
+    *aExtraState = (mContent->GetCurrentDoc() == mDocument) ?
+      0 : nsIAccessibleStates::EXT_STATE_STALE;
+  }
 
 #ifdef MOZ_XUL
   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
   if (!xulDoc)
 #endif
   {
     // XXX Need to invent better check to see if doc is focusable,
     // which it should be if it is scrollable. A XUL document could be focusable.
@@ -670,18 +674,20 @@ nsDocAccessible::Shutdown()
   if (mParent) {
     nsDocAccessible* parentDocument = mParent->GetDocAccessible();
     if (parentDocument)
       parentDocument->RemoveChildDocument(this);
 
     mParent->RemoveChild(this);
   }
 
-  PRUint32 childDocCount = mChildDocuments.Length();
-  for (PRUint32 idx = 0; idx < childDocCount; idx++)
+  // Walk the array backwards because child documents remove themselves from the
+  // array as they are shutdown.
+  PRInt32 childDocCount = mChildDocuments.Length();
+  for (PRInt32 idx = childDocCount - 1; idx >= 0; idx--)
     mChildDocuments[idx]->Shutdown();
 
   mChildDocuments.Clear();
 
   mWeakShell = nsnull;  // Avoid reentrancy
 
   mNodeToAccessibleMap.Clear();
   ClearCache(mAccessibleCache);
@@ -1234,22 +1240,27 @@ void nsDocAccessible::ContentAppended(ns
 {
 }
 
 void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument,
                                            nsIContent* aContent1,
                                            nsIContent* aContent2,
                                            nsEventStates aStateMask)
 {
-  if (!aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
-    return;
+  if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
+    nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent1);
+    nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2);
   }
 
-  nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent1);
-  nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2);
+  if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) {
+    nsRefPtr<AccEvent> event =
+      new AccStateChangeEvent(aContent1, nsIAccessibleStates::STATE_INVALID,
+                              PR_FALSE, PR_TRUE);
+    FireDelayedAccessibleEvent(event);
+   }
 }
 
 void nsDocAccessible::DocumentStatesChanged(nsIDocument* aDocument,
                                             nsEventStates aStateMask)
 {
 }
 
 void nsDocAccessible::CharacterDataWillChange(nsIDocument *aDocument,
@@ -1341,32 +1352,59 @@ nsDocAccessible::UpdateTree(nsIContent* 
                             PRBool aIsInsert)
 {
   // Content change notification mostly are async, thus we can't detect whether
   // these actions are from user. This information is used to fire or do not
   // fire events to avoid events that are generated because of document loading.
   // Since this information may be not correct then we need to fire some events
   // regardless the document loading state.
 
+  // Update the whole tree of this document accessible when the container is
+  // null (document element is inserted or removed).
+
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   nsIEventStateManager* esm = presShell->GetPresContext()->EventStateManager();
   PRBool fireAllEvents = PR_TRUE;//IsContentLoaded() || esm->IsHandlingUserInputExternal();
 
-  // We don't create new accessibles on content removal.
-  nsAccessible* container = aIsInsert ?
-    GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
-    GetAccService()->GetCachedAccessibleOrContainer(aContainerNode);
+  // XXX: bug 608887 reconsider accessible tree update logic because
+  // 1) elements appended outside the HTML body don't get accessibles;
+  // 2) the document having elements that should be accessible may function
+  // without body.
+  nsAccessible* container = nsnull;
+  if (aIsInsert) {
+    container = aContainerNode ?
+      GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
+      this;
 
-  if (aIsInsert) {
+    // The document children were changed; the root content might be affected.
+    if (container == this) {
+      nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocument);
+
+      // No root content (for example HTML document element was inserted but no
+      // body). Nothing to update.
+      if (!rootContent)
+        return;
+
+      // New root content has been inserted, update it and update the tree.
+      if (rootContent != mContent)
+        mContent = rootContent;
+    }
+
     // XXX: Invalidate parent-child relations for container accessible and its
     // children because there's no good way to find insertion point of new child
     // accessibles into accessible tree. We need to invalidate children even
     // there's no inserted accessibles in the end because accessible children
     // are created while parent recaches child accessibles.
     container->InvalidateChildren();
+
+  } else {
+    // Don't create new accessibles on content removal.
+    container = aContainerNode ?
+      GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
+      this;
   }
 
   EIsFromUserInput fromUserInput = esm->IsHandlingUserInputExternal() ?
     eFromUserInput : eNoUserInput;
 
   // Update the accessible tree in the case of content removal and fire events
   // if allowed.
   PRUint32 updateFlags =
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -103,16 +103,17 @@ public:
   NS_DECL_NSIDOCUMENTOBSERVER
 
   // nsAccessNode
   virtual PRBool Init();
   virtual void Shutdown();
   virtual nsIFrame* GetFrame();
   virtual PRBool IsDefunct();
   virtual nsINode* GetNode() const { return mDocument; }
+  virtual nsIDocument* GetDocumentNode() const { return mDocument; }
 
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState);
 
   virtual void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry);
 
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -191,18 +191,23 @@ nsOuterDocAccessible::InvalidateChildren
   // accessible is created and appended as a child when it's requested.
 
   mChildrenFlags = eChildrenUninitialized;
 }
 
 PRBool
 nsOuterDocAccessible::AppendChild(nsAccessible *aAccessible)
 {
-  NS_ASSERTION(!mChildren.Length(),
-               "Previous child document of outerdoc accessible wasn't removed!");
+  // We keep showing the old document for a bit after creating the new one,
+  // and while building the new DOM and frame tree. That's done on purpose
+  // to avoid weird flashes of default background color.
+  // The old viewer will be destroyed after the new one is created.
+  // For a11y, it should be safe to shut down the old document now.
+  if (mChildren.Length())
+    mChildren[0]->Shutdown();
 
   if (!nsAccessible::AppendChild(aAccessible))
     return PR_FALSE;
 
   NS_LOG_ACCDOCCREATE("append document to outerdoc",
                       aAccessible->GetDocumentNode())
   NS_LOG_ACCDOCCREATE_ACCADDRESS("outerdoc", this)
 
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -407,26 +407,34 @@ nsresult
 nsHTMLTextFieldAccessible::GetNameInternal(nsAString& aName)
 {
   nsresult rv = nsAccessible::GetNameInternal(aName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!aName.IsEmpty())
     return NS_OK;
 
-  if (!mContent->GetBindingParent())
+  if (mContent->GetBindingParent())
+  {
+    // XXX: bug 459640
+    // There's a binding parent.
+    // This means we're part of another control, so use parent accessible for name.
+    // This ensures that a textbox inside of a XUL widget gets
+    // an accessible name.
+    nsAccessible* parent = GetParent();
+    parent->GetName(aName);
+  }
+
+  if (!aName.IsEmpty())
     return NS_OK;
 
-  // XXX: bug 459640
-  // There's a binding parent.
-  // This means we're part of another control, so use parent accessible for name.
-  // This ensures that a textbox inside of a XUL widget gets
-  // an accessible name.
-  nsAccessible* parent = GetParent();
-  return parent ? parent->GetName(aName) : NS_OK;
+  // text inputs and textareas might have useful placeholder text
+  mContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::placeholder, aName);
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetValue(nsAString& _retval)
 {
   PRUint32 state;
   nsresult rv = GetStateInternal(&state, nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -129,28 +129,38 @@ nsresult nsHyperTextAccessible::QueryInt
 PRUint32
 nsHyperTextAccessible::NativeRole()
 {
   nsIAtom *tag = mContent->Tag();
 
   if (tag == nsAccessibilityAtoms::form)
     return nsIAccessibleRole::ROLE_FORM;
 
-  if (tag == nsAccessibilityAtoms::div ||
-      tag == nsAccessibilityAtoms::blockquote)
+  if (tag == nsAccessibilityAtoms::article ||
+      tag == nsAccessibilityAtoms::blockquote ||
+      tag == nsAccessibilityAtoms::div ||
+      tag == nsAccessibilityAtoms::nav)
     return nsIAccessibleRole::ROLE_SECTION;
 
   if (tag == nsAccessibilityAtoms::h1 ||
       tag == nsAccessibilityAtoms::h2 ||
       tag == nsAccessibilityAtoms::h3 ||
       tag == nsAccessibilityAtoms::h4 ||
       tag == nsAccessibilityAtoms::h5 ||
       tag == nsAccessibilityAtoms::h6)
     return nsIAccessibleRole::ROLE_HEADING;
 
+  // Deal with html landmark elements
+  if (tag == nsAccessibilityAtoms::header)
+    return nsIAccessibleRole::ROLE_HEADER;
+
+  if (tag == nsAccessibilityAtoms::footer)
+    return nsIAccessibleRole::ROLE_FOOTER;
+
+  // Treat block frames as paragraphs
   nsIFrame *frame = GetFrame();
   if (frame && frame->GetType() == nsAccessibilityAtoms::blockFrame &&
       frame->GetContent()->Tag() != nsAccessibilityAtoms::input) {
     // An html:input @type="file" is the only input that is exposed as a
     // blockframe. It must be exposed as ROLE_TEXT_CONTAINER for JAWS.
     return nsIAccessibleRole::ROLE_PARAGRAPH;
   }
 
@@ -1192,16 +1202,31 @@ nsHyperTextAccessible::GetAttributesInte
     if (lineNumber >= 1) {
       nsAutoString strLineNumber;
       strLineNumber.AppendInt(lineNumber);
       nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::lineNumber,
                              strLineNumber);
     }
   }
 
+  // For the html landmark elements we expose them like we do aria landmarks to
+  // make AT navigation schemes "just work".
+  if (mContent->Tag() == nsAccessibilityAtoms::nav)
+    nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
+                           NS_LITERAL_STRING("navigation"));
+  else if (mContent->Tag() == nsAccessibilityAtoms::header) 
+    nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
+                           NS_LITERAL_STRING("banner"));
+  else if (mContent->Tag() == nsAccessibilityAtoms::footer) 
+    nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
+                           NS_LITERAL_STRING("contentinfo"));
+  else if (mContent->Tag() == nsAccessibilityAtoms::article) 
+    nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
+                           NS_LITERAL_STRING("main"));
+
   return  NS_OK;
 }
 
 /*
  * Given an offset, the x, y, width, and height values are filled appropriately.
  */
 NS_IMETHODIMP nsHyperTextAccessible::GetCharacterExtents(PRInt32 aOffset, PRInt32 *aX, PRInt32 *aY,
                                                          PRInt32 *aWidth, PRInt32 *aHeight,
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -90,16 +90,17 @@ include $(topsrcdir)/config/rules.mk
 		test_aria_roles.xul \
 		test_aria_token_attrs.html \
 		test_bug420863.html \
 	$(warning   test_childAtPoint.html temporarily disabled) \
 	$(warning	test_childAtPoint.xul temporarily disabled) \
 		test_descr.html \
 		test_editabletext_1.html \
 		test_editabletext_2.html \
+		test_elm_landmarks.html \
 		test_elm_listbox.xul \
 	$(warning   test_elm_media.html temporarily disabled) \
 		test_elm_nsApplicationAcc.html \
 		test_elm_plugin.html \
 		test_name.html \
 		test_name.xul \
 		test_name_button.html \
 		test_name_link.html \
--- a/accessible/tests/mochitest/events/test_statechange.html
+++ b/accessible/tests/mochitest/events/test_statechange.html
@@ -21,20 +21,16 @@
   <script type="application/javascript">
     ////////////////////////////////////////////////////////////////////////////
     // Invokers
 
     function makeEditableDoc(aDocNode, aIsEnabled)
     {
       this.DOMNode = aDocNode;
 
-      this.eventSeq = [
-        new invokerChecker(EVENT_STATE_CHANGE, getAccessible(this.DOMNode))
-      ];
-
       this.invoke = function editabledoc_invoke() {
         // Note: this should fire an EVENT_STATE_CHANGE
         this.DOMNode.designMode = 'on';
       };
 
       this.check = function editabledoc_check(aEvent) {
 
         testStates(aDocNode, 0, EXT_STATE_EDITABLE);
@@ -53,50 +49,79 @@
         ok(event.isEnabled(), "Expected editable state to be enabled");
       }
 
       this.getID = function editabledoc_getID() {
         return prettyName(aDocNode) + " editable state changed";
       };
     }
 
+    function invalidInput(aNodeOrID)
+    {
+      this.DOMNode = getNode(aNodeOrID);
+
+      this.invoke = function invalidInput_invoke() {
+        // Note: this should fire an EVENT_STATE_CHANGE
+        this.DOMNode.value = "I am too long";
+      };
+
+      this.check = function invalidInput_check() {
+        testStates(aNodeOrID, STATE_INVALID);
+      };
+
+      this.getID = function invalidInput_getID() {
+        return prettyName(aNodeOrID) + " became invalid";
+      };
+    }
+
     ////////////////////////////////////////////////////////////////////////////
     // Do tests
 
     var gQueue = null;
 
     // var gA11yEventDumpID = "eventdump"; // debug stuff
 
     function doTests()
     {
-      gQueue = new eventQueue();
+      gQueue = new eventQueue(nsIAccessibleEvent.EVENT_STATE_CHANGE);
 
       // Test delayed editable state change
       var doc = document.getElementById("iframe").contentDocument;
       gQueue.push(new makeEditableDoc(doc));
 
+      // invalid state change
+      gQueue.push(new invalidInput("maxlength"));
+
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=564471"
      title="Make state change events async">
     Mozilla Bug 564471
+  </a><br>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=555728"
+     title="Fire a11y event based on HTML5 constraint validation">
+    Mozilla Bug 555728
   </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div id="testContainer">
     <iframe id="iframe"></iframe>
   </div>
+
+  <input id="maxlength" maxlength="1">
+
   <div id="eventdump"></div>
 </body>
 </html>
--- a/accessible/tests/mochitest/role.js
+++ b/accessible/tests/mochitest/role.js
@@ -14,21 +14,23 @@ const ROLE_CHROME_WINDOW = nsIAccessible
 const ROLE_COMBOBOX = nsIAccessibleRole.ROLE_COMBOBOX;
 const ROLE_COMBOBOX_LIST = nsIAccessibleRole.ROLE_COMBOBOX_LIST;
 const ROLE_COMBOBOX_OPTION = nsIAccessibleRole.ROLE_COMBOBOX_OPTION;
 const ROLE_COLUMNHEADER = nsIAccessibleRole.ROLE_COLUMNHEADER;
 const ROLE_DIALOG = nsIAccessibleRole.ROLE_DIALOG;
 const ROLE_DOCUMENT = nsIAccessibleRole.ROLE_DOCUMENT;
 const ROLE_EMBEDDED_OBJECT = nsIAccessibleRole.ROLE_EMBEDDED_OBJECT;
 const ROLE_ENTRY = nsIAccessibleRole.ROLE_ENTRY;
+const ROLE_FOOTER = nsIAccessibleRole.ROLE_FOOTER;
 const ROLE_FLAT_EQUATION = nsIAccessibleRole.ROLE_FLAT_EQUATION;
 const ROLE_FORM = nsIAccessibleRole.ROLE_FORM;
 const ROLE_GRAPHIC = nsIAccessibleRole.ROLE_GRAPHIC;
 const ROLE_GRID_CELL = nsIAccessibleRole.ROLE_GRID_CELL;
 const ROLE_GROUPING = nsIAccessibleRole.ROLE_GROUPING;
+const ROLE_HEADER = nsIAccessibleRole.ROLE_HEADER;
 const ROLE_HEADING = nsIAccessibleRole.ROLE_HEADING;
 const ROLE_IMAGE_MAP = nsIAccessibleRole.ROLE_IMAGE_MAP;
 const ROLE_INTERNAL_FRAME = nsIAccessibleRole.ROLE_INTERNAL_FRAME;
 const ROLE_LABEL = nsIAccessibleRole.ROLE_LABEL;
 const ROLE_LINK = nsIAccessibleRole.ROLE_LINK;
 const ROLE_LIST = nsIAccessibleRole.ROLE_LIST;
 const ROLE_LISTBOX = nsIAccessibleRole.ROLE_LISTBOX;
 const ROLE_LISTITEM = nsIAccessibleRole.ROLE_LISTITEM;
--- a/accessible/tests/mochitest/states.js
+++ b/accessible/tests/mochitest/states.js
@@ -33,16 +33,17 @@ const STATE_UNAVAILABLE = nsIAccessibleS
 
 const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE;
 const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT;
 const EXT_STATE_EDITABLE = nsIAccessibleStates.EXT_STATE_EDITABLE;
 const EXT_STATE_EXPANDABLE = nsIAccessibleStates.EXT_STATE_EXPANDABLE;
 const EXT_STATE_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL;
 const EXT_STATE_MULTI_LINE = nsIAccessibleStates.EXT_STATE_MULTI_LINE;
 const EXT_STATE_SINGLE_LINE = nsIAccessibleStates.EXT_STATE_SINGLE_LINE;
+const EXT_STATE_STALE = nsIAccessibleStates.EXT_STATE_STALE;
 const EXT_STATE_SUPPORTS_AUTOCOMPLETION =
   nsIAccessibleStates.EXT_STATE_SUPPORTS_AUTOCOMPLETION;
 const EXT_STATE_VERTICAL = nsIAccessibleStates.EXT_STATE_VERTICAL;
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Test functions
 
--- a/accessible/tests/mochitest/states/test_docarticle.html
+++ b/accessible/tests/mochitest/states/test_docarticle.html
@@ -12,27 +12,28 @@
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
 
   <script type="application/javascript">
     function doTest()
-    {      
+    {
       var docAcc = getAccessible(document, [nsIAccessibleDocument]);
       if (docAcc) {
         testStates(docAcc, STATE_READONLY);
         testStates("article", STATE_READONLY);
         testStates("editable_article", 0, EXT_STATE_EDITABLE);
 
         document.designMode = "on";
 
         testStates(docAcc, 0, EXT_STATE_EDITABLE);
         testStates("article", 0, EXT_STATE_EDITABLE);
+        testStates("article", 0, EXT_STATE_EDITABLE);
         testStates("editable_article", 0, EXT_STATE_EDITABLE);
   
         document.designMode = "off";
 
         testStates(docAcc, STATE_READONLY);
         testStates("article", STATE_READONLY);
         testStates("editable_article", 0, EXT_STATE_EDITABLE);
       }
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_elm_landmarks.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>HTML landmark tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <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/javascript"
+          src="common.js"></script>
+  <script type="application/javascript"
+          src="role.js"></script>
+  <script type="application/javascript"
+          src="attributes.js"></script>
+
+  <script type="application/javascript">
+
+    function doTest()
+    {
+      testRole("nav", ROLE_SECTION);
+      testRole("header", ROLE_HEADER);
+      testRole("footer", ROLE_FOOTER);
+      testRole("article", ROLE_SECTION);
+
+      // Some AT may look for this
+      testAttrs("nav", {"xml-roles" : "navigation"}, true);
+      testAttrs("header", {"xml-roles" : "banner"}, true);
+      testAttrs("footer", {"xml-roles" : "contentinfo"}, true);
+      testAttrs("article", {"xml-roles" : "main"}, true);
+      testAttrs("document", {"xml-roles" : "document"}, true); // ARIA override
+
+      // And some AT may look for this
+      testAttrs("nav", {"tag" : "NAV"}, true);
+      testAttrs("header", {"tag" : "HEADER"}, true);
+      testAttrs("footer", {"tag" : "FOOTER"}, true);
+      testAttrs("article", {"tag" : "ARTICLE"}, true);
+      testAttrs("document", {"tag" : "ARTICLE"}, true); // no override expected
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="Provide mappings for html5 <nav> <header> <footer> <article>"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=593368">Bug 593368</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <nav id="nav">a nav</nav>
+  <header id="header">a header</header>
+  <footer id="footer">a footer</footer>
+  <article id="article">an article</article>
+
+  <article id="document" role="document">a document</article>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/test_name.html
+++ b/accessible/tests/mochitest/test_name.html
@@ -171,16 +171,24 @@
       testName("checkbox", "Play the Haliluya sound when new mail arrives");
 
       testName("comboinend", "This day was sunny");
       testName("combo6", "This day was");
 
       testName("textboxinend", "This day was sunny");
       testName("textbox2", "This day was");
 
+      // placeholder
+      testName("ph_password", "a placeholder");
+      testName("ph_text", "a placeholder");
+      testName("ph_textarea", "a placeholder");
+      testName("ph_text2", "a label");
+      testName("ph_textarea2", "a label");
+      testName("ph_text3", "a label");
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 
 </head>
@@ -191,16 +199,21 @@
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=444279"
      title="mochitest for accessible name calculating">
     Mozilla Bug 444279
   </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=530081"
      title="Clean up our tree walker ">
     Mozilla Bug 530081
+  </a><br>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=604391"
+     title="Use placeholder as name if name is otherwise empty">
+    Mozilla Bug 604391
   </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <!-- aria-label, simple label -->
   <span id="btn_simple_aria_label" role="button" aria-label="I am a button"/>
@@ -416,10 +429,23 @@
       </select></label>
 
     <label id="textboxinend">
       This day was
       <input id="textbox2" value="sunny">
     </label>
   </form>
 
+  <!-- placeholder  -->
+  <input id="ph_password" type="password" value="" placeholder="a placeholder" />
+  <input id="ph_text" type="text" placeholder="a placeholder" />
+  <textarea id="ph_textarea" cols="5" placeholder="a placeholder"></textarea>  
+
+  <!-- placeholder does not win -->
+  <input id="ph_text2" type="text" aria-label="a label" placeholder="meh" />
+  <textarea id="ph_textarea2" cols="5" aria-labelledby="ph_text2" 
+            placeholder="meh"></textarea>
+
+  <label for="ph_text3">a label</label>
+  <input id="ph_text3" placeholder="meh" />
+
 </body>
 </html>
--- a/accessible/tests/mochitest/treeupdate/Makefile.in
+++ b/accessible/tests/mochitest/treeupdate/Makefile.in
@@ -41,16 +41,17 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible/treeupdate
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
+		test_doc.html \
 		test_list_editabledoc.html \
 		test_list.html \
 		test_recreation.html \
 		test_tableinsubtree.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_doc.html
@@ -0,0 +1,370 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>Test document root content mutations</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <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/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Helpers
+
+    function getDocNode(aID)
+    {
+      return getNode(aID).contentDocument;
+    }
+    function getDocChildNode(aID)
+    {
+      return getDocNode(aID).body.firstChild;
+    }
+
+    function rootContentReplaced(aID, aTextName)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, getDocChildNode, aID),
+        new invokerChecker(EVENT_REORDER, getDocNode, aID)
+      ];
+
+      this.finalCheck = function rootContentReplaced_finalCheck()
+      {
+        var tree = {
+          role: ROLE_DOCUMENT,
+          children: [
+            {
+              role: ROLE_TEXT_LEAF,
+              name: aTextName
+            }
+          ]
+        };
+        testAccessibleTree(getDocNode(aID), tree);
+      }
+    }
+
+    function rootContentRemoved(aID)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, null),
+        new invokerChecker(EVENT_REORDER, getDocNode, aID)
+      ];
+
+      this.preinvoke = function rootContentRemoved_preinvoke()
+      {
+        // Set up target for hide event before we invoke.
+        var text = getAccessible(getAccessible(getDocNode(aID)).firstChild,
+                                               [nsIAccessNode]).DOMNode;
+        this.eventSeq[0].target = text;
+      }
+
+      this.finalCheck = function rootContentRemoved_finalCheck()
+      {
+        var tree = {
+          role: ROLE_DOCUMENT,
+          states: {
+            // Out of date root content involves stale state presence.
+            states: 0,
+            extraStates: EXT_STATE_STALE
+          },
+          children: [ ]
+        };
+        testAccessibleTree(getDocNode(aID), tree);
+      }
+    }
+
+    function rootContentInserted(aID, aTextName)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, getDocChildNode, aID),
+        new invokerChecker(EVENT_REORDER, getDocNode, aID)
+      ];
+
+      this.finalCheck = function rootContentInserted_finalCheck()
+      {
+        var tree = {
+          role: ROLE_DOCUMENT,
+          states: {
+            states: 0,
+            extraStates: 0,
+            absentStates: 0,
+            absentExtraStates: EXT_STATE_STALE
+          },
+          children: [
+            {
+              role: ROLE_TEXT_LEAF,
+              name: aTextName
+            }
+          ]
+        };
+        testAccessibleTree(getDocNode(aID), tree);
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers
+
+    function writeIFrameDoc(aID)
+    {
+      this.__proto__ = new rootContentReplaced(aID, "hello");
+
+      this.invoke = function writeIFrameDoc_invoke()
+      {
+        var docNode = getDocNode(aID);
+
+        // We can't use open/write/close outside of iframe document because of
+        // security error.
+        var script = docNode.createElement("script");
+        script.textContent = "document.open(); document.write('hello'); document.close();";
+        docNode.body.appendChild(script);
+      }
+
+      this.getID = function writeIFrameDoc_getID()
+      {
+        return "write document";
+      }
+    }
+
+    /**
+     * Replace HTML element.
+     */
+    function replaceIFrameHTMLElm(aID)
+    {
+      this.__proto__ = new rootContentReplaced(aID, "New Wave");
+
+      this.invoke = function replaceIFrameHTMLElm_invoke()
+      {
+        var docNode = getDocNode(aID);
+        var newHTMLNode = docNode.createElement("html");
+        var newBodyNode = docNode.createElement("body");
+        var newTextNode = docNode.createTextNode("New Wave");
+        newBodyNode.appendChild(newTextNode);
+        newHTMLNode.appendChild(newBodyNode);
+        docNode.replaceChild(newHTMLNode, docNode.documentElement);
+      }
+
+      this.getID = function replaceIFrameBody_getID()
+      {
+        return "replace HTML element";
+      }
+    }
+
+    /**
+     * Replace HTML body.
+     */
+    function replaceIFrameBody(aID)
+    {
+      this.__proto__ = new rootContentReplaced(aID, "New Hello");
+
+      this.invoke = function replaceIFrameBody_invoke()
+      {
+        var docNode = getDocNode(aID);
+        var newBodyNode = docNode.createElement("body");
+        var newTextNode = docNode.createTextNode("New Hello");
+        newBodyNode.appendChild(newTextNode);
+        docNode.documentElement.replaceChild(newBodyNode, docNode.body);
+      }
+
+      this.finalCheck = function replaceIFrameBody_finalCheck()
+      {
+        var tree = {
+          role: ROLE_DOCUMENT,
+          children: [
+            {
+              role: ROLE_TEXT_LEAF,
+              name: "New Hello"
+            }
+          ]
+        };
+        testAccessibleTree(getDocNode(aID), tree);
+      }
+
+      this.getID = function replaceIFrameBody_getID()
+      {
+        return "replace body";
+      }
+    }
+
+    /**
+     * Open/close document pair.
+     */
+    function openIFrameDoc(aID)
+    {
+      this.__proto__ = new rootContentRemoved(aID);
+
+      this.invoke = function openIFrameDoc_invoke()
+      {
+        this.preinvoke();
+
+        // Open document.
+        var docNode = getDocNode(aID);
+        var script = docNode.createElement("script");
+        script.textContent = "function closeMe() { document.write('Works?'); document.close(); } window.closeMe = closeMe; document.open();";
+        docNode.body.appendChild(script);
+      }
+
+      this.getID = function openIFrameDoc_getID()
+      {
+        return "open document";
+      }
+    }
+
+    function closeIFrameDoc(aID)
+    {
+      this.__proto__ = new rootContentInserted(aID, "Works?");
+
+      this.invoke = function closeIFrameDoc_invoke()
+      {
+        // Write and close document.
+        getDocNode(aID).write('Works?'); getDocNode(aID).close();
+      }
+
+      this.getID = function closeIFrameDoc_getID()
+      {
+        return "close document";
+      }
+    }
+
+    /**
+     * Remove/insert HTML element pair.
+     */
+    function removeHTMLFromIFrameDoc(aID)
+    {
+      this.__proto__ = new rootContentRemoved(aID);
+
+      this.invoke = function removeHTMLFromIFrameDoc_invoke()
+      {
+        this.preinvoke();
+
+        // Remove HTML element.
+        var docNode = getDocNode(aID);
+        docNode.removeChild(docNode.firstChild);
+      }
+
+      this.getID = function removeHTMLFromIFrameDoc_getID()
+      {
+        return "remove HTML element";
+      }
+    }
+
+    function insertHTMLToIFrameDoc(aID)
+    {
+      this.__proto__ = new rootContentInserted(aID, "Haha");
+
+      this.invoke = function insertHTMLToIFrameDoc_invoke()
+      {
+        // Insert HTML element.
+        var docNode = getDocNode(aID);
+        var html = docNode.createElement("html");
+        var body = docNode.createElement("body");
+        var text = docNode.createTextNode("Haha");
+        body.appendChild(text);
+        html.appendChild(body);
+        docNode.appendChild(html);
+      }
+
+      this.getID = function insertHTMLToIFrameDoc_getID()
+      {
+        return "insert HTML element document";
+      }
+    }
+
+    /**
+     * Remove/insert HTML body pair.
+     */
+    function removeBodyFromIFrameDoc(aID)
+    {
+      this.__proto__ = new rootContentRemoved(aID);
+
+      this.invoke = function removeBodyFromIFrameDoc_invoke()
+      {
+        this.preinvoke();
+
+        // Remove body element.
+        var docNode = getDocNode(aID);
+        docNode.documentElement.removeChild(docNode.body);
+      }
+
+      this.getID = function removeBodyFromIFrameDoc_getID()
+      {
+        return "remove body element";
+      }
+    }
+
+    function insertBodyToIFrameDoc(aID)
+    {
+      this.__proto__ = new rootContentInserted(aID, "Yo ho ho i butylka roma!");
+
+      this.invoke = function insertBodyToIFrameDoc_invoke()
+      {
+        // Insert body element.
+        var docNode = getDocNode(aID);
+        var body = docNode.createElement("body");
+        var text = docNode.createTextNode("Yo ho ho i butylka roma!");
+        body.appendChild(text);
+        docNode.documentElement.appendChild(body);
+      }
+
+      this.getID = function insertBodyToIFrameDoc_getID()
+      {
+        return "insert body element";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+
+    //gA11yEventDumpID = "eventdump"; // debug stuff
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new writeIFrameDoc("iframe"));
+      gQueue.push(new replaceIFrameHTMLElm("iframe"));
+      gQueue.push(new replaceIFrameBody("iframe"));
+      gQueue.push(new openIFrameDoc("iframe"));
+      gQueue.push(new closeIFrameDoc("iframe"));
+      gQueue.push(new removeHTMLFromIFrameDoc("iframe"));
+      gQueue.push(new insertHTMLToIFrameDoc("iframe"));
+      gQueue.push(new removeBodyFromIFrameDoc("iframe"));
+      gQueue.push(new insertBodyToIFrameDoc("iframe"));
+
+      gQueue.invoke(); // SimpleTest.finish() will be called in the end
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="Update accessible tree when root element is changed"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=606082">Mozilla Bug 606082</a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <iframe id="iframe"></iframe>
+
+  <div id="eventdump"></div>
+</body>
+</html>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -54,19 +54,19 @@ pref("browser.chromeURL","chrome://brows
 pref("browser.hiddenWindowChromeURL", "chrome://browser/content/hiddenWindow.xul");
 
 // Enables some extra Extension System Logging (can reduce performance)
 pref("extensions.logging.enabled", false);
 
 // Preferences for AMO integration
 pref("extensions.getAddons.cache.enabled", true);
 pref("extensions.getAddons.maxResults", 15);
-pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/guid:%IDS%");
+pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/guid:%IDS%?src=firefox");
 pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/%APP%/search?q=%TERMS%");
-pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%");
+pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%?src=firefox");
 pref("extensions.webservice.discoverURL", "https://services.addons.mozilla.org/%LOCALE%/%APP%/discovery/%VERSION%/%OS%");
 
 // Blocklist preferences
 pref("extensions.blocklist.enabled", true);
 pref("extensions.blocklist.interval", 86400);
 // Controls what level the blocklist switches from warning about items to forcibly
 // blocking them.
 pref("extensions.blocklist.level", 2);
@@ -234,16 +234,18 @@ pref("general.autoScroll", true);
 // is the default browser.
 pref("browser.shell.checkDefaultBrowser", true);
 
 // 0 = blank, 1 = home (browser.startup.homepage), 2 = last visited page, 3 = resume previous browser session
 // The behavior of option 3 is detailed at: http://wiki.mozilla.org/Session_Restore
 pref("browser.startup.page",                1);
 pref("browser.startup.homepage",            "chrome://branding/locale/browserconfig.properties");
 
+pref("browser.aboutHomeSnippets.updateUrl", "http://snippets.mozilla.com/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
+
 pref("browser.enable_automatic_image_resizing", true);
 pref("browser.chrome.site_icons", true);
 pref("browser.chrome.favicons", true);
 pref("browser.warnOnQuit", true);
 pref("browser.warnOnRestart", true);
 pref("browser.fullscreen.autohide", true);
 pref("browser.fullscreen.animateUp", 1);
 
--- a/browser/base/Makefile.in
+++ b/browser/base/Makefile.in
@@ -77,13 +77,14 @@ endif
 
 ifneq (,$(filter windows cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
 ifneq ($(OS_ARCH),WINCE)
 DEFINES += -DCONTEXT_COPY_IMAGE_CONTENTS=1
 endif
 endif
 
 ifneq (,$(filter windows, $(MOZ_WIDGET_TOOLKIT)))
+DEFINES += -DCAN_DRAW_IN_TITLEBAR=1
 DEFINES += -DMENUBAR_CAN_AUTOHIDE=1
 endif
 
 libs::
 	$(NSINSTALL) $(srcdir)/content/tabview/modules/* $(FINAL_TARGET)/modules/tabview
--- a/browser/base/content/aboutHome.js
+++ b/browser/base/content/aboutHome.js
@@ -134,60 +134,70 @@ function setupSearchEngine()
 
 function loadSnippets()
 {
   // Check last snippets update.
   let lastUpdate = localStorage["snippets-last-update"];
   let updateURL = localStorage["snippets-update-url"];
   if (updateURL && (!lastUpdate ||
                     Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS)) {
+    // Even if fetching should fail we don't want to spam the server, thus
+    // set the last update time regardless its results.  Will retry tomorrow.
+    localStorage["snippets-last-update"] = Date.now();
+
     // Try to update from network.
     let xhr = new XMLHttpRequest();
     xhr.open('GET', updateURL, true);
     xhr.onerror = function (event) {
       showSnippets();
     };
     xhr.onload = function (event)
     {
       if (xhr.status == 200) {
         localStorage["snippets"] = xhr.responseText;
-        localStorage["snippets-last-update"] = Date.now();
       }
       showSnippets();
     };
     xhr.send(null);
   } else {
     showSnippets();
   }
 }
 
 function showSnippets()
 {
   let snippets = localStorage["snippets"];
+  // If there are remotely fetched snippets, try to to show them.
   if (snippets) {
     let snippetsElt = document.getElementById("snippets");
-    snippetsElt.innerHTML = snippets;
-    // Scripts injected by innerHTML are inactive, so we have to relocate them
-    // through DOM manipulation to activate their contents.
-    Array.forEach(snippetsElt.getElementsByTagName("script"), function(elt) {
-      let relocatedScript = document.createElement("script");
-      relocatedScript.type = "text/javascript;version=1.8";
-      relocatedScript.text = elt.text;
-      elt.parentNode.replaceChild(relocatedScript, elt);
-    });
-    snippetsElt.hidden = false;
-  } else {
-    // If there are no saved snippets, show one of the default ones.
-    let defaultSnippetsElt = document.getElementById("defaultSnippets");
-    let entries = defaultSnippetsElt.querySelectorAll("span");
-    // Choose a random snippet.  Assume there is always at least one.
-    let randIndex = Math.round(Math.random() * (entries.length - 1));
-    let entry = entries[randIndex];
-    // Inject url in the eventual link.
-    if (DEFAULT_SNIPPETS_URLS[randIndex]) {
-      let links = entry.getElementsByTagName("a");
-      if (links.length != 1)
-        return; // Something is messed up in this entry, we support just 1 link.
-      links[0].href = DEFAULT_SNIPPETS_URLS[randIndex];
+    // Injecting snippets can throw if they're invalid XML.
+    try {
+      snippetsElt.innerHTML = snippets;
+      // Scripts injected by innerHTML are inactive, so we have to relocate them
+      // through DOM manipulation to activate their contents.
+      Array.forEach(snippetsElt.getElementsByTagName("script"), function(elt) {
+        let relocatedScript = document.createElement("script");
+        relocatedScript.type = "text/javascript;version=1.8";
+        relocatedScript.text = elt.text;
+        elt.parentNode.replaceChild(relocatedScript, elt);
+      });
+      snippetsElt.hidden = false;
+      return;
+    } catch (ex) {
+      // Bad content, continue to show default snippets.
     }
-    entry.hidden = false;
   }
+
+  // Show default snippets otherwise.
+  let defaultSnippetsElt = document.getElementById("defaultSnippets");
+  let entries = defaultSnippetsElt.querySelectorAll("span");
+  // Choose a random snippet.  Assume there is always at least one.
+  let randIndex = Math.round(Math.random() * (entries.length - 1));
+  let entry = entries[randIndex];
+  // Inject url in the eventual link.
+  if (DEFAULT_SNIPPETS_URLS[randIndex]) {
+    let links = entry.getElementsByTagName("a");
+    if (links.length != 1)
+      return; // Something is messed up in this entry, we support just 1 link.
+    links[0].href = DEFAULT_SNIPPETS_URLS[randIndex];
+  }
+  entry.hidden = false;
 }
--- a/browser/base/content/baseMenuOverlay.xul
+++ b/browser/base/content/baseMenuOverlay.xul
@@ -108,25 +108,16 @@
                   label="&helpFeedbackPage.label;"
                   oncommand="openFeedbackPage()"
                   onclick="checkForMiddleClick(this, event);"/>
         <menuitem id="helpSafeMode"
                   accesskey="&helpSafeMode.accesskey;"
                   label="&helpSafeMode.label;"
                   oncommand="safeModeRestart();"/>
         <menuseparator/>
-        <menuseparator id="updateSeparator"/>
-#ifdef XP_MACOSX
-#ifdef MOZ_UPDATER
-        <menuitem id="checkForUpdates"
-                  label="&updateCmd.label;"
-                  class="menuitem-iconic"
-                  oncommand="checkForUpdates();"/>
-#endif
-#endif
         <menuseparator id="aboutSeparator"/>
         <menuitem id="aboutName"
                   accesskey="&aboutProduct.accesskey;"
                   label="&aboutProduct.label;"
                   oncommand="openAboutDialog();"/>
       </menupopup>
     </menu>
 
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -434,21 +434,27 @@
                onpopupshowing="if (!this.parentNode._placesView)
                                  new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
                tooltip="bhTooltip" popupsinherittooltip="true">
       <menuitem id="menu_bookmarkThisPage"
                 label="&bookmarkThisPageCmd.label;"
                 command="Browser:AddBookmarkAs"
                 key="addBookmarkAsKb"/>
       <menuitem id="subscribeToPageMenuitem"
+#ifndef XP_MACOSX
+                class="menuitem-iconic"
+#endif
                 label="&subscribeToPageMenuitem.label;"
                 oncommand="return FeedHandler.subscribeToFeed(null, event);"
                 onclick="checkForMiddleClick(this, event);"
                 observes="singleFeedMenuitemState"/>
       <menu id="subscribeToPageMenupopup"
+#ifndef XP_MACOSX
+            class="menu-iconic"
+#endif
             label="&subscribeToPageMenupopup.label;"
             observes="multipleFeedsMenuState">
         <menupopup id="subscribeToPageSubmenuMenupopup"
                    onpopupshowing="return FeedHandler.buildFeedList(event.target);"
                    oncommand="return FeedHandler.subscribeToFeed(null, event);"
                    onclick="checkForMiddleClick(this, event);"/>
       </menu>
       <menuitem id="menu_bookmarkAllTabs"
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -46,17 +46,17 @@ tabbrowser {
 
 .tab-throbber,
 .tab-label,
 .tab-icon-image,
 .tab-close-button {
   -moz-transition: opacity .25s;
 }
 
-.tabbrowser-tab[pinned] {
+.tabbrowser-tabs:not([pinnedonly]) > .tabbrowser-tab[pinned] {
   position: fixed;
   display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
 }
 
 #alltabs-popup {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
 }
 
@@ -75,17 +75,17 @@ toolbar[printpreview="true"] {
 #TabsToolbar {
   -moz-box-ordinal-group: 100;
 }
 
 #TabsToolbar[tabsontop="true"] {
   -moz-box-ordinal-group: 10;
 }
 
-%ifdef MENUBAR_CAN_AUTOHIDE
+%ifdef CAN_DRAW_IN_TITLEBAR
 #main-window[inFullscreen] > #titlebar {
   display: none;
 }
 
 #titlebar {
   -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
 }
 %endif
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1908,31 +1908,31 @@ function BrowserReload() {
 }
 
 function BrowserReloadSkipCache() {
   // Bypass proxy and cache.
   const reloadFlags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
   BrowserReloadWithFlags(reloadFlags);
 }
 
-function BrowserHome()
-{
-  var homePage = gHomeButton.getHomePage();
-  loadOneOrMoreURIs(homePage);
-}
-
+var BrowserHome = BrowserGoHome;
 function BrowserGoHome(aEvent) {
   if (aEvent && "button" in aEvent &&
       aEvent.button == 2) // right-click: do nothing
     return;
 
   var homePage = gHomeButton.getHomePage();
   var where = whereToOpenLink(aEvent, false, true);
   var urls;
 
+  // Home page should open in a new tab when current tab is an app tab
+  if (where == "current" &&
+      gBrowser.selectedTab.pinned)
+    where = "tab";
+
   // openUILinkIn in utilityOverlay.js doesn't handle loading multiple pages
   switch (where) {
   case "current":
     loadOneOrMoreURIs(homePage);
     break;
   case "tabshifted":
   case "tab":
     urls = homePage.split("|");
@@ -3484,20 +3484,21 @@ function BrowserToolboxCustomizeDone(aTo
 #ifndef XP_MACOSX
     updateEditUIVisibility();
 #endif
   }
 
   PlacesToolbarHelper.customizeDone();
   BookmarksMenuButton.customizeDone();
 
+  // The url bar splitter state is dependent on whether stop/reload
+  // and the location bar are combined, so we need this ordering
+  CombinedStopReload.init();
   UpdateUrlbarSearchSplitterState();
 
-  CombinedStopReload.init();
-
   // Update the urlbar
   if (gURLBar) {
     URLBarSetURI();
     XULBrowserWindow.asyncUpdateUI();
     PlacesStarButton.updateState();
   }
 
   // Re-enable parts of the UI we disabled during the dialog
@@ -4718,24 +4719,28 @@ var TabsOnTop = {
 
 #ifdef MENUBAR_CAN_AUTOHIDE
 function updateAppButtonDisplay() {
   var displayAppButton =
     !gInPrintPreviewMode &&
     window.menubar.visible &&
     document.getElementById("toolbar-menubar").getAttribute("autohide") == "true";
 
+#ifdef CAN_DRAW_IN_TITLEBAR
   document.getElementById("titlebar").hidden = !displayAppButton;
 
   if (displayAppButton)
     document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1");
   else
     document.documentElement.removeAttribute("chromemargin");
-}
-
+#endif
+}
+#endif
+
+#ifdef CAN_DRAW_IN_TITLEBAR
 function onTitlebarMaxClick() {
   if (window.windowState == window.STATE_MAXIMIZED)
     window.restore();
   else
     window.maximize();
 }
 #endif
 
@@ -4978,165 +4983,191 @@ function asyncOpenWebPanel(event)
 }
 
 /*
  * - [ Dependencies ] ---------------------------------------------------------
  *  utilityOverlay.js:
  *    - gatherTextUnder
  */
 
- // Called whenever the user clicks in the content area,
- // except when left-clicking on links (special case)
- // should always return true for click to go through
- function contentAreaClick(event, fieldNormalClicks)
- {
-   if (!event.isTrusted || event.getPreventDefault()) {
-     return true;
-   }
-
-   var target = event.target;
-   var linkNode;
-
-   if (target instanceof HTMLAnchorElement ||
-       target instanceof HTMLAreaElement ||
-       target instanceof HTMLLinkElement) {
-     if (target.hasAttribute("href"))
-       linkNode = target;
-
-     // xxxmpc: this is kind of a hack to work around a Gecko bug (see bug 266932)
-     // we're going to walk up the DOM looking for a parent link node,
-     // this shouldn't be necessary, but we're matching the existing behaviour for left click
-     var parent = target.parentNode;
-     while (parent) {
-       if (parent instanceof HTMLAnchorElement ||
-           parent instanceof HTMLAreaElement ||
-           parent instanceof HTMLLinkElement) {
-           if (parent.hasAttribute("href"))
-             linkNode = parent;
-       }
-       parent = parent.parentNode;
-     }
-   }
-   else {
-     linkNode = event.originalTarget;
-     while (linkNode && !(linkNode instanceof HTMLAnchorElement))
-       linkNode = linkNode.parentNode;
-     // <a> cannot be nested.  So if we find an anchor without an
-     // href, there is no useful <a> around the target
-     if (linkNode && !linkNode.hasAttribute("href"))
-       linkNode = null;
-   }
-   var wrapper = null;
-   if (linkNode) {
-     wrapper = linkNode;
-     if (event.button == 0 && !event.ctrlKey && !event.shiftKey &&
-         !event.altKey && !event.metaKey) {
-       // A Web panel's links should target the main content area.  Do this
-       // if no modifier keys are down and if there's no target or the target equals
-       // _main (the IE convention) or _content (the Mozilla convention).
-       // XXX Now that markLinkVisited is gone, we may not need to field _main and
-       // _content here.
-       target = wrapper.getAttribute("target");
-       if (fieldNormalClicks &&
-           (!target || target == "_content" || target  == "_main"))
-         // IE uses _main, SeaMonkey uses _content, we support both
-       {
-         if (!wrapper.href)
-           return true;
-         if (wrapper.getAttribute("onclick"))
-           return true;
-         // javascript links should be executed in the current browser
-         if (wrapper.href.substr(0, 11) === "javascript:")
-           return true;
-         // data links should be executed in the current browser
-         if (wrapper.href.substr(0, 5) === "data:")
-           return true;
-
-         try {
-           urlSecurityCheck(wrapper.href, wrapper.ownerDocument.nodePrincipal);
-         }
-         catch(ex) {
-           return false;
-         }
-
-         var postData = { };
-         var url = getShortcutOrURI(wrapper.href, postData);
-         if (!url)
-           return true;
-         loadURI(url, null, postData.value, false);
-         event.preventDefault();
-         return false;
-       }
-       else if (linkNode.getAttribute("rel") == "sidebar") {
-         // This is the Opera convention for a special link that - when clicked - allows
-         // you to add a sidebar panel.  We support the Opera convention here.  The link's
-         // title attribute contains the title that should be used for the sidebar panel.
-         PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(wrapper.href),
-                                                wrapper.getAttribute("title"),
-                                                null, null, true, true);
-         event.preventDefault();
-         return false;
-       }
-     }
-     else {
-       handleLinkClick(event, wrapper.href, linkNode);
-     }
-
-     return true;
-   } else {
-     // Try simple XLink
-     var href, realHref, baseURI;
-     linkNode = target;
-     while (linkNode) {
-       if (linkNode.nodeType == Node.ELEMENT_NODE) {
-         wrapper = linkNode;
-
-         realHref = wrapper.getAttributeNS("http://www.w3.org/1999/xlink", "href");
-         if (realHref) {
-           href = realHref;
-           baseURI = wrapper.baseURI
-         }
-       }
-       linkNode = linkNode.parentNode;
-     }
-     if (href) {
-       href = makeURLAbsolute(baseURI, href);
-       handleLinkClick(event, href, null);
-       return true;
-     }
-   }
-   if (event.button == 1 &&
-       gPrefService.getBoolPref("middlemouse.contentLoadURL") &&
-       !gPrefService.getBoolPref("general.autoScroll")) {
-     middleMousePaste(event);
-   }
-   return true;
- }
-
+/**
+ * Extracts linkNode and href for the current click target.
+ *
+ * @param event
+ *        The click event.
+ * @return [href, linkNode].
+ *
+ * @note linkNode will be null if the click wasn't on an anchor
+ *       element (or XLink).
+ */
+function hrefAndLinkNodeForClickEvent(event)
+{
+  function isHTMLLink(aNode)
+  {
+    return aNode instanceof HTMLAnchorElement ||
+           aNode instanceof HTMLAreaElement ||
+           aNode instanceof HTMLLinkElement;
+  }
+
+  let linkNode;
+  if (isHTMLLink(event.target)) {
+    // This is a hack to work around Gecko bug 266932.
+    // Walk up the DOM looking for a parent link node, to match the existing
+    // behaviour for left click.
+    // TODO: this is no more needed and should be removed in bug 325652.
+    let node = event.target;
+    while (node) {
+      if (isHTMLLink(node) && node.hasAttribute("href"))
+        linkNode = node;
+      node = node.parentNode;
+    }
+  }
+  else {
+    let node = event.originalTarget;
+    while (node && !(node instanceof HTMLAnchorElement)) {
+      node = node.parentNode;
+    }
+    // <a> cannot be nested.  So if we find an anchor without an
+    // href, there is no useful <a> around the target.
+    if (node && node.hasAttribute("href"))
+      linkNode = node;
+  }
+
+  if (linkNode)
+    return [linkNode.href, linkNode];
+
+  // If there is no linkNode, try simple XLink.
+  let href, baseURI;
+  let node = event.target;
+  while (node) {
+    if (node.nodeType == Node.ELEMENT_NODE) {
+      href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
+      if (href)
+        baseURI = node.baseURI;
+    }
+    node = node.parentNode;
+  }
+
+  // In case of XLink, we don't return the node we got href from since
+  // callers expect <a>-like elements.
+  return [href ? makeURLAbsolute(baseURI, href) : null, null];
+}
+
+/**
+ * Called whenever the user clicks in the content area.
+ *
+ * @param event
+ *        The click event.
+ * @param isPanelClick
+ *        Whether the event comes from a web panel.
+ * @note default event is prevented if the click is handled.
+ */
+function contentAreaClick(event, isPanelClick)
+{
+  if (!event.isTrusted || event.getPreventDefault() || event.button == 2)
+    return true;
+
+  let [href, linkNode] = hrefAndLinkNodeForClickEvent(event);
+  if (!href) {
+    // Not a link, handle middle mouse navigation.
+    if (event.button == 1 &&
+        gPrefService.getBoolPref("middlemouse.contentLoadURL") &&
+        !gPrefService.getBoolPref("general.autoScroll")) {
+      middleMousePaste(event);
+      event.preventDefault();
+    }
+    return true;
+  }
+
+  // This code only applies if we have a linkNode (i.e. clicks on real anchor
+  // elements, as opposed to XLink).
+  if (linkNode && event.button == 0 &&
+      !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
+    // A Web panel's links should target the main content area.  Do this
+    // if no modifier keys are down and if there's no target or the target
+    // equals _main (the IE convention) or _content (the Mozilla convention).
+    let target = linkNode.target;
+    let mainTarget = !target || target == "_content" || target  == "_main";
+    if (isPanelClick && mainTarget) {
+      // javascript and data links should be executed in the current browser.
+      if (linkNode.getAttribute("onclick") ||
+          href.substr(0, 11) === "javascript:" ||
+          href.substr(0, 5) === "data:")
+        return true;
+
+      try {
+        urlSecurityCheck(href, linkNode.ownerDocument.nodePrincipal);
+      }
+      catch(ex) {
+        // Prevent loading unsecure destinations.
+        event.preventDefault();
+        return true;
+      }
+
+      let postData = {};
+      let url = getShortcutOrURI(href, postData);
+      if (!url)
+        return true;
+      loadURI(url, null, postData.value, false);
+      event.preventDefault();
+      return true;
+    }
+
+    if (linkNode.getAttribute("rel") == "sidebar") {
+      // This is the Opera convention for a special link that, when clicked,
+      // allows to add a sidebar panel.  The link's title attribute contains
+      // the title that should be used for the sidebar panel.
+      PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(href),
+                                             linkNode.getAttribute("title"),
+                                             null, null, true, true);
+      event.preventDefault();
+      return true;
+    }
+  }
+
+  handleLinkClick(event, href, linkNode);
+
+  // Mark the page as a user followed link.  This is done so that history can
+  // distinguish automatic embed visits from user activated ones.  For example
+  // pages loaded in frames are embed visits and lost with the session, while
+  // visits across frames should be preserved.
+  try {
+    PlacesUIUtils.markPageAsFollowedLink(href);
+  } catch (ex) { /* Skip invalid URIs. */ }
+
+  return true;
+}
+
+/**
+ * Handles clicks on links.
+ *
+ * @return true if the click event was handled, false otherwise.
+ */
 function handleLinkClick(event, href, linkNode) {
   if (event.button == 2) // right click
     return false;
 
   var where = whereToOpenLink(event);
   if (where == "current")
     return false;
 
   var doc = event.target.ownerDocument;
 
   if (where == "save") {
     saveURL(href, linkNode ? gatherTextUnder(linkNode) : "", null, true,
             true, doc.documentURIObject);
+    event.preventDefault();
     return true;
   }
 
   urlSecurityCheck(href, doc.nodePrincipal);
   openLinkIn(href, where, { fromContent: true,
                             referrerURI: doc.documentURIObject,
                             charset: doc.characterSet });
-  event.stopPropagation();
+  event.preventDefault();
   return true;
 }
 
 function middleMousePaste(event) {
   var url = getShortcutOrURI(readFromClipboard());
   try {
     makeURI(url);
   } catch (ex) {
@@ -7830,27 +7861,21 @@ var LightWeightThemeWebInstaller = {
 function switchToTabHavingURI(aURI, aOpenNew, aCallback) {
   function switchIfURIInWindow(aWindow) {
     if (!("gBrowser" in aWindow))
       return false;
     let browsers = aWindow.gBrowser.browsers;
     for (let i = 0; i < browsers.length; i++) {
       let browser = browsers[i];
       if (browser.currentURI.equals(aURI)) {
-        gURLBar.handleRevert();
-        // We need the current tab so we can check if we should close it
-        let prevTab = gBrowser.selectedTab;
         // Focus the matching window & tab
         aWindow.focus();
         aWindow.gBrowser.tabContainer.selectedIndex = i;
         if (aCallback)
           aCallback(browser);
-        // Close the previously selected tab if it was empty
-        if (isTabEmpty(prevTab))
-          gBrowser.removeTab(prevTab);
         return true;
       }
     }
     return false;
   }
 
   // This can be passed either nsIURI or a string.
   if (!(aURI instanceof Ci.nsIURI))
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -424,39 +424,35 @@
       <iframe id="customizeToolbarSheetIFrame"
               style="&dialog.style;"
               hidden="true"/>
     </panel>
 
     <tooltip id="tabbrowser-tab-tooltip" onpopupshowing="gBrowser.createTooltip(event);"/>
   </popupset>
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-  <vbox id="titlebar">
+#ifdef CAN_DRAW_IN_TITLEBAR
+<vbox id="titlebar">
   <hbox id="titlebar-content">
-  <hbox id="appmenu-button-container" align="start">
-  <button id="appmenu-button"
-          type="menu"
-#ifdef XP_WIN
-          label="&brandShortName;"
-#else
-          label="&appMenuButton.label;"
-#endif
-          style="-moz-user-focus: ignore;">
+    <hbox id="appmenu-button-container" align="start">
+      <button id="appmenu-button"
+              type="menu"
+              label="&brandShortName;"
+              style="-moz-user-focus: ignore;">
 #include browser-appmenu.inc
-  </button>
+      </button>
+    </hbox>
+    <spacer id="titlebar-spacer" flex="1"/>
+    <hbox id="titlebar-buttonbox">
+      <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
+      <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
+      <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
+    </hbox>
   </hbox>
-  <spacer id="titlebar-spacer" flex="1"/>
-  <hbox id="titlebar-buttonbox">
-    <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
-    <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
-    <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
-  </hbox>
-  </hbox>
-  </vbox>
+</vbox>
 #endif
 
 <deck flex="1" id="tab-view-deck">
 <vbox flex="1">
 
   <toolbox id="navigator-toolbox"
            defaultmode="icons" mode="icons"
 #ifdef WINCE
@@ -575,23 +571,26 @@
                    class="urlbar-icon"
                    onclick="PlacesStarButton.onClick(event);"/>
             <image id="go-button"
                    class="urlbar-icon"
                    tooltiptext="&goEndCap.tooltip;"
                    onclick="gURLBar.handleCommand(event);"/>
           </hbox>
           <toolbarbutton id="urlbar-go-button"
+                         class="chromeclass-toolbar-additional"
                          onclick="gURLBar.handleCommand(event);"
                          tooltiptext="&goEndCap.tooltip;"/>
           <toolbarbutton id="urlbar-reload-button"
+                         class="chromeclass-toolbar-additional"
                          command="Browser:ReloadOrDuplicate"
                          onclick="checkForMiddleClick(this, event);"
                          tooltiptext="&reloadButton.tooltip;"/>
           <toolbarbutton id="urlbar-stop-button"
+                         class="chromeclass-toolbar-additional"
                          command="Browser:Stop"
                          tooltiptext="&stopButton.tooltip;"/>
         </textbox>
       </toolbaritem>
 
       <toolbarbutton id="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&reloadCmd.label;" removable="true"
                      command="Browser:ReloadOrDuplicate"
@@ -647,21 +646,27 @@
             <menuitem id="BMB_bookmarkThisPage"
 #ifndef XP_MACOSX
                       class="menuitem-iconic"
 #endif
                       label="&bookmarkThisPageCmd.label;"
                       command="Browser:AddBookmarkAs"
                       key="addBookmarkAsKb"/>
             <menuitem id="BMB_subscribeToPageMenuitem"
+#ifndef XP_MACOSX
+                      class="menuitem-iconic"
+#endif
                       label="&subscribeToPageMenuitem.label;"
                       oncommand="return FeedHandler.subscribeToFeed(null, event);"
                       onclick="checkForMiddleClick(this, event);"
                       observes="singleFeedMenuitemState"/>
             <menu id="BMB_subscribeToPageMenupopup"
+#ifndef XP_MACOSX
+                  class="menu-iconic"
+#endif
                   label="&subscribeToPageMenupopup.label;"
                   observes="multipleFeedsMenuState">
               <menupopup id="BMB_subscribeToPageSubmenuMenupopup"
                          onpopupshowing="return FeedHandler.buildFeedList(event.target);"
                          oncommand="return FeedHandler.subscribeToFeed(null, event);"
                          onclick="checkForMiddleClick(this, event);"/>
             </menu>
             <menuseparator/>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -519,18 +519,20 @@
                     !(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE))
                   this.mBrowser.mIconURL = null;
 
                 let browserHistory = this.mTabBrowser.mBrowserHistory;
                 if (this.mBrowser.registeredOpenURI) {
                   browserHistory.unregisterOpenPage(this.mBrowser.registeredOpenURI);
                   delete this.mBrowser.registeredOpenURI;
                 }
-                browserHistory.registerOpenPage(aLocation);
-                this.mBrowser.registeredOpenURI = aLocation;
+                if (aLocation.spec != "about:blank") {
+                  browserHistory.registerOpenPage(aLocation);
+                  this.mBrowser.registeredOpenURI = aLocation;
+                }
               }
 
               if (!this.mBlank) {
                 this._callProgressListeners("onLocationChange",
                                             [aWebProgress, aRequest, aLocation]);
               }
 
               if (topLevel)
@@ -825,41 +827,58 @@
                                           true, false);
             }
 
             // TabSelect events are suppressed during preview mode to avoid confusing extensions and other bits of code
             // that might rely upon the other changes suppressed.
             // Focus is suppressed in the event that the main browser window is minimized - focusing a tab would restore the window
             if (!this._previewMode) {
               // We've selected the new tab, so go ahead and notify listeners.
-              var event = document.createEvent("Events");
+              let event = document.createEvent("Events");
               event.initEvent("TabSelect", true, false);
               this.mCurrentTab.dispatchEvent(event);
 
               this._tabAttrModified(oldTab);
               this._tabAttrModified(this.mCurrentTab);
 
-              // Change focus to the new browser unless the findbar is focused.
-              if (!gFindBarInitialized ||
-                  gFindBar.hidden ||
-                  gFindBar.getElement("findbar-textbox").getAttribute("focused") != "true") {
-
-                var fm = Components.classes["@mozilla.org/focus-manager;1"].
-                           getService(Components.interfaces.nsIFocusManager);
-                var newFocusedElement = fm.getFocusedElementForWindow(window.content, true, {});
+              // Adjust focus
+              do {
+                // Focus the location bar if it was previously focused for that tab.
+                // In full screen mode, only bother making the location bar visible
+                // if the tab is a blank one.
+                oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused);
+                if (newBrowser._urlbarFocused && gURLBar) {
+                  if (!window.fullScreen) {
+                    gURLBar.focus();
+                    break;
+                  } else if (isTabEmpty(this.mCurrentTab)) {
+                    focusAndSelectUrlBar();
+                    break;
+                  }
+                }
+
+                // If the find bar is focused, keep it focused.
+                if (gFindBarInitialized &&
+                    !gFindBar.hidden &&
+                    gFindBar.getElement("findbar-textbox").getAttribute("focused") == "true")
+                  break;
+
+                // Otherwise, focus the content area.
+                let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
+                let newFocusedElement = fm.getFocusedElementForWindow(window.content, true, {});
 
                 // for anchors, use FLAG_SHOWRING so that it is clear what link was
                 // last clicked when switching back to that tab
-                var focusFlags = fm.FLAG_NOSCROLL;
+                let focusFlags = fm.FLAG_NOSCROLL;
                 if (newFocusedElement &&
                     (newFocusedElement instanceof HTMLAnchorElement ||
                      newFocusedElement.getAttributeNS("http://www.w3.org/1999/xlink", "type") == "simple"))
                   focusFlags |= fm.FLAG_SHOWRING;
                 fm.setFocus(newBrowser, focusFlags);
-              }
+              } while (false);
             }
           ]]>
         </body>
       </method>
 
       <method name="_tabAttrModified">
         <parameter name="aTab"/>
         <body><![CDATA[
@@ -1895,25 +1914,21 @@
       </property>
 
       <!-- Moves a tab to a new browser window, unless it's already the only tab
            in the current window, in which case this will do nothing. -->
       <method name="replaceTabWithWindow">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
-            if (this.visibleTabs.length == 1)
+            if (this.tabs.length == 1)
               return null;
 
             // tell a new window to take the "dropped" tab
-            return Services.ww.openWindow(window,
-                                          getBrowserURL(),
-                                          null,
-                                          "chrome,dialog=no,all",
-                                          aTab);
+            return window.openDialog(getBrowserURL(), "_blank", "dialog=no,all", aTab);
           ]]>
         </body>
       </method>
 
       <method name="moveTabTo">
         <parameter name="aTab"/>
         <parameter name="aIndex"/>
         <body>
@@ -2701,21 +2716,28 @@
               tabStrip.scrollByPixels(-1);
           } catch (e) {}
         ]]></body>
       </method>
 
       <method name="_positionPinnedTabs">
         <body><![CDATA[
           var width = 0;
-          var scrollButtonWidth = this.getAttribute("overflow") != "true" ? 0 :
+          var pinnedOnly = (this.tabbrowser._numPinnedTabs == this.tabbrowser.visibleTabs.length);
+
+          if (pinnedOnly)
+            this.tabbrowser.tabContainer.setAttribute("pinnedonly", "true");
+          else
+            this.tabbrowser.tabContainer.removeAttribute("pinnedonly");
+
+          var scrollButtonWidth = (this.getAttribute("overflow") != "true" || pinnedOnly) ? 0 :
                                   this.mTabstrip._scrollButtonDown.scrollWidth;
           for (var i = this.tabbrowser._numPinnedTabs - 1; i >= 0; i--) {
             let tab = this.childNodes[i];
-            width += tab.scrollWidth;
+            width += pinnedOnly ? 0 : tab.scrollWidth;
             tab.style.MozMarginStart = - (width + scrollButtonWidth) + "px";
           }
           this.style.MozMarginStart = width + "px";
           this.mTabstrip.ensureElementIsVisible(this.selectedItem, false);
         ]]></body>
       </method>
 
       <method name="handleEvent">
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -76,16 +76,18 @@ function GroupItem(listOfEls, options) {
   this.isAGroupItem = true;
   this.id = options.id || GroupItems.getNextID();
   this._isStacked = false;
   this._stackAngles = [0];
   this.expanded = null;
   this.locked = (options.locked ? Utils.copy(options.locked) : {});
   this.topChild = null;
   this.hidden = false;
+  this.fadeAwayUndoButtonDelay = 15000;
+  this.fadeAwayUndoButtonDuration = 300;
 
   this.keepProportional = false;
 
   // Variable: _activeTab
   // The <TabItem> for the groupItem's active tab.
   this._activeTab = null;
 
   // Variables: xDensity, yDensity
@@ -272,16 +274,17 @@ function GroupItem(listOfEls, options) {
   if (this.locked.bounds)
     $container.css({cursor: 'default'});
 
   if (this.locked.close)
     $close.hide();
 
   // ___ Undo Close
   this.$undoContainer = null;
+  this._undoButtonTimeoutId = null;
 
   // ___ Superclass initialization
   this._init($container[0]);
 
   if (this.$debug)
     this.$debug.css({zIndex: -1000});
 
   // ___ Children
@@ -632,46 +635,25 @@ GroupItem.prototype = Utils.extend(new I
         easing: "tabviewBounce",
         duration: 170,
         complete: function() {
           self._sendToSubscribers("groupHidden", { groupItemId: self.id });
         }
       });
     }, 50);
 
-    let remove = function() {
-      // close all children
-      let toClose = self._children.concat();
-      toClose.forEach(function(child) {
-        child.removeSubscriber(self, "close");
-        child.close();
-      });
- 
-      // remove all children
-      self.removeAll();
-      GroupItems.unregister(self);
-      self._sendToSubscribers("close");
-      self.removeTrenches();
-
-      iQ(self.container).remove();
-      self.$undoContainer.remove();
-      self.$undoContainer = null;
-      Items.unsquish();
-
-      self.deleteData();
-    };
-
     this.$undoContainer.click(function(e) {
       // Only do this for clicks on this actual element.
       if (e.target.nodeName != self.$undoContainer[0].nodeName)
         return;
 
       self.$undoContainer.fadeOut(function() {
         iQ(this).remove();
         self.hidden = false;
+        self._cancelFadeAwayUndoButtonTimer();
         self.$undoContainer = null;
 
         iQ(self.container).show().animate({
           "-moz-transform": "scale(1)",
           "opacity": 1
         }, {
           duration: 170,
           complete: function() {
@@ -681,41 +663,102 @@ GroupItem.prototype = Utils.extend(new I
           }
         });
 
         self._sendToSubscribers("groupShown", { groupItemId: self.id });
       });
     });
 
     undoClose.click(function() {
-      self.$undoContainer.fadeOut(remove);
+      self._cancelFadeAwayUndoButtonTimer();
+      self.$undoContainer.fadeOut(function() { self._removeHiddenGroupItem(); });
     });
 
-    // After 15 seconds, fade away.
-    const WAIT = 15000;
-    const FADE = 300;
+    this.setupFadeAwayUndoButtonTimer();
+    // Cancel the fadeaway if you move the mouse over the undo
+    // button, and restart the countdown once you move out of it.
+    this.$undoContainer.mouseover(function() { 
+      self._cancelFadeAwayUndoButtonTimer();
+    });
+    this.$undoContainer.mouseout(function() {
+      self.setupFadeAwayUndoButtonTimer();
+    });
+  },
+
+  // ----------
+  // Sets up fade away undo button timeout. 
+  setupFadeAwayUndoButtonTimer: function() {
+    let self = this;
 
-    let fadeaway = function() {
-      if (self.$undoContainer)
+    if (!this._undoButtonTimeoutId) {
+      this._undoButtonTimeoutId = setTimeout(function() { 
+        self._fadeAwayUndoButton(); 
+      }, this.fadeAwayUndoButtonDelay);
+    }
+  },
+  
+  // ----------
+  // Cancels the fade away undo button timeout. 
+  _cancelFadeAwayUndoButtonTimer: function() {
+    clearTimeout(this._undoButtonTimeoutId);
+    this._undoButtonTimeoutId = null;
+  }, 
+
+  // ----------
+  // Fades away the undo button
+  _fadeAwayUndoButton: function() {
+    let self = this;
+
+    if (this.$undoContainer) {
+      // if there is one or more orphan tabs or there is more than one group 
+      // and other groupS are not empty, fade away the undo button.
+      let shouldFadeAway = GroupItems.getOrphanedTabs().length > 0;
+      
+      if (!shouldFadeAway && GroupItems.groupItems.length > 1) {
+        shouldFadeAway = 
+          GroupItems.groupItems.some(function(groupItem) {
+            return (groupItem != self && groupItem.getChildren().length > 0);
+          });
+      }
+      if (shouldFadeAway) {
         self.$undoContainer.animate({
           color: "transparent",
           opacity: 0
         }, {
-          duration: FADE,
-          complete: remove
+          duration: this.fadeAwayUndoButtonDuration,
+          complete: function() { self._removeHiddenGroupItem(); }
         });
-    };
+      }
+    }
+  },
+
+  // ----------
+  // Removes the group item, its children and its container.
+  _removeHiddenGroupItem: function() {
+    let self = this;
 
-    let timeoutId = setTimeout(fadeaway, WAIT);
-    // Cancel the fadeaway if you move the mouse over the undo
-    // button, and restart the countdown once you move out of it.
-    this.$undoContainer.mouseover(function() clearTimeout(timeoutId));
-    this.$undoContainer.mouseout(function() {
-      timeoutId = setTimeout(fadeaway, WAIT);
+    // close all children
+    let toClose = this._children.concat();
+    toClose.forEach(function(child) {
+      child.removeSubscriber(self, "close");
+      child.close();
     });
+ 
+    // remove all children
+    this.removeAll();
+    GroupItems.unregister(this);
+    this._sendToSubscribers("close");
+    this.removeTrenches();
+
+    iQ(this.container).remove();
+    this.$undoContainer.remove();
+    this.$undoContainer = null;
+    Items.unsquish();
+
+    this.deleteData();
   },
 
   // ----------
   // Function: add
   // Adds an item to the groupItem.
   // Parameters:
   //
   //   a - The item to add. Can be an <Item>, a DOM element or an iQ object.
@@ -972,74 +1015,72 @@ GroupItem.prototype = Utils.extend(new I
           opacity: .2,
           top: childBB.top + childBB.height - parentBB.top + padding,
           left: parentBB.width/2 - this.$expander.width()/2
         });
   },
 
   // ----------
   // Function: shouldStack
-  // Returns true if the groupItem, given "count", should stack (instead of grid).
+  // Returns true if the groupItem should stack (instead of grid).
   shouldStack: function GroupItem_shouldStack(count) {
     if (count <= 1)
       return false;
 
     var bb = this.getContentBounds();
     var options = {
-      pretend: true,
-      count: count
+      return: 'widthAndColumns',
+      count: count || this._children.length
     };
+    let {childWidth, columns} = Items.arrange(null, bb, options);
 
-    var rects = Items.arrange(null, bb, options);
-    return (rects[0].width < 55);
+    let shouldStack = childWidth < TabItems.minTabWidth * 1.35;
+    this._columns = shouldStack ? null : columns;
+
+    return shouldStack;
   },
 
   // ----------
   // Function: arrange
   // Lays out all of the children.
   //
   // Parameters:
   //   options - passed to <Items.arrange> or <_stackArrange>
   arrange: function GroupItem_arrange(options) {
     if (this.expanded) {
       this.topChild = null;
       var box = new Rect(this.expanded.bounds);
       box.inset(8, 8);
       Items.arrange(this._children, box, Utils.extend({}, options, {z: 99999}));
     } else {
       var bb = this.getContentBounds();
-      var count = this._children.length;
-      if (!this.shouldStack(count)) {
+      if (!this.shouldStack()) {
         if (!options)
           options = {};
 
-        var animate;
-        if (typeof options.animate == 'undefined')
-          animate = true;
-        else
-          animate = options.animate;
-
         this._children.forEach(function(child) {
             child.removeClass("stacked")
         });
 
         this.topChild = null;
 
-        var arrangeOptions = Utils.copy(options);
-        Utils.extend(arrangeOptions, {
-          pretend: true,
-          count: count
-        });
-
-        if (!count) {
+        if (!this._children.length) {
           this.xDensity = 0;
           this.yDensity = 0;
           return;
         }
 
+        var arrangeOptions = Utils.copy(options);
+        Utils.extend(arrangeOptions, {
+          columns: this._columns
+        });
+
+        // Items.arrange will rearrange the children, but also return an array
+        // of the Rect's used.
+
         var rects = Items.arrange(this._children, bb, arrangeOptions);
 
         // yDensity = (the distance of the bottom of the last tab to the top of the content area)
         // / (the total available content height)
         this.yDensity = (rects[rects.length - 1].bottom - bb.top) / (bb.height);
 
         // xDensity = (the distance from the left of the content area to the right of the rightmost
         // tab) / (the total available content width)
@@ -1050,25 +1091,16 @@ GroupItem.prototype = Utils.extend(new I
         for each (var rect in rects) {
           if (rect.right > rightMostRight)
             rightMostRight = rect.right;
           else
             break;
         }
         this.xDensity = (rightMostRight - bb.left) / (bb.width);
 
-        this._children.forEach(function(child, index) {
-          if (!child.locked.bounds) {
-            child.setBounds(rects[index], !animate);
-            child.setRotation(0);
-            if (options.z)
-              child.setZ(options.z);
-          }
-        });
-
         this._isStacked = false;
       } else
         this._stackArrange(bb, options);
     }
 
     if (this._isStacked && !this.expanded) this.showExpandControl();
     else this.hideExpandControl();
   },
deleted file mode 100644
--- a/browser/base/content/tabview/infoitems.js
+++ /dev/null
@@ -1,252 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is infoitems.js.
- *
- * The Initial Developer of the Original Code is
- * the Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Ian Gilman <ian@iangilman.com>
- * Aza Raskin <aza@mozilla.com>
- * Michael Yoshitaka Erlewine <mitcho@mitcho.com>
- * Ehsan Akhgari <ehsan@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-// **********
-// Title: infoitems.js
-
-// ##########
-// Class: InfoItem
-// An <Item> in TabView used for displaying information, such as the welcome video.
-// Note that it implements the <Subscribable> interface.
-//
-// ----------
-// Constructor: InfoItem
-//
-// Parameters:
-//   bounds - a <Rect> for where the item should be located
-//   options - various options for this infoItem (see below)
-//
-// Possible options:
-//   locked - see <Item.locked>; default is {}
-//   dontPush - true if this infoItem shouldn't push away on creation; default is false
-//   immediately - place the item immediately, without animation
-function InfoItem(bounds, options) {
-  try {
-    Utils.assertThrow(Utils.isRect(bounds), 'bounds');
-
-    if (typeof options == 'undefined')
-      options = {};
-
-    this._inited = false;
-    this.isAnInfoItem = true;
-    this.defaultSize = bounds.size();
-    this.locked = (options.locked ? Utils.copy(options.locked) : {});
-    this.bounds = new Rect(bounds);
-    this.isDragging = false;
-
-    var self = this;
-
-    var $container = iQ('<div>')
-      .addClass('info-item')
-      .css(this.bounds)
-      .appendTo('body');
-
-    this.$contents = iQ('<div>')
-      .appendTo($container);
-
-    var $close = iQ('<div>')
-      .addClass('close')
-      .click(function() {
-        self.close();
-      })
-      .appendTo($container);
-
-    // ___ locking
-    if (this.locked.bounds)
-      $container.css({cursor: 'default'});
-
-    if (this.locked.close)
-      $close.hide();
-
-    // ___ Superclass initialization
-    this._init($container[0]);
-
-    if (this.$debug)
-      this.$debug.css({zIndex: -1000});
-
-    // ___ Finish Up
-    if (!this.locked.bounds)
-      this.draggable();
-
-    // ___ Position
-    if (!options.dontPush)
-      this.snap(options.immediately);
-
-    this._inited = true;
-    this.save();
-  } catch(e) {
-    Utils.log(e);
-  }
-};
-
-// ----------
-InfoItem.prototype = Utils.extend(new Item(), new Subscribable(), {
-
-  // ----------
-  // Function: getStorageData
-  // Returns all of the info worth storing about this item.
-  getStorageData: function InfoItem_getStorageData() {
-    var data = null;
-
-    try {
-      data = {
-        bounds: this.getBounds(),
-        locked: Utils.copy(this.locked)
-      };
-    } catch(e) {
-      Utils.log(e);
-    }
-
-    return data;
-  },
-
-  // ----------
-  // Function: save
-  // Saves this item to persistent storage.
-  save: function InfoItem_save() {
-    try {
-      if (!this._inited) // too soon to save now
-        return;
-
-      var data = this.getStorageData();
-
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: setBounds
-  // Sets the bounds with the given <Rect>, animating unless "immediately" is false.
-  setBounds: function InfoItem_setBounds(rect, immediately) {
-    try {
-      Utils.assertThrow(Utils.isRect(rect), 'InfoItem.setBounds: rect must be a real rectangle!');
-
-      // ___ Determine what has changed
-      var css = {};
-
-      if (rect.left != this.bounds.left)
-        css.left = rect.left;
-
-      if (rect.top != this.bounds.top)
-        css.top = rect.top;
-
-      if (rect.width != this.bounds.width)
-        css.width = rect.width;
-
-      if (rect.height != this.bounds.height)
-        css.height = rect.height;
-
-      if (Utils.isEmptyObject(css))
-        return;
-
-      this.bounds = new Rect(rect);
-      Utils.assertThrow(Utils.isRect(this.bounds), 
-          'InfoItem.setBounds: this.bounds must be a real rectangle!');
-
-      // ___ Update our representation
-      if (immediately) {
-        iQ(this.container).css(css);
-      } else {
-        TabItems.pausePainting();
-        iQ(this.container).animate(css, {
-          duration: 350,
-          easing: "tabviewBounce",
-          complete: function() {
-            TabItems.resumePainting();
-          }
-        });
-      }
-
-      this._updateDebugBounds();
-      this.setTrenches(rect);
-      this.save();
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: setZ
-  // Set the Z order for the item's container.
-  setZ: function InfoItem_setZ(value) {
-    try {
-      Utils.assertThrow(typeof value == 'number', 'value must be a number');
-
-      this.zIndex = value;
-
-      iQ(this.container).css({zIndex: value});
-
-      if (this.$debug)
-        this.$debug.css({zIndex: value + 1});
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: close
-  // Closes the item.
-  close: function InfoItem_close() {
-    try {
-      this._sendToSubscribers("close");
-      this.removeTrenches();
-      iQ(this.container).fadeOut(function() {
-        iQ(this).remove();
-        Items.unsquish();
-      });
-
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: html
-  // Sets the item's container's html to the specified value.
-  html: function InfoItem_html(value) {
-    try {
-      Utils.assertThrow(typeof value == 'string', 'value must be a string');
-      this.$contents.html(value);
-    } catch(e) {
-      Utils.log(e);
-    }
-  }
-});
--- a/browser/base/content/tabview/items.js
+++ b/browser/base/content/tabview/items.js
@@ -596,17 +596,17 @@ Item.prototype = {
       var startSent;
       var startEvent;
       var droppables;
       var dropTarget;
 
       // ___ mousemove
       var handleMouseMove = function(e) {
         // positioning
-        var mouse = new Point(e.pageX, e.pageY);		
+        var mouse = new Point(e.pageX, e.pageY);
         if (!startSent) {
           if(Math.abs(mouse.x - startMouse.x) > self.dragOptions.minDragDistance ||
              Math.abs(mouse.y - startMouse.y) > self.dragOptions.minDragDistance) {
             if (typeof self.dragOptions.start == "function")
               self.dragOptions.start.apply(self,
                   [startEvent, {position: {left: startPos.x, top: startPos.y}}]);
             startSent = true;
           }
@@ -887,49 +887,51 @@ let Items = {
   },
 
   // ----------
   // Function: arrange
   // Arranges the given items in a grid within the given bounds,
   // maximizing item size but maintaining standard tab aspect ratio for each
   //
   // Parameters:
-  //   items - an array of <Item>s. Can be null if the pretend and count options are set.
+  //   items - an array of <Item>s. Can be null, in which case we won't
+  //     actually move anything.
   //   bounds - a <Rect> defining the space to arrange within
   //   options - an object with various properites (see below)
   //
   // Possible "options" properties:
   //   animate - whether to animate; default: true.
   //   z - the z index to set all the items; default: don't change z.
-  //   pretend - whether to collect and return the rectangle rather than moving the items; default: false
-  //   count - overrides the item count for layout purposes; default: the actual item count
+  //   return - if set to 'widthAndColumns', it'll return an object with the
+  //     width of children and the columns.
+  //   count - overrides the item count for layout purposes;
+  //     default: the actual item count
   //   padding - pixels between each item
+  //   columns - (int) a preset number of columns to use
   //
   // Returns:
-  //   the list of rectangles if the pretend option is set; otherwise null
+  //   an object with the width value of the child items and the number of columns, 
+  //   if the return option is set to 'widthAndColumns'; otherwise the list of <Rect>s
   arrange: function Items_arrange(items, bounds, options) {
-    var animate;
-    if (!options || typeof options.animate == 'undefined')
-      animate = true;
-    else
-      animate = options.animate;
-
     if (typeof options == 'undefined')
       options = {};
 
-    var rects = null;
-    if (options.pretend)
-      rects = [];
+    var animate = true;
+    if (typeof options.animate != 'undefined')
+      animate = options.animate;
+    var immediately = !animate;
+
+    var rects = [];
 
     var tabAspect = TabItems.tabHeight / TabItems.tabWidth;
     var count = options.count || (items ? items.length : 0);
     if (!count)
       return rects;
 
-    var columns = 1;
+    var columns = options.columns || 1;
     // We'll assume for the time being that all the items have the same styling
     // and that the margin is the same width around.
     var itemMargin = items && items.length ?
                        parseInt(iQ(items[0].container).css('margin-left')) : 0;
     var padding = itemMargin * 2;
     var yScale = 1.1; // to allow for titles
     var rows;
     var tabWidth;
@@ -949,45 +951,41 @@ let Items = {
       columns++;
       figure();
     }
 
     if (rows == 1) {
       tabWidth = Math.min(tabWidth, (bounds.height - 2 * itemMargin) / tabAspect);
       tabHeight = tabWidth * tabAspect;
     }
+    
+    if (options.return == 'widthAndColumns')
+      return {childWidth: tabWidth, columns: columns};
 
     var box = new Rect(bounds.left, bounds.top, tabWidth, tabHeight);
-    var row = 0;
     var column = 0;
-    var immediately;
 
-    var a;
-    for (a = 0; a < count; a++) {
-      immediately = !animate;
-
-      if (rects)
-        rects.push(new Rect(box));
-      else if (items && a < items.length) {
-        var item = items[a];
+    for (let a = 0; a < count; a++) {
+      rects.push(new Rect(box));
+      if (items && a < items.length) {
+        let item = items[a];
         if (!item.locked.bounds) {
           item.setBounds(box, immediately);
           item.setRotation(0);
           if (options.z)
             item.setZ(options.z);
         }
       }
 
       box.left += box.width + padding;
       column++;
       if (column == columns) {
         box.left = bounds.left;
         box.top += (box.height * yScale) + padding;
         column = 0;
-        row++;
       }
     }
 
     return rects;
   },
 
   // ----------
   // Function: unsquish
--- a/browser/base/content/tabview/tabview.js
+++ b/browser/base/content/tabview/tabview.js
@@ -47,13 +47,10 @@ XPCOMUtils.defineLazyGetter(this, "gPriv
 
 #include iq.js
 #include storage.js
 #include items.js
 #include groupitems.js
 #include tabitems.js
 #include drag.js
 #include trench.js
-#include infoitems.js
 #include ui.js
 #include search.js
-
-
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -244,26 +244,29 @@ let UI = {
     this._reorderTabsOnHide = null;
     this._frameInitialized = false;
   },
   
   // Function: reset
   // Resets the Panorama view to have just one group with all tabs
   // and, if firstTime == true, add the welcome video/tab
   reset: function UI_reset(firstTime) {
-    let padding = 10;
-    let infoWidth = 350;
-    let infoHeight = 232;
+    let padding = Trenches.defaultRadius;
+    let welcomeWidth = 300;
     let pageBounds = Items.getPageBounds();
     pageBounds.inset(padding, padding);
 
+    let $actions = iQ("#actions");
+    if ($actions)
+      pageBounds.width -= $actions.width();
+
     // ___ make a fresh groupItem
     let box = new Rect(pageBounds);
-    box.width = 
-      Math.min(box.width * 0.667, pageBounds.width - (infoWidth + padding));
+    box.width = Math.min(box.width * 0.667,
+                         pageBounds.width - (welcomeWidth + padding));
     box.height = box.height * 0.667;
 
     GroupItems.groupItems.forEach(function(group) {
       group.close();
     });
     
     let options = {
       bounds: box,
@@ -275,27 +278,28 @@ let UI = {
       if (item.parent)
         item.parent.remove(item);
       groupItem.add(item, null, {immediately: true});
     });
     
     if (firstTime) {
       gPrefBranch.setBoolPref("experienced_first_run", true);
 
-      // ___ make info item
-      let video = 
-        "http://videos-cdn.mozilla.net/firefox4beta/tabcandy_howto.webm";
-      let html =
-        "<div class='intro'>"
-          + "<video src='" + video + "' width='100%' preload controls>"
-        + "</div>";
-      let infoBox = new Rect(box.right + padding, box.top,
-                         infoWidth, infoHeight);
-      let infoItem = new InfoItem(infoBox);
-      infoItem.html(html);
+      let url = gPrefBranch.getCharPref("welcome_url");
+      let newTab = gBrowser.loadOneTab(url, {inBackground: true});
+      let newTabItem = newTab.tabItem;
+      let parent = newTabItem.parent;
+      Utils.assert(parent, "should have a parent");
+
+      newTabItem.parent.remove(newTabItem);
+      let aspect = TabItems.tabHeight / TabItems.tabWidth;
+      let welcomeBounds = new Rect(box.right + padding, box.top,
+                                   welcomeWidth, welcomeWidth * aspect);
+      newTabItem.setBounds(welcomeBounds, true);
+      GroupItems.setActiveGroupItem(groupItem);
     }
   },
 
   // Function: blurAll
   // Blurs any currently focused element
   //
   blurAll: function UI_blurAll() {
     iQ(":focus").each(function(element) {
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -140,30 +140,32 @@ endif
                  browser_bug555224.js \
                  browser_bug555767.js \
                  browser_bug556061.js \
                  browser_bug559991.js \
                  browser_bug561623.js \
                  browser_bug561636.js \
                  browser_bug562649.js \
                  browser_bug563588.js \
+                 browser_bug565575.js \
                  browser_bug575561.js \
                  browser_bug577121.js \
                  browser_bug579872.js \
                  browser_bug580956.js \
                  browser_bug581242.js \
                  browser_bug581253.js \
                  browser_bug581947.js \
                  browser_bug585785.js \
                  browser_bug585830.js \
                  browser_bug592338.js \
                  browser_bug594131.js \
                  browser_bug595507.js \
                  browser_bug596687.js \
                  browser_bug597218.js \
+                 browser_bug609700.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_discovery.js \
                  browser_duplicateIDs.js \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
                  browser_hide_removing.js \
                  browser_inspector_initialization.js \
@@ -216,16 +218,17 @@ endif
                  dummy_page.html \
                  browser_tabMatchesInAwesomebar.js \
                  file_bug550565_popup.html \
                  file_bug550565_favicon.ico \
                  browser_overLinkInLocationBar.js \
                  browser_aboutHome.js \
                  app_bug575561.html \
                  app_subframe_bug575561.html \
+                 browser_contentAreaClick.js \
                  $(NULL)
 
 # compartment-disabled
 #                 browser_popupUI.js \
 #                 browser_tab_dragdrop.js \
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -89,16 +89,42 @@ let gTests = [
     ok(snippetsElt, "Found default snippets element")
     ok(Array.some(snippetsElt.getElementsByTagName("span"), function(elt) {
       return !elt.hidden;
     }), "A default snippet is visible.");
     executeSoon(runNextTest);
   }
 },
 
+{
+  desc: "Check default snippets are shown if snippets are invalid xml",
+  setup: function ()
+  {
+    let storage = getStorage();
+    // This must be some incorrect xhtml code.
+    storage.setItem("snippets", "<p><b></p></b>");
+  },
+  run: function ()
+  {
+    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
+
+    let snippetsElt = doc.getElementById("snippets");
+    ok(snippetsElt, "Found snippets element");
+    ok(snippetsElt.hidden, "Snippets element is hidden");
+
+    let defaultsElt = doc.getElementById("defaultSnippets");
+    ok(defaultsElt, "Found default snippets element")
+    ok(Array.some(defaultsElt.getElementsByTagName("span"), function(elt) {
+      return !elt.hidden;
+    }), "A default snippet is visible.");
+
+    executeSoon(runNextTest);
+  }
+},
+
 ];
 
 function test()
 {
   waitForExplicitFinish();
 
   // browser-chrome test harness inits browser specifying an hardcoded page
   // and this causes nsIBrowserHandler.defaultArgs to not be evaluated since
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug565575.js
@@ -0,0 +1,13 @@
+function test() {
+  gBrowser.selectedBrowser.focus();
+  BrowserOpenTab();
+  ok(gURLBar.focused, "location bar is focused for a new tab");
+
+  gBrowser.selectedTab = gBrowser.tabs[0];
+  ok(!gURLBar.focused, "location bar isn't focused for the previously selected tab");
+
+  gBrowser.selectedTab = gBrowser.tabs[1];
+  ok(gURLBar.focused, "location bar is re-focused when selecting the new tab");
+
+  gBrowser.removeCurrentTab();
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug609700.js
@@ -0,0 +1,20 @@
+function test() {
+  waitForExplicitFinish();
+
+  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 () {
+        executeSoon(function () {
+          aSubject.close();
+          finish();
+        });
+      }, false);
+    }
+  });
+
+  duplicateTabIn(gBrowser.selectedTab, "window");
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_contentAreaClick.js
@@ -0,0 +1,296 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Firefox Browser Test Code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   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 ***** */
+ 
+/**
+ * Test for bug 549340.
+ * Test for browser.js::contentAreaClick() util.
+ *
+ * The test opens a new browser window, then replaces browser.js methods invoked
+ * by contentAreaClick with a mock function that tracks which methods have been
+ * called.
+ * Each sub-test synthesizes a mouse click event on links injected in content,
+ * the event is collected by a click handler that ensures that contentAreaClick
+ * correctly prevent default events, and follows the correct code path.
+ */
+
+let gTests = [
+
+  {
+    desc: "Simple left click",
+    setup: function() {},
+    clean: function() {},
+    event: {},
+    target: "commonlink",
+    expectedInvokedMethods: [],
+    preventDefault: false,
+  },
+
+  {
+    desc: "Ctrl/Cmd left click",
+    setup: function() {},
+    clean: function() {},
+    event: { ctrlKey: true,
+             metaKey: true },
+    target: "commonlink",
+    expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
+    preventDefault: true,
+  },
+
+  // The next test was once handling feedService.forcePreview().  Now it should
+  // just be like Alt click.
+  {
+    desc: "Shift+Alt left click",
+    setup: function() {},
+    clean: function() {},
+    event: { shiftKey: true,
+             altKey: true },
+    target: "commonlink",
+    expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
+    preventDefault: true,
+  },
+
+  {
+    desc: "Shift click",
+    setup: function() {},
+    clean: function() {},
+    event: { shiftKey: true },
+    target: "commonlink",
+    expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
+    preventDefault: true,
+  },
+
+  {
+    desc: "Alt click",
+    setup: function() {},
+    clean: function() {},
+    event: { altKey: true },
+    target: "commonlink",
+    expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
+    preventDefault: true,
+  },
+
+  {
+    desc: "Panel click",
+    setup: function() {},
+    clean: function() {},
+    event: {},
+    target: "panellink",
+    expectedInvokedMethods: [ "urlSecurityCheck", "getShortcutOrURI", "loadURI" ],
+    preventDefault: true,
+  },
+
+  {
+    desc: "Simple middle click opentab",
+    setup: function() {},
+    clean: function() {},
+    event: { button: 1 },
+    target: "commonlink",
+    expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
+    preventDefault: true,
+  },
+
+  {
+    desc: "Simple middle click openwin",
+    setup: function() {
+      gPrefService.setBoolPref("browser.tabs.opentabfor.middleclick", false);
+    },
+    clean: function() {
+      try {
+        gPrefService.clearUserPref("browser.tabs.opentabfor.middleclick");
+      } catch(ex) {}
+    },
+    event: { button: 1 },
+    target: "commonlink",
+    expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
+    preventDefault: true,
+  },
+
+  {
+    desc: "Middle mouse paste",
+    setup: function() {
+      gPrefService.setBoolPref("middlemouse.contentLoadURL", true);
+      gPrefService.setBoolPref("general.autoScroll", false);
+    },
+    clean: function() {
+      try {
+        gPrefService.clearUserPref("middlemouse.contentLoadURL");
+      } catch(ex) {}
+      try {
+        gPrefService.clearUserPref("general.autoScroll");
+      } catch(ex) {}
+    },
+    event: { button: 1 },
+    target: "emptylink",
+    expectedInvokedMethods: [ "middleMousePaste" ],
+    preventDefault: true,
+  },
+
+];
+
+// Array of method names that will be replaced in the new window.
+let gReplacedMethods = [
+  "middleMousePaste",
+  "urlSecurityCheck",
+  "loadURI",
+  "gatherTextUnder",
+  "saveURL",
+  "openLinkIn",
+  "getShortcutOrURI",
+];
+
+// Reference to the new window.
+let gTestWin = null;
+
+// List of methods invoked by a specific call to contentAreaClick.
+let gInvokedMethods = [];
+
+// The test currently running.
+let gCurrentTest = null;
+
+function test() {
+  waitForExplicitFinish();
+
+  gTestWin = openDialog(location, "", "chrome,all,dialog=no", "about:blank");
+  gTestWin.addEventListener("load", function (event) {
+    info("Window loaded.");
+    gTestWin.removeEventListener("load", arguments.callee, false);
+    waitForFocus(function() {
+      info("Setting up browser...");
+      setupTestBrowserWindow();
+      info("Running tests...");
+      executeSoon(runNextTest);
+    }, gTestWin.content, true);
+  }, false);
+}
+
+// Click handler used to steal click events.
+let gClickHandler = {
+  handleEvent: function (event) {
+    let linkId = event.target.id;
+    is(event.type, "click",
+       gCurrentTest.desc + ":Handler received a click event on " + linkId);
+
+    let isPanelClick = linkId == "panellink";
+    let returnValue = gTestWin.contentAreaClick(event, isPanelClick);
+    let prevent = event.getPreventDefault();
+    is(prevent, gCurrentTest.preventDefault,
+       gCurrentTest.desc + ": event.getPreventDefault() is correct (" + prevent + ")")
+
+    // Check that all required methods have been called.
+    gCurrentTest.expectedInvokedMethods.forEach(function(aExpectedMethodName) {
+      isnot(gInvokedMethods.indexOf(aExpectedMethodName), -1,
+            gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked");
+    });
+    
+    if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) {
+      is(false, "More than the expected methods have been called");
+      gInvokedMethods.forEach(function (method) info(method + " was invoked"));
+    }
+
+    event.preventDefault();
+    event.stopPropagation();
+
+    executeSoon(runNextTest);
+  }
+}
+
+// Wraps around the methods' replacement mock function.
+function wrapperMethod(aInvokedMethods, aMethodName) {
+  return function () {
+    aInvokedMethods.push(aMethodName);
+    // At least getShortcutOrURI requires to return url that is the first param.
+    return arguments[0];
+  }
+}
+
+function setupTestBrowserWindow() {
+  // Steal click events and don't propagate them.
+  gTestWin.addEventListener("click", gClickHandler, true);
+
+  // Replace methods.
+  gReplacedMethods.forEach(function (aMethodName) {
+    gTestWin["old_" + aMethodName] = gTestWin[aMethodName];
+    gTestWin[aMethodName] = wrapperMethod(gInvokedMethods, aMethodName);
+  });
+
+  // Inject links in content.
+  let doc = gTestWin.content.document;
+  let mainDiv = doc.createElement("div");
+  mainDiv.innerHTML =
+    '<a id="commonlink" href="http://mochi.test/moz/">Common link</a>' +
+    '<a id="panellink" href="http://mochi.test/moz/">Panel link</a>' +
+    '<a id="emptylink">Empty link</a>';
+  doc.body.appendChild(mainDiv);
+}
+
+function runNextTest() {
+  if (gCurrentTest) {
+    info(gCurrentTest.desc + ": cleaning up...")
+    gCurrentTest.clean();
+    gInvokedMethods.length = 0;
+  }
+
+  if (gTests.length > 0) {
+    gCurrentTest = gTests.shift();
+
+    info(gCurrentTest.desc + ": starting...");
+    // Prepare for test.
+    gCurrentTest.setup();
+
+    // Fire click event.
+    let target = gTestWin.content.document.getElementById(gCurrentTest.target);
+    ok(target, gCurrentTest.desc + ": target is valid (" + target.id + ")");
+    EventUtils.synthesizeMouse(target, 2, 2, gCurrentTest.event, gTestWin.content);
+  }
+  else {
+    // No more tests to run.
+    finishTest()
+  }
+}
+
+function finishTest() {
+  info("Restoring browser...");
+  gTestWin.removeEventListener("click", gClickHandler, true);
+
+  // Restore original methods.
+  gReplacedMethods.forEach(function (aMethodName) {
+    gTestWin[aMethodName] = gTestWin["old_" + aMethodName];
+    delete gTestWin["old_" + aMethodName];
+  });
+
+  gTestWin.close();
+  finish();
+}
--- a/browser/base/content/test/browser_tabMatchesInAwesomebar.js
+++ b/browser/base/content/test/browser_tabMatchesInAwesomebar.js
@@ -116,17 +116,17 @@ var gTestSteps = [
         }, true);
         tab.linkedBrowser.contentDocument.querySelector("iframe").src = "http://test2.example.org/";
       });
     }, true);
     tab.linkedBrowser.loadURI('data:text/html,<body><iframe src=""></iframe></body>');
   },
   function() {
     info("Running step 7 - remove tab immediately");
-    let tab = gBrowser.addTab("about:blank");
+    let tab = gBrowser.addTab("about:logo");
     gBrowser.removeTab(tab);
     ensure_opentabs_match_db();
     nextStep();
   },
   function() {
     info("Running step 8 - check swapBrowsersAndCloseOther preserves registered switch-to-tab result");
     let tabToKeep = gBrowser.addTab();
     let tab = gBrowser.addTab();
@@ -203,16 +203,18 @@ function ensure_opentabs_match_db() {
     let browserWin = winEnum.getNext();
     // skip closed-but-not-destroyed windows
     if (browserWin.closed)
       continue;
 
     for (let i = 0; i < browserWin.gBrowser.tabContainer.childElementCount; i++) {
       let browser = browserWin.gBrowser.getBrowserAtIndex(i);
       let url = browser.currentURI.spec;
+      if (url == "about:blank")
+        continue;
       if (!(url in tabs))
         tabs[url] = 1;
       else
         tabs[url]++;
     }
   }
 
   var db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
@@ -242,16 +244,20 @@ function ensure_opentabs_match_db() {
   } finally {
     stmt.finalize();
   }
 
   for (let url in tabs) {
     ok(dbtabs.indexOf(url) > -1,
        "tab is open (" + tabs[url] + " times) and should recorded in db: " + url);
   }
+  dbtabs.forEach(function (url) {
+    ok(url in tabs,
+       "db-recorded tab should actually exist: " + url);
+  });
 }
 
 /**
  * Clears history invoking callback when done.
  */
 function waitForClearHistory(aCallback) {
   const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
   let observer = {
--- a/browser/base/content/test/browser_tabfocus.js
+++ b/browser/base/content/test/browser_tabfocus.js
@@ -39,21 +39,18 @@ function test() {
     is(focusedWindow.value, browser1.contentWindow, "initial frame focus in tab 1");
     is(fm.getFocusedElementForWindow(browser2.contentWindow, false, focusedWindow), null, "initial focus in tab 2");
     is(focusedWindow.value, browser2.contentWindow, "initial frame focus in tab 2");
 
     expectFocusShift(function () gBrowser.selectedTab = tab2,
                      browser2.contentWindow, null, true,
                      "focusedElement after tab change, focus in new tab");
 
-    // switching tabs when the urlbar is focused and nothing in the new tab is focused
+    // switching tabs when nothing in the new tab is focused
     // should focus the browser
-    expectFocusShift(function () gURLBar.focus(),
-                     window, gURLBar.inputField, true,
-                     "url field focused");
     expectFocusShift(function () gBrowser.selectedTab = tab1,
                      browser1.contentWindow, null, true,
                      "focusedElement after tab change, focus in new tab");
 
     // focusing a button in the current tab should focus it
     var button1 = browser1.contentDocument.getElementById("button1");
     expectFocusShift(function () button1.focus(),
                      browser1.contentWindow, button1, true,
@@ -84,16 +81,19 @@ function test() {
 
     // focusing the url field should switch active focus away from the tab but
     // not clear what would be the focus in the tab 
     button1.focus();
     expectFocusShift(function () gURLBar.focus(),
                      window, gURLBar.inputField, true,
                      "focusedWindow after url field focused");
     is(fm.getFocusedElementForWindow(browser2.contentWindow, false, {}), button2, "url field focused, button in tab");
+    expectFocusShift(function () gURLBar.blur(),
+                     window, null, true,
+                     "focusedWindow after browser focused");
 
     // when a chrome element is focused, switching tabs to a tab with a button
     // with the current focus should focus the button
     expectFocusShift(function () gBrowser.selectedTab = tab1,
                      browser1.contentWindow, button1, true,
                      "focusedWindow after tab change, focus in url field, button focused in new tab");
     is(fm.getFocusedElementForWindow(browser2.contentWindow, false, {}), button2, "after switch tab, focus in unfocused tab");
 
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -48,16 +48,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug580412.js \
                  browser_tabview_bug587043.js \
                  browser_tabview_bug587990.js \
                  browser_tabview_bug590606.js \
                  browser_tabview_bug591706.js \
                  browser_tabview_bug594176.js \
                  browser_tabview_bug595191.js \
                  browser_tabview_bug595518.js \
+                 browser_tabview_bug595521.js \
                  browser_tabview_bug595804.js \
                  browser_tabview_bug595930.js \
                  browser_tabview_bug595943.js \
                  browser_tabview_bug598600.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug595521.js
@@ -0,0 +1,101 @@
+/* ***** 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 a test for bug 595521.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Raymond Lee <raymond@appcoast.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let fadeAwayUndoButtonDelay;
+let fadeAwayUndoButtonDuration;
+
+function test() {
+  waitForExplicitFinish();
+
+  window.addEventListener("tabviewshown", testCloseLastGroup, false);
+  TabView.toggle();
+}
+
+function testCloseLastGroup() {
+  window.removeEventListener("tabviewshown", testCloseLastGroup, false);
+  ok(TabView.isVisible(), "Tab View is visible");
+
+  let contentWindow = document.getElementById("tab-view").contentWindow;
+
+  is(contentWindow.GroupItems.groupItems.length, 1, "Has one group only");
+
+  let groupItem = contentWindow.GroupItems.groupItems[0];
+  
+  let checkExistence = function() {
+    is(contentWindow.GroupItems.groupItems.length, 1, 
+       "Still has one group after delay");
+
+    EventUtils.sendMouseEvent(
+      { type: "click" }, groupItem.$undoContainer[0], contentWindow);
+  };
+
+  groupItem.addSubscriber(groupItem, "groupHidden", function() {
+    groupItem.removeSubscriber(groupItem, "groupHidden");
+    // it should still stay after 3 ms.
+    setTimeout(checkExistence, 3);
+  });
+
+  groupItem.addSubscriber(groupItem, "groupShown", function() {
+    groupItem.removeSubscriber(groupItem, "groupShown");
+
+    let endGame = function() {
+      window.removeEventListener("tabviewhidden", endGame, false);
+      ok(!TabView.isVisible(), "Tab View is hidden");
+
+      groupItem.fadeAwayUndoButtonDelay = fadeAwayUndoButtonDelay;
+      groupItem.fadeAwayUndoButtonDuration = fadeAwayUndoButtonDuration;
+
+      finish();
+    };
+    window.addEventListener("tabviewhidden", endGame, false);
+
+    TabView.toggle();
+  });
+
+  let closeButton = groupItem.container.getElementsByClassName("close");
+  ok(closeButton, "Group item close button exists");
+
+  // store the original values
+  fadeAwayUndoButtonDelay = groupItem.fadeAwayUndoButtonDelay;
+  fadeAwayUndoButtonDuration = groupItem.fadeAwayUndoButtonDuration;
+
+  // set both fade away delay and duration to 1ms
+  groupItem.fadeAwayUndoButtonDelay = 1;
+  groupItem.fadeAwayUndoButtonDuration = 1;
+
+  EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
+}
--- a/browser/base/content/test/tabview/browser_tabview_bug598600.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug598600.js
@@ -30,25 +30,18 @@
  * 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 ***** */
 let newWin;
-let prefService;
-
 function test() {
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-  prefService = 
-    Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).
-      getBranch("browser.panorama.");
-  // make sure we don't trigger the 'first run' behavior
-  prefService.setBoolPref("experienced_first_run", true);
 
   waitForExplicitFinish();
 
   // open a new window and setup the window state.
   newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
   newWin.addEventListener("load", function(event) {
     this.removeEventListener("load", arguments.callee, false);
 
@@ -99,17 +92,16 @@ function test() {
       newWin.removeEventListener("tabviewshown", onTabViewShow, false);
 
       let contentWindow = newWin.document.getElementById("tab-view").contentWindow;
 
       is(contentWindow.GroupItems.groupItems.length, 2, "Has two group items");
       is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphan tabs");
 
       // clean up and finish
-      prefService.setBoolPref("experienced_first_run", false);
       newWin.close();
 
       finish();
     }
     newWin.addEventListener("tabviewshown", onTabViewShow, false);
     newWin.TabView.toggle();
   }, false);
 }
--- a/browser/base/content/test/tabview/browser_tabview_firstrun_pref.js
+++ b/browser/base/content/test/tabview/browser_tabview_firstrun_pref.js
@@ -39,52 +39,64 @@ var prefsBranch = Cc["@mozilla.org/prefe
                   getService(Ci.nsIPrefService).
                   getBranch("browser.panorama.");
 
 function test() {
   waitForExplicitFinish();
 
   ok(!TabView.isVisible(), "Main window TabView is hidden");
 
+  ok(experienced(), "should start as experienced");
+
   prefsBranch.setBoolPref("experienced_first_run", false);
-  ok(!experienced(), "not experienced");
+  ok(!experienced(), "set to not experienced");
 
   newWindowWithTabView(checkFirstRun, part2);
 }
 
 function experienced() {
   return prefsBranch.prefHasUserValue("experienced_first_run") &&
     prefsBranch.getBoolPref("experienced_first_run");
 }
 
 function checkFirstRun(win) {
   let contentWindow = win.document.getElementById("tab-view").contentWindow;
   
-  let infoItems = contentWindow.iQ(".info-item");
-  is(infoItems.length, 1, "There should be an info item");
-
+  is(win.gBrowser.tabs.length, 2, "There should be two tabs");
+  
   let groupItems = contentWindow.GroupItems.groupItems;
   is(groupItems.length, 1, "There should be one group");
+  is(groupItems[0].getChildren().length, 1, "...with one child");
+
+  let orphanTabCount = contentWindow.GroupItems.getOrphanedTabs().length;
+  is(orphanTabCount, 1, "There should also be an orphaned tab");
   
   ok(experienced(), "we're now experienced");
 }
 
 function part2() {
   newWindowWithTabView(checkNotFirstRun, endGame);
 }
 
 function checkNotFirstRun(win) {
   let contentWindow = win.document.getElementById("tab-view").contentWindow;
   
-  let infoItems = contentWindow.iQ(".info-item");
-  is(infoItems.length, 0, "There should be no info items");
+  is(win.gBrowser.tabs.length, 1, "There should be one tab");
+  
+  let groupItems = contentWindow.GroupItems.groupItems;
+  is(groupItems.length, 1, "There should be one group");
+  is(groupItems[0].getChildren().length, 1, "...with one child");
+
+  let orphanTabCount = contentWindow.GroupItems.getOrphanedTabs().length;
+  is(orphanTabCount, 0, "There should also be no orphaned tabs");
 }
 
 function endGame() {
   ok(!TabView.isVisible(), "Main window TabView is still hidden");
+  ok(experienced(), "should finish as experienced");
   finish();
 }
 
 function newWindowWithTabView(callback, completeCallback) {
   let charsetArg = "charset=" + window.content.document.characterSet;
   let win = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no,height=800,width=800",
                               "about:blank", charsetArg, null, null, true);
   let onLoad = function() {
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -156,17 +156,17 @@
           insertLocation = insertLocation.nextSibling;
         if (insertLocation) {
           pasteAndGo = document.createElement("menuitem");
           let label = Services.strings.createBundle("chrome://browser/locale/browser.properties").
                                    GetStringFromName("pasteAndGo.label");
           pasteAndGo.setAttribute("label", label);
           pasteAndGo.setAttribute("anonid", "paste-and-go");
           pasteAndGo.setAttribute("oncommand",
-              "gURLBar.value = ''; goDoCommand('cmd_paste'); gURLBar.handleCommand();");
+              "gURLBar.select(); goDoCommand('cmd_paste'); gURLBar.handleCommand();");
           cxmenu.insertBefore(pasteAndGo, insertLocation.nextSibling);
         }
       ]]></constructor>
 
       <destructor><![CDATA[
         this._prefs.removeObserver("", this);
         this._prefs = null;
         this.inputField.controllers.removeController(this._copyCutController);
@@ -243,18 +243,23 @@
 
           var url = this.value;
           var postData = null;
 
           var action = this._parseActionUrl(url);
           if (action) {
             url = action.param;
             if (!(aTriggeringEvent && aTriggeringEvent.altKey)) {
-              if (action.type == "switchtab")
-                switchToTabHavingURI(url);
+              if (action.type == "switchtab") {
+                this.handleRevert();
+                let prevTab = gBrowser.selectedTab;
+                if (switchToTabHavingURI(url) &&
+                    isTabEmpty(prevTab))
+                  gBrowser.removeTab(prevTab);
+              }
               return;
             }
           }
           else {
             [url, postData] = this._canonizeURL(aTriggeringEvent);
             if (!url)
               return;
           }
@@ -267,18 +272,23 @@
             // Things may go wrong when adding url to session history,
             // but don't let that interfere with the loading of the url.
             Cu.reportError(ex);
           }
 
           if (aTriggeringEvent instanceof MouseEvent) {
             // We have a mouse event (from the go button), so use the standard
             // UI link behaviors
-            openUILink(url, aTriggeringEvent, false, false,
-                       true /* allow third party fixup */, postData);
+            let where = whereToOpenLink(aTriggeringEvent, false, false);
+            if (where != "current") {
+              this.handleRevert();
+              content.focus();
+            }
+            openUILinkIn(url, where,
+                        { allowThirdPartyFixup: true, postData: postData });
             return;
           }
 
           if (aTriggeringEvent && aTriggeringEvent.altKey) {
             this.handleRevert();
             content.focus();
             gBrowser.loadOneTab(url, {
                                 postData: postData,
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -407,19 +407,18 @@ function isBidiEnabled() {
   } catch (e) {}
 
   return rv;
 }
 
 function openAboutDialog() {
   var enumerator = Services.wm.getEnumerator("Browser:About");
   while (enumerator.hasMoreElements()) {
+    // Only open one about window (Bug 599573)
     let win = enumerator.getNext();
-    if (win.opener != window)
-      continue;
     win.focus();
     return;
   }
 
 #ifdef XP_MACOSX
   var features = "chrome,resizable=no,minimizable=no";
 #else
   var features = "chrome,centerscreen,dependent";
@@ -481,117 +480,22 @@ function openTroubleshootingPage()
 /**
  * Opens the feedback page for this version of the application.
  */
 function openFeedbackPage()
 {
   openUILinkIn("http://input.mozilla.com/feedback", "tab");
 }
 
-
-#ifdef MOZ_UPDATER
-/**
- * Opens the update manager and checks for updates to the application.
- */
-function checkForUpdates()
-{
-  var um = 
-      Components.classes["@mozilla.org/updates/update-manager;1"].
-      getService(Components.interfaces.nsIUpdateManager);
-  var prompter = 
-      Components.classes["@mozilla.org/updates/update-prompt;1"].
-      createInstance(Components.interfaces.nsIUpdatePrompt);
-
-  // If there's an update ready to be applied, show the "Update Downloaded"
-  // UI instead and let the user know they have to restart the browser for
-  // the changes to be applied. 
-  if (um.activeUpdate && um.activeUpdate.state == "pending")
-    prompter.showUpdateDownloaded(um.activeUpdate);
-  else
-    prompter.checkForUpdates();
-}
-#endif
-
-#ifdef MOZ_UPDATER
-/**
- * Updates an element to reflect the state of available update services.
- */
-function setupCheckForUpdates(checkForUpdates, aStringBundle)
-{
-  var updates = 
-      Components.classes["@mozilla.org/updates/update-service;1"].
-      getService(Components.interfaces.nsIApplicationUpdateService);
-  var um = 
-      Components.classes["@mozilla.org/updates/update-manager;1"].
-      getService(Components.interfaces.nsIUpdateManager);
-
-  // Disable the UI if the update enabled pref has been locked by the 
-  // administrator or if we cannot update for some other reason
-  var canCheckForUpdates = updates.canCheckForUpdates;
-  checkForUpdates.setAttribute("disabled", !canCheckForUpdates);
-  if (!canCheckForUpdates)
-    return; 
-
-  var activeUpdate = um.activeUpdate;
-
-  // If there's an active update, substitute its name into the label
-  // we show for this item, otherwise display a generic label.
-  function getStringWithUpdateName(key) {
-    if (activeUpdate && activeUpdate.name)
-      return aStringBundle.formatStringFromName(key, [activeUpdate.name], 1);
-    return aStringBundle.GetStringFromName(key + "Fallback");
-  }
-
-  // By default, show "Check for Updates..."
-  var key = "default";
-  if (activeUpdate) {
-    switch (activeUpdate.state) {
-    case "downloading":
-      // If we're downloading an update at present, show the text:
-      // "Downloading Firefox x.x..." otherwise we're paused, and show
-      // "Resume Downloading Firefox x.x..."
-      key = updates.isDownloading ? "downloading" : "resume";
-      break;
-    case "pending":
-      // If we're waiting for the user to restart, show: "Apply Downloaded
-      // Updates Now..."
-      key = "pending";
-      break;
-    }
-  }
-  checkForUpdates.label = getStringWithUpdateName("updatesItem_" + key);
-  checkForUpdates.accessKey = aStringBundle.
-                              GetStringFromName("updatesItem_" + key + ".accesskey");
-  if (um.activeUpdate && updates.isDownloading)
-    checkForUpdates.setAttribute("loading", "true");
-  else
-    checkForUpdates.removeAttribute("loading");
-}
-#endif
-
 function buildHelpMenu()
 {
   // Enable/disable the "Report Web Forgery" menu item.  safebrowsing object
   // may not exist in OSX
   if (typeof safebrowsing != "undefined")
     safebrowsing.setReportPhishingMenu();
-
-#ifdef XP_MACOSX
-#ifdef MOZ_UPDATER
-  var checkForUpdates = document.getElementById("checkForUpdates");
-  var browserBundle = document.getElementById("bundle_browser").stringBundle;
-  setupCheckForUpdates(checkForUpdates, browserBundle);
-#else  
-  // Needed by safebrowsing for inserting its menuitem so just hide it
-  document.getElementById("updateSeparator").hidden = true;
-#endif
-#else
-  // Needed by safebrowsing for inserting its menuitem so just hide it
-  document.getElementById("updateSeparator").hidden = true;
-#endif
 }
 
 function isElementVisible(aElement)
 {
   if (!aElement)
     return false;
 
   // If aElement or a direct or indirect parent is hidden or collapsed,
--- a/browser/branding/nightly/pref/firefox-branding.js
+++ b/browser/branding/nightly/pref/firefox-branding.js
@@ -1,10 +1,11 @@
 pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
 pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
+pref("browser.panorama.welcome_url", "http://www.mozilla.com/firefox/panorama/");
 // The time interval between checks for a new version (in seconds)
 // nightly=8 hours, official=24 hours
 pref("app.update.interval", 28800);
 // The time interval between the downloading of mar file chunks in the
 // background (in seconds)
 pref("app.update.download.backgroundInterval", 60);
 // URL user can browse to manually if for some reason all update installation
 // attempts fail.
--- a/browser/branding/unofficial/pref/firefox-branding.js
+++ b/browser/branding/unofficial/pref/firefox-branding.js
@@ -1,10 +1,11 @@
 pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
 pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
+pref("browser.panorama.welcome_url", "http://www.mozilla.com/firefox/panorama/");
 // The time interval between checks for a new version (in seconds)
 // nightly=8 hours, official=24 hours
 pref("app.update.interval", 28800);
 // The time interval between the downloading of mar file chunks in the
 // background (in seconds)
 pref("app.update.download.backgroundInterval", 60);
 // URL user can browse to manually if for some reason all update installation
 // attempts fail.
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -32,16 +32,18 @@
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 const kIMig = Components.interfaces.nsIBrowserProfileMigrator;
 const kIPStartup = Components.interfaces.nsIProfileStartup;
 const kProfileMigratorContractIDPrefix = "@mozilla.org/profile/migrator;1?app=browser&type=";
+const Cc = Components.classes;
+const Ci = Components.interfaces;
 
 var MigrationWizard = {
   _source: "",                  // Source Profile Migrator ContractID suffix
   _itemsFlags: kIMig.ALL,       // Selected Import Data Sources (16-bit bitfield)
   _selectedProfile: null,       // Selected Profile name to import from
   _wiz: null,
   _migrator: null,
   _autoMigrate: null,
@@ -49,16 +51,17 @@ var MigrationWizard = {
 
   init: function ()
   {
     var os = Components.classes["@mozilla.org/observer-service;1"]
                        .getService(Components.interfaces.nsIObserverService);
     os.addObserver(this, "Migration:Started", false);
     os.addObserver(this, "Migration:ItemBeforeMigrate", false);
     os.addObserver(this, "Migration:ItemAfterMigrate", false);
+    os.addObserver(this, "Migration:ItemError", false);
     os.addObserver(this, "Migration:Ended", false);
 
     this._wiz = document.documentElement;
 
     if ("arguments" in window && window.arguments.length > 1) {
       this._source = window.arguments[0];
       this._migrator = window.arguments[1].QueryInterface(kIMig);
       this._autoMigrate = window.arguments[2].QueryInterface(kIPStartup);
@@ -76,16 +79,17 @@ var MigrationWizard = {
 
   uninit: function ()
   {
     var os = Components.classes["@mozilla.org/observer-service;1"]
                        .getService(Components.interfaces.nsIObserverService);
     os.removeObserver(this, "Migration:Started");
     os.removeObserver(this, "Migration:ItemBeforeMigrate");
     os.removeObserver(this, "Migration:ItemAfterMigrate");
+    os.removeObserver(this, "Migration:ItemError");
     os.removeObserver(this, "Migration:Ended");
   },
 
   // 1 - Import Source
   onImportSourcePageShow: function ()
   {
     // Reference to the "From File" radio button 
     var fromfile = null;
@@ -484,16 +488,45 @@ var MigrationWizard = {
         setTimeout(close, 5000);
       }
       else {
         this._wiz.canAdvance = true;
         var nextButton = this._wiz.getButton("next");
         nextButton.click();
       }
       break;
+    case "Migration:ItemError":
+      var type = "undefined";
+      switch (parseInt(aData)) {
+      case Ci.nsIBrowserProfileMigrator.SETTINGS:
+        type = "settings";
+        break;
+      case Ci.nsIBrowserProfileMigrator.COOKIES:
+        type = "cookies";
+        break;
+      case Ci.nsIBrowserProfileMigrator.HISTORY:
+        type = "history";
+        break;
+      case Ci.nsIBrowserProfileMigrator.FORMDATA:
+        type = "form data";
+        break;
+      case Ci.nsIBrowserProfileMigrator.PASSWORDS:
+        type = "passwords";
+        break;
+      case Ci.nsIBrowserProfileMigrator.BOOKMARKS:
+        type = "bookmarks";
+        break;
+      case Ci.nsIBrowserProfileMigrator.OTHERDATA:
+        type = "misc. data";
+        break;
+      }
+      Cc["@mozilla.org/consoleservice;1"]
+        .getService(Ci.nsIConsoleService)
+        .logStringMessage("some " + type + " did not successfully migrate.");
+      break;
     }
   },
 
   onDonePageShow: function ()
   {
     this._wiz.getButton("cancel").disabled = true;
     this._wiz.canRewind = false;
     this._listItems("doneItems");
--- a/browser/components/migration/src/nsBrowserProfileMigratorUtils.h
+++ b/browser/components/migration/src/nsBrowserProfileMigratorUtils.h
@@ -34,29 +34,31 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef browserprofilemigratorutils___h___
 #define browserprofilemigratorutils___h___
 
 #define MIGRATION_ITEMBEFOREMIGRATE "Migration:ItemBeforeMigrate"
+#define MIGRATION_ITEMMIGRATEERROR  "Migration:ItemError"
 #define MIGRATION_ITEMAFTERMIGRATE  "Migration:ItemAfterMigrate"
 #define MIGRATION_STARTED           "Migration:Started"
 #define MIGRATION_ENDED             "Migration:Ended"
 
 #define NOTIFY_OBSERVERS(message, item) \
   mObserverService->NotifyObservers(nsnull, message, item)
 
 #define COPY_DATA(func, replace, itemIndex) \
-  if (NS_SUCCEEDED(rv) && (aItems & itemIndex || !aItems)) { \
+  if ((aItems & itemIndex || !aItems)) { \
     nsAutoString index; \
     index.AppendInt(itemIndex); \
     NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get()); \
-    rv = func(replace); \
+    if (NS_FAILED(func(replace))) \
+      NOTIFY_OBSERVERS(MIGRATION_ITEMMIGRATEERROR, index.get()); \
     NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get()); \
   }
 
 #define NC_URI(property) \
   NS_LITERAL_CSTRING("http://home.netscape.com/NC-rdf#"#property)
 
 #define BATCH_ACTION_HISTORY 0
 #define BATCH_ACTION_HISTORY_REPLACE 1
--- a/browser/components/migration/src/nsIEProfileMigrator.cpp
+++ b/browser/components/migration/src/nsIEProfileMigrator.cpp
@@ -65,16 +65,18 @@
 #include "nsISimpleEnumerator.h"
 #include "nsISupportsArray.h"
 #include "nsIProfileMigrator.h"
 #include "nsIBrowserProfileMigrator.h"
 #include "nsIObserverService.h"
 #include "nsILocalFileWin.h"
 #include "nsAutoPtr.h"
 
+#include "prnetdb.h"
+
 #include <objbase.h>
 #include <shlguid.h>
 #include <urlhist.h>
 #include <comdef.h>
 #include <shlobj.h>
 #include <intshcut.h>
 
 #include "nsIBrowserHistory.h"
@@ -1914,24 +1916,30 @@ nsIEProfileMigrator::CopyCookiesFromBuff
     PL_strncpy(hostCopyConstructor, host, hostLength);
     hostCopyConstructor += hostLength;
 
     *hostCopyConstructor = '\0';
 
     nsDependentCString stringName(name),
                        stringPath(path);
 
-    // delete any possible extant matching host cookie
-    if (hostCopy[0] == '.')
+    // delete any possible extant matching host cookie and
+    // check if we're dealing with an IPv4/IPv6 hostname.
+    PRBool isIPAddress = PR_FALSE;
+    if (hostCopy[0] == '.') {
       aCookieManager->Remove(nsDependentCString(hostCopy+1),
                              stringName, stringPath, PR_FALSE);
+      PRNetAddr addr;
+      if (PR_StringToNetAddr(hostCopy+1, &addr) == PR_SUCCESS)
+        isIPAddress = PR_TRUE;
+    }
 
     nsresult onerv;
     // Add() makes a new domain cookie
-    onerv = aCookieManager->Add(nsDependentCString(hostCopy),
+    onerv = aCookieManager->Add(nsDependentCString(hostCopy + (isIPAddress ? 1 : 0)),
                                 stringPath,
                                 stringName,
                                 nsDependentCString(value),
                                 flagsValue & 0x1, // isSecure
                                 PR_FALSE, // isHttpOnly
                                 PR_FALSE, // isSession
                                 PRInt64(expirationDate));
     if (NS_FAILED(onerv)) {
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -569,48 +569,53 @@ nsBrowserContentHandler.prototype = {
 
   helpInfo : "  -browser           Open a browser window.\n",
 
   /* nsIBrowserHandler */
 
   get defaultArgs() {
     var prefb = Components.classes["@mozilla.org/preferences-service;1"]
                           .getService(nsIPrefBranch);
-    var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
-                              .getService(Components.interfaces.nsIURLFormatter);
 
     var overridePage = "";
     var haveUpdateSession = false;
     try {
       let override = needHomepageOverride(prefb);
       if (override != OVERRIDE_NONE) {
         // Setup the default search engine to about:home page.
         AboutHomeUtils.loadDefaultSearchEngine();
         AboutHomeUtils.loadSnippetsURL();
 
         switch (override) {
           case OVERRIDE_NEW_PROFILE:
             // New profile.
-            overridePage = formatter.formatURLPref("startup.homepage_welcome_url");
+            overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url");
             break;
           case OVERRIDE_NEW_MSTONE:
             // Existing profile, new milestone build.
             copyPrefOverride();
 
             // Check whether we have a session to restore. If we do, we assume
             // that this is an "update" session.
             var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"]
                                .getService(Components.interfaces.nsISessionStartup);
             haveUpdateSession = ss.doRestore();
-            overridePage = formatter.formatURLPref("startup.homepage_override_url");
+            overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url");
             if (prefb.prefHasUserValue("app.update.postupdate"))
               overridePage = getPostUpdateOverridePage(overridePage);
             break;
         }
       }
+      else {
+        // No need to override homepage, but update snippets url if the pref has
+        // been manually changed.
+        if (Services.prefs.prefHasUserValue(AboutHomeUtils.SNIPPETS_URL_PREF)) {
+          AboutHomeUtils.loadSnippetsURL();
+        }
+      }
     } catch (ex) {}
 
     // formatURLPref might return "about:blank" if getting the pref fails
     if (overridePage == "about:blank")
       overridePage = "";
 
     var startPage = "";
     try {
@@ -877,16 +882,17 @@ nsDefaultCommandLineHandler.prototype = 
                  gBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS);
     }
   },
 
   helpInfo : "",
 };
 
 let AboutHomeUtils = {
+  SNIPPETS_URL_PREF: "browser.aboutHomeSnippets.updateUrl",
   get _storage() {
     let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
     let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
                     getService(Components.interfaces.nsIScriptSecurityManager).
                     getCodebasePrincipal(aboutHomeURI);
     let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
               getService(Components.interfaces.nsIDOMStorageManager);
     return dsm.getLocalStorageForPrincipal(principal, "");
@@ -903,18 +909,18 @@ let AboutHomeUtils = {
     , searchUrl: submission.uri.spec
     }
     this._storage.setItem("search-engine", JSON.stringify(engine));
   },
 
   loadSnippetsURL: function AHU_loadSnippetsURL()
   {
     const STARTPAGE_VERSION = 1;
-    const SNIPPETS_URL = "http://snippets.mozilla.com/" + STARTPAGE_VERSION + "/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/";
-    let updateURL = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"].
-                    getService(Components.interfaces.nsIURLFormatter).
-                    formatURL(SNIPPETS_URL);
+    let updateURL = Services.prefs
+                            .getCharPref(this.SNIPPETS_URL_PREF)
+                            .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
+    updateURL = Services.urlFormatter.formatURL(updateURL);
     this._storage.setItem("snippets-update-url", updateURL);
   },
 };
 
 var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
 var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -494,20 +494,20 @@ PlacesViewBase.prototype = {
     // Here we need the <menu>.
     if (elt.localName == "menupopup")
       elt = elt.parentNode;
 
     if (!aNewTitle && elt.localName != "toolbarbutton") {
       // Many users consider toolbars as shortcuts containers, so explicitly
       // allow empty labels on toolbarbuttons.  For any other element try to be
       // smarter, guessing a title from the uri.
-      elt.label = PlacesUIUtils.getBestTitle(aPlacesNode);
+      elt.setAttribute("label", PlacesUIUtils.getBestTitle(aPlacesNode));
     }
     else {
-      elt.label = aNewTitle;
+      elt.setAttribute("label", aNewTitle);
     }
   },
 
   nodeRemoved:
   function PVB_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) {
     let parentElt = aParentPlacesNode._DOMElement;
     let elt = aPlacesNode._DOMElement;
 
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -715,17 +715,17 @@ var PlacesUIUtils = {
   },
 
   /**
    * By calling this before visiting an URL, any visit in frames will be
    * associated to a TRANSITION_FRAMED_LINK transition.
    * This is actually used to distinguish user-initiated visits in frames
    * so automatic visits can be correctly ignored.
    */
-  markPageAsFollowedLink: function PUIU_markPageAsUserClicked(aURL) {
+  markPageAsFollowedLink: function PUIU_markPageAsFollowedLink(aURL) {
     PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory)
                .markPageAsFollowedLink(this.createFixedURI(aURL));
   },
 
   /**
    * Allows opening of javascript/data URI only if the given node is
    * bookmarked (see bug 224521).
    * @param aURINode
--- a/browser/components/places/tests/browser/Makefile.in
+++ b/browser/components/places/tests/browser/Makefile.in
@@ -61,12 +61,16 @@ include $(topsrcdir)/config/rules.mk
 	browser_library_left_pane_commands.js \
 	browser_drag_bookmarks_on_toolbar.js \
 	browser_library_middleclick.js \
 	browser_library_views_liveupdate.js \
 	browser_views_liveupdate.js \
 	browser_sidebarpanels_click.js \
 	sidebarpanels_click_test_page.html \
 	browser_library_infoBox.js \
+	browser_markPageAsFollowedLink.js \
+	framedPage.html \
+	frameLeft.html \
+	frameRight.html \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_markPageAsFollowedLink.js
@@ -0,0 +1,89 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Tests that visits across frames are correctly represented in the database.
+ */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+const BASE_URL = "http://mochi.test:8888/browser/browser/components/places/tests/browser";
+const PAGE_URL = BASE_URL + "/framedPage.html";
+const LEFT_URL = BASE_URL + "/frameLeft.html";
+const RIGHT_URL = BASE_URL + "/frameRight.html";
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+let gTabLoaded = false;
+let gLeftFrameVisited = false;
+
+let observer = {
+  observe: function(aSubject, aTopic, aData)
+  {
+    let url = aSubject.QueryInterface(Ci.nsIURI).spec;
+    if (url == LEFT_URL ) {
+      is(getTransitionForUrl(url), PlacesUtils.history.TRANSITION_EMBED,
+         "Frames should get a EMBED transition.");
+      gLeftFrameVisited = true;
+      maybeClickLink();
+    }
+    else if (url == RIGHT_URL ) {
+      is(getTransitionForUrl(url), PlacesUtils.history.TRANSITION_FRAMED_LINK,
+         "User activated visits should get a FRAMED_LINK transition.");
+      finish();
+    }
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
+};
+Services.obs.addObserver(observer, "uri-visit-saved", false);
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab(PAGE_URL);
+  let frameCount = 0;
+  gBrowser.selectedTab.linkedBrowser.addEventListener("DOMContentLoaded",
+    function (event)
+    {
+      // Wait for all the frames.
+      if (frameCount++ < 2)
+        return;
+      gBrowser.selectedTab.linkedBrowser.removeEventListener("DOMContentLoaded", arguments.callee, false)
+      gTabLoaded = true;
+      maybeClickLink();
+    }, false
+  );
+}
+
+function maybeClickLink() {
+  if (gTabLoaded && gLeftFrameVisited) {
+    // Click on the link in the left frame to cause a page load in the
+    // right frame.
+    EventUtils.sendMouseEvent({type: "click"}, "clickme", content.frames[0]);
+  }
+}
+
+function getTransitionForUrl(aUrl)
+{
+  let dbConn = PlacesUtils.history
+                          .QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
+  let stmt = dbConn.createStatement(
+    "SELECT visit_type FROM moz_historyvisits_view WHERE place_id = " +
+      "(SELECT id FROM moz_places_view WHERE url = :page_url)");
+  stmt.params.page_url = aUrl;
+  try {
+    ok(stmt.executeStep(), "Found the visit in the database");
+    return stmt.row.visit_type;
+  }
+  finally {
+    stmt.finalize();
+  }
+}
+
+registerCleanupFunction(function ()
+{
+  gBrowser.removeTab(gBrowser.selectedTab);
+  Services.obs.removeObserver(observer, "uri-visit-saved");
+})
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -286,18 +286,18 @@ var bookmarksObserver = {
         let cellText = tree.view.getCellText(aElementOrTreeIndex,
                                              tree.columns.getColumnAt(0));
         if (!aNewValue)
           return cellText == PlacesUIUtils.getBestTitle(tree.view.nodeForTreeIndex(aElementOrTreeIndex));
         return cellText == aNewValue;
       }
       else {
         if (!aNewValue && aElementOrTreeIndex.localName != "toolbarbutton")
-          return aElementOrTreeIndex.label == PlacesUIUtils.getBestTitle(aElementOrTreeIndex._placesNode);
-        return aElementOrTreeIndex.label == aNewValue;
+          return aElementOrTreeIndex.getAttribute("label") == PlacesUIUtils.getBestTitle(aElementOrTreeIndex._placesNode);
+        return aElementOrTreeIndex.getAttribute("label") == aNewValue;
       }
     };
 
     for (var i = 0; i < views.length; i++) {
       var [node, index, valid] = searchItemInView(aItemId, views[i], validator);
       isnot(node, null, "Found changed Places node in " + views[i]);
       is(node.title, aNewValue, "Node has correct title: " + aNewValue);
       ok(valid, "Node element has correct label: " + aNewValue);
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/frameLeft.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>Left frame</title>
+  </head>
+  <body>
+    <a id="clickme" href="frameRight.html" target="right">Open page in the right frame.</a>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/frameRight.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>Right Frame</title>
+  </head>
+  <body>
+    This is the right frame.
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/framedPage.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <title>Framed page</title>
+  </head>
+  <frameset cols="*,*">
+    <frame name="left" src="frameLeft.html">
+    <frame name="right" src="about:robots">
+  </frameset>
+</html>
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
@@ -40,22 +40,20 @@
   <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
   %htmlDTD;
   <!ENTITY % netErrorDTD SYSTEM "chrome://global/locale/netError.dtd">
   %netErrorDTD;
   <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
   %globalDTD;
   <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
   %browserDTD;
-#ifdef XP_WIN
-  <!ENTITY basePBMenu.label   "<span class='appMenuButton'>&brandShortName;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
-#elifdef XP_MACOSX
+#ifdef XP_MACOSX
   <!ENTITY basePBMenu.label   "&toolsMenu.label;">
 #else
-  <!ENTITY basePBMenu.label   "<span class='appMenuButton'>&appMenuButton.label;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
+  <!ENTITY basePBMenu.label   "<span class='appMenuButton'>&brandShortName;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
 #endif
   <!ENTITY % privatebrowsingpageDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
   %privatebrowsingpageDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all"/>
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -464,18 +464,20 @@ PrivateBrowsingService.prototype = {
   },
 
   // nsICommandLineHandler
 
   handle: function PBS_handle(aCmdLine) {
     if (aCmdLine.handleFlag("private", false))
       ; // It has already been handled
     else if (aCmdLine.handleFlag("private-toggle", false)) {
+      if (this._autoStarted) {
+        throw Cr.NS_ERROR_ABORT;
+      }
       this.privateBrowsingEnabled = !this.privateBrowsingEnabled;
-      this._autoStarted = false;
       this._lastChangedByCommandLine = true;
     }
   },
 
   get helpInfo() {
     return "  -private           Enable private browsing mode.\n" +
            "  -private-toggle    Toggle private browsing mode.\n";
   },
--- a/browser/components/safebrowsing/content/report-phishing-overlay.xul
+++ b/browser/components/safebrowsing/content/report-phishing-overlay.xul
@@ -47,21 +47,21 @@
   <broadcasterset id="mainBroadcasterSet">
     <broadcaster id="reportPhishingBroadcaster" disabled="true"/>
     <broadcaster id="reportPhishingErrorBroadcaster" disabled="true"/>
   </broadcasterset>
   <menupopup id="menu_HelpPopup">
     <menuitem id="menu_HelpPopup_reportPhishingtoolmenu"
               label="&reportPhishSiteMenu.title2;"
               accesskey="&reportPhishSiteMenu.accesskey;"
-              insertbefore="updateSeparator"
+              insertbefore="aboutSeparator"
               observes="reportPhishingBroadcaster"
               oncommand="openUILink(safebrowsing.getReportURL('Phish'), event);"
               onclick="checkForMiddleClick(this, event);"/>
     <menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu"
               label="&safeb.palm.notforgery.label2;"
               accesskey="&reportPhishSiteMenu.accesskey;"
-              insertbefore="updateSeparator"
+              insertbefore="aboutSeparator"
               observes="reportPhishingErrorBroadcaster"
               oncommand="openUILinkIn(safebrowsing.getReportURL('Error'), 'tab');"
               onclick="checkForMiddleClick(this, event);"/>
   </menupopup>
 </overlay>
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -600,17 +600,17 @@
                  insertLocation.getAttribute("cmd") != "cmd_paste")
             insertLocation = insertLocation.nextSibling;
           if (insertLocation) {
             element = document.createElementNS(kXULNS, "menuitem");
             label = this._stringBundle.getString("cmd_pasteAndSearch");
             element.setAttribute("label", label);
             element.setAttribute("anonid", "paste-and-search");
             element.setAttribute("oncommand",
-                "BrowserSearch.searchBar.value = ''; goDoCommand('cmd_paste'); BrowserSearch.searchBar.handleSearchCommand();");
+                "BrowserSearch.searchBar.select(); goDoCommand('cmd_paste'); BrowserSearch.searchBar.handleSearchCommand();");
             cxmenu.insertBefore(element, insertLocation.nextSibling);
             pasteAndSearch = element;
           }
 
           element = document.createElementNS(kXULNS, "menuitem");
           label = this._stringBundle.getString("cmd_clearHistory");
           akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
           element.setAttribute("label", label);
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -740,34 +740,69 @@ SessionStoreService.prototype = {
       let followUp = this._statesToRestore[aWindow.__SS_restoreID].windows.length == 1;
       this.restoreWindow(aWindow, this._statesToRestore[aWindow.__SS_restoreID], true, followUp);
     }
     else if (this._restoreLastWindow && aWindow.toolbar.visible &&
              this._closedWindows.length &&
              !this._inPrivateBrowsing) {
       // default to the most-recently closed window
       // don't use popup windows
-      let state = null;
-      let newClosedWindows = this._closedWindows.filter(function(aWinState) {
-        if (!state && !aWinState.isPopup) {
-          state = aWinState;
-          return false;
+      let closedWindowState = null;
+      let closedWindowIndex;
+      for (let i = 0; i < this._closedWindows.length; i++) {
+        // Take the first non-popup, point our object at it, and break out.
+        if (!this._closedWindows[i].isPopup) {
+          closedWindowState = this._closedWindows[i];
+          closedWindowIndex = i;
+          break;
         }
-        return true;
-      });
-      if (state) {
-        delete state.hidden;
+      }
+
+      if (closedWindowState) {
+        let newWindowState;
 #ifndef XP_MACOSX
-        if (!this._doResumeSession())
+        if (!this._doResumeSession()) {
 #endif
-          state.tabs = state.tabs.filter(function (tab) tab.pinned);
-        if (state.tabs.length > 0) {
-          this._closedWindows = newClosedWindows;
+          // We want to split the window up into pinned tabs and unpinned tabs.
+          // Pinned tabs should be restored. If there are any remaining tabs,
+          // they should be added back to _closedWindows.
+          // We'll cheat a little bit and reuse _prepDataForDeferredRestore
+          // even though it wasn't built exactly for this.
+          let [appTabsState, normalTabsState] =
+            this._prepDataForDeferredRestore(JSON.stringify({ windows: [closedWindowState] }));
+
+          // These are our pinned tabs, which we should restore
+          if (appTabsState.windows.length) {
+            newWindowState = appTabsState.windows[0];
+            delete newWindowState.__lastSessionWindowID;
+          }
+
+          // In case there were no unpinned tabs, remove the window from _closedWindows
+          if (!normalTabsState.windows.length) {
+            this._closedWindows.splice(closedWindowIndex, 1);
+          }
+          // Or update _closedWindows with the modified state
+          else {
+            delete normalTabsState.windows[0].__lastSessionWindowID;
+            this._closedWindows[closedWindowIndex] = normalTabsState.windows[0];
+          }
+#ifndef XP_MACOSX
+        }
+        else {
+          // If we're just restoring the window, make sure it gets removed from
+          // _closedWindows.
+          this._closedWindows.splice(closedWindowIndex, 1);
+          newWindowState = closedWindowState;
+          delete newWindowState.hidden;
+        }
+#endif
+        if (newWindowState) {
+          // Ensure that the window state isn't hidden
           this._restoreCount = 1;
-          state = { windows: [state] };
+          let state = { windows: [newWindowState] };
           this.restoreWindow(aWindow, state, this._isCmdLineEmpty(aWindow, state));
         }
       }
       // we actually restored the session just now.
       this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
     }
     if (this._restoreLastWindow && aWindow.toolbar.visible) {
       // always reset (if not a popup window)
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -115,16 +115,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_524745.js \
 	browser_528776.js \
 	browser_579868.js \
 	browser_579879.js \
 	browser_580512.js \
 	browser_581593.js \
 	browser_586147.js \
 	browser_586068-cascaded_restore.js \
+	browser_589246.js \
 	browser_590268.js \
 	browser_600545.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),Darwin)
 _BROWSER_TEST_FILES += \
 	browser_597071.js \
 	$(NULL)
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_589246.js
@@ -0,0 +1,276 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is sessionstore test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Paul O’Shannessy <paul@oshannessy.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Mirrors WINDOW_ATTRIBUTES IN nsSessionStore.js
+const WINDOW_ATTRIBUTES = ["width", "height", "screenX", "screenY", "sizemode"];
+
+Cu.import("resource://gre/modules/Services.jsm");
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+         getService(Ci.nsISessionStore);
+
+let stateBackup = ss.getBrowserState();
+
+let originalWarnOnClose = gPrefService.getBoolPref("browser.tabs.warnOnClose");
+let originalStartupPage = gPrefService.getIntPref("browser.startup.page");
+let originalWindowType = document.documentElement.getAttribute("windowtype");
+
+let gotLastWindowClosedTopic = false;
+let shouldPinTab = false;
+let shouldOpenTabs = false;
+let shouldCloseTab = false;
+let testNum = 0;
+let afterTestCallback;
+
+// Set state so we know the closed windows content
+let testState = {
+  windows: [
+    { tabs: [{ entries: [{ url: "http://example.org" }] }] }
+  ],
+  _closedWindows: []
+};
+
+// We'll push a set of conditions and callbacks into this array
+// Ideally we would also test win/linux under a complete set of conditions, but
+// the tests for osx mirror the other set of conditions possible on win/linux.
+let tests = [];
+
+// the third & fourth test share a condition check, keep it DRY
+function checkOSX34Generator(num) {
+  return function(aPreviousState, aCurState) {
+    // In here, we should have restored the pinned tab, so only the unpinned tab
+    // should be in aCurState. So let's shape our expectations.
+    let expectedState = JSON.parse(aPreviousState);
+    expectedState[0].tabs.shift();
+    // size attributes are stripped out in _prepDataForDeferredRestore in nsSessionStore.
+    // This isn't the best approach, but neither is comparing JSON strings
+    WINDOW_ATTRIBUTES.forEach(function (attr) delete expectedState[0][attr]);
+
+    is(aCurState, JSON.stringify(expectedState),
+       "test #" + num + ": closedWindowState is as expected");
+  };
+}
+function checkNoWindowsGenerator(num) {
+  return function(aPreviousState, aCurState) {
+    is(aCurState, "[]", "test #" + num + ": there should be no closedWindowsLeft");
+  };
+}
+
+// The first test has 0 pinned tabs and 1 unpinned tab
+tests.push({
+  pinned: false,
+  extra: false,
+  close: false,
+  checkWinLin: checkNoWindowsGenerator(1),
+  checkOSX: function(aPreviousState, aCurState) {
+    is(aCurState, aPreviousState, "test #1: closed window state is unchanged");
+  }
+});
+
+// The second test has 1 pinned tab and 0 unpinned tabs.
+tests.push({
+  pinned: true,
+  extra: false,
+  close: false,
+  checkWinLin: checkNoWindowsGenerator(2),
+  checkOSX: checkNoWindowsGenerator(2)
+});
+
+// The third test has 1 pinned tab and 2 unpinned tabs.
+tests.push({
+  pinned: true,
+  extra: true,
+  close: false,
+  checkWinLin: checkNoWindowsGenerator(3),
+  checkOSX: checkOSX34Generator(3)
+});
+
+// The fourth test has 1 pinned tab, 2 unpinned tabs, and closes one unpinned tab.
+tests.push({
+  pinned: true,
+  extra: true,
+  close: "one",
+  checkWinLin: checkNoWindowsGenerator(4),
+  checkOSX: checkOSX34Generator(4)
+});
+
+// The fifth test has 1 pinned tab, 2 unpinned tabs, and closes both unpinned tabs.
+tests.push({
+  pinned: true,
+  extra: true,
+  close: "both",
+  checkWinLin: checkNoWindowsGenerator(5),
+  checkOSX: checkNoWindowsGenerator(5)
+});
+
+
+function test() {
+  /** Test for Bug 589246 - Closed window state getting corrupted when closing
+      and reopening last browser window without exiting browser **/
+  waitForExplicitFinish();
+  // windows opening & closing, so extending the timeout
+  requestLongerTimeout(2);
+
+  // We don't want the quit dialog pref
+  gPrefService.setBoolPref("browser.tabs.warnOnClose", false);
+  // Ensure that we would restore the session (important for Windows)
+  gPrefService.setIntPref("browser.startup.page", 3);
+
+  runNextTestOrFinish();
+}
+
+function runNextTestOrFinish() {
+  if (tests.length) {
+    setupForTest(tests.shift())
+  }
+  else {
+    // some state is cleaned up at the end of each test, but not all
+    ["browser.tabs.warnOnClose", "browser.startup.page"].forEach(function(p) {
+      if (gPrefService.prefHasUserValue(p))
+        gPrefService.clearUserPref(p);
+    });
+
+    ss.setBrowserState(stateBackup);
+    executeSoon(finish);
+  }
+}
+
+function setupForTest(aConditions) {
+  // reset some checks
+  gotLastWindowClosedTopic = false;
+  shouldPinTab = aConditions.pinned;
+  shouldOpenTabs = aConditions.extra;
+  shouldCloseTab = aConditions.close;
+  testNum++;
+
+  // set our test callback
+  afterTestCallback = /Mac/.test(navigator.platform) ? aConditions.checkOSX
+                                                     : aConditions.checkWinLin;
+
+  // Add observers
+  Services.obs.addObserver(onLastWindowClosed, "browser-lastwindow-close-granted", false);
+
+  // Set the state
+  Services.obs.addObserver(onStateRestored, "sessionstore-browser-state-restored", false);
+  ss.setBrowserState(JSON.stringify(testState));
+}
+
+function onStateRestored(aSubject, aTopic, aData) {
+  info("test #" + testNum + ": onStateRestored");
+  Services.obs.removeObserver(onStateRestored, "sessionstore-browser-state-restored", false);
+
+  // change this window's windowtype so that closing a new window will trigger
+  // browser-lastwindow-close-granted.
+  document.documentElement.setAttribute("windowtype", "navigator:testrunner");
+
+  let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "http://example.com");
+  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);
+
+      // pin this tab
+      if (shouldPinTab)
+        newWin.gBrowser.pinTab(newWin.gBrowser.selectedTab);
+
+      newWin.addEventListener("unload", 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() {
+          newTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+
+          if (shouldCloseTab == "one") {
+            newWin.gBrowser.removeTab(newTab2);
+          }
+          else if (shouldCloseTab == "both") {
+            newWin.gBrowser.removeTab(newTab);
+            newWin.gBrowser.removeTab(newTab2);
+          }
+          newWin.BrowserTryToCloseWindow();
+        }, true);
+      }
+      else {
+        newWin.BrowserTryToCloseWindow();
+      }
+    }, true);
+  }, false);
+}
+
+// This will be called before the window is actually closed
+function onLastWindowClosed(aSubject, aTopic, aData) {
+  info("test #" + testNum + ": onLastWindowClosed");
+  Services.obs.removeObserver(onLastWindowClosed, "browser-lastwindow-close-granted", false);
+  gotLastWindowClosedTopic = true;
+}
+
+// This is the unload event listener on the new window (from onStateRestored).
+// Unload is fired after the window is closed, so sessionstore has already
+// updated _closedWindows (which is important). We'll open a new window here
+// which should actually trigger the bug.
+function onWindowUnloaded() {
+  info("test #" + testNum + ": onWindowClosed");
+  ok(gotLastWindowClosedTopic, "test #" + testNum + ": browser-lastwindow-close-granted was notified prior");
+
+  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 () {
+      // Good enough for checking the state
+      afterTestCallback(previousClosedWindowData, ss.getClosedWindowData());
+      afterTestCleanup(newWin);
+    }, true);
+
+  }, false);
+}
+
+function afterTestCleanup(aNewWin) {
+  executeSoon(function() {
+    aNewWin.close();
+    document.documentElement.setAttribute("windowtype", originalWindowType);
+    runNextTestOrFinish();
+  });
+}
+
--- a/browser/components/wintaskbar/WindowsJumpLists.jsm
+++ b/browser/components/wintaskbar/WindowsJumpLists.jsm
@@ -255,20 +255,17 @@ var WinTaskbarJumpList =
    *       _pendingStatements object, using a different LIST_TYPE entry for
    *       each statement. Once finished they must remove it and call
    *       commitBuild().  When there will be no more _pendingStatements,
    *       commitBuild() will commit for real.
    */
 
   _pendingStatements: {},
   _hasPendingStatements: function WTBJL__hasPendingStatements() {
-    for (let listType in this._pendingStatements) {
-      return true;
-    }
-    return false;
+    return Object.keys(this._pendingStatements).length > 0;
   },
 
   _buildList: function WTBJL__buildList() {
     if (this._hasPendingStatements()) {
       // We were requested to update the list while another update was in
       // progress, this could happen at shutdown, idle or privatebrowsing.
       // Abort the current list building.
       for (let listType in this._pendingStatements) {
@@ -339,16 +336,21 @@ var WinTaskbarJumpList =
   },
 
   _buildCustom: function WTBJL__buildCustom(title, items) {
     if (items.length > 0)
       this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_CUSTOMLIST, items, title);
   },
 
   _buildFrequent: function WTBJL__buildFrequent() {
+    // If history is empty, just bail out.
+    if (!PlacesUtils.history.hasHistoryEntries) {
+      return;
+    }
+
     // Windows supports default frequent and recent lists,
     // but those depend on internal windows visit tracking
     // which we don't populate. So we build our own custom
     // frequent and recent lists using our nav history data.
 
     var items = Cc["@mozilla.org/array;1"].
                 createInstance(Ci.nsIMutableArray);
     // track frequent items so that we don't add them to
@@ -372,16 +374,21 @@ var WinTaskbarJumpList =
         items.appendElement(shortcut, false);
         this._frequentHashList.push(aResult.uri);
       },
       this
     );
   },
 
   _buildRecent: function WTBJL__buildRecent() {
+    // If history is empty, just bail out.
+    if (!PlacesUtils.history.hasHistoryEntries) {
+      return;
+    }
+
     var items = Cc["@mozilla.org/array;1"].
                 createInstance(Ci.nsIMutableArray);
     // Frequent items will be skipped, so we select a double amount of
     // entries and stop fetching results at _maxItemCount.
     var count = 0;
 
     this._pendingStatements[LIST_TYPE.RECENT] = this._getHistoryResults(
       Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING,
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -208,16 +208,17 @@
 @BINPATH@/components/necko_file.xpt
 @BINPATH@/components/necko_ftp.xpt
 @BINPATH@/components/necko_http.xpt
 @BINPATH@/components/necko_res.xpt
 @BINPATH@/components/necko_socket.xpt
 @BINPATH@/components/necko_strconv.xpt
 @BINPATH@/components/necko_viewsource.xpt
 @BINPATH@/components/necko_wifi.xpt
+@BINPATH@/components/necko_wyciwyg.xpt
 @BINPATH@/components/necko.xpt
 @BINPATH@/components/loginmgr.xpt
 @BINPATH@/components/parentalcontrols.xpt
 @BINPATH@/components/places.xpt
 @BINPATH@/components/plugin.xpt
 @BINPATH@/components/pref.xpt
 @BINPATH@/components/prefetch.xpt
 @BINPATH@/components/profile.xpt
@@ -378,18 +379,16 @@
 #endif
 @BINPATH@/components/nsINIProcessor.manifest
 @BINPATH@/components/nsINIProcessor.js
 @BINPATH@/components/nsPrompter.manifest
 @BINPATH@/components/nsPrompter.js
 #ifdef MOZ_SERVICES_SYNC
 @BINPATH@/components/SyncComponents.manifest
 @BINPATH@/components/Weave.js
-@BINPATH@/components/WeaveCrypto.manifest
-@BINPATH@/components/WeaveCrypto.js
 #endif
 
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsSafebrowsingApplication.manifest
 @BINPATH@/components/nsSafebrowsingApplication.js
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -62,16 +62,18 @@ components/nsCloseAllWindows.js
 components/nsDictionary.js
 components/nsExtensionManager.js
 components/nsInterfaceInfoToIDL.js
 components/nsScriptableIO.js
 components/nsUrlClassifierTable.js
 components/nsXmlRpcClient.js
 components/pluginGlue.js
 components/sidebar.xpt
+components/WeaveCrypto.js
+components/WeaveCrypto.manifest
 components/xmlextras.xpt
 components/xpcom.xpt
 components/xpti.dat
 components/xptitemp.dat
 defaults/pref/all.js
 defaults/pref/bug259708.js
 defaults/pref/bug307259.js
 defaults/pref/reporter.js
@@ -616,17 +618,16 @@ xpicleanup@BIN_SUFFIX@
   components/nsUrlClassifierLib.js
   components/nsUrlClassifierListManager.js
   components/nsURLFormatter.js
   components/nsWebHandlerApp.js
   components/PlacesProtocolHandler.js
   components/storage-Legacy.js
   components/storage-mozStorage.js
   components/txEXSLTRegExFunctions.js
-  components/WeaveCrypto.js
   components/Weave.js
   components/WebContentConverter.js
   defaults/autoconfig/platform.js
   defaults/autoconfig/prefcalls.js
   defaults/pref/firefox-branding.js
   defaults/pref/firefox.js
   defaults/pref/firefox-l10n.js
   defaults/pref/services-sync.js
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -228,17 +228,17 @@ menuitem.bookmark-item {
   list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
 }
 
 .bookmark-item[query][hostContainer][open] {
   list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
 }
 
 /* Stock icons for the menu bar items */
-menuitem:not([type]) {
+menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
 }
 
 #placesContext_open\:newwindow,
 #menu_newNavigator,
 #context-openlink,
 #context-openframe {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
@@ -467,16 +467,23 @@ menuitem:not([type]) {
   -moz-image-region: rect(0px 32px 16px 16px);
 }
 
 #bookmarksShowAll {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 48px 16px 32px);
 }
 
+#subscribeToPageMenuitem:not([disabled]),
+#subscribeToPageMenupopup,
+#BMB_subscribeToPageMenuitem:not([disabled]),
+#BMB_subscribeToPageMenupopup {
+  list-style-image: url("chrome://browser/skin/page-livemarks.png");
+}
+
 #bookmarksToolbarFolderMenu,
 #BMB_bookmarksToolbar {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
 }
 
 #BMB_bookmarkThisPage {
   list-style-image: url("chrome://browser/skin/places/starPage.png");
 }
--- a/browser/themes/gnomestripe/browser/sanitizeDialog.css
+++ b/browser/themes/gnomestripe/browser/sanitizeDialog.css
@@ -31,17 +31,17 @@
 #sanitizeEverythingWarningBox {
   background-color: Window;
   border: 1px solid ThreeDDarkShadow;
   border-radius: 5px;
   padding: 16px;
 }
 
 #sanitizeEverythingWarningIcon {
-  list-style-image: url("chrome://global/skin/icons/warning-large.png");
+  list-style-image: url("moz-icon://stock/gtk-dialog-warning?size=dialog");
   padding: 0;
   margin: 0;
 }
 
 #sanitizeEverythingWarningDescBox {
   padding: 0 16px;
   margin: 0;
 }
--- a/browser/themes/gnomestripe/browser/syncCommon.css
+++ b/browser/themes/gnomestripe/browser/syncCommon.css
@@ -9,21 +9,21 @@
   max-width: 16px;
 }
 
 .statusIcon[status="active"] {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
 }
 
 .statusIcon[status="error"] {
-  list-style-image: url("chrome://global/skin/icons/error-16.png");
+  list-style-image: url("moz-icon://stock/gtk-dialog-error?size=menu");
 }
 
 .statusIcon[status="success"] {
-  list-style-image: url("chrome://global/skin/icons/information-16.png");
+  list-style-image: url("moz-icon://stock/gtk-dialog-info?size=menu");
 }
 
 /* .data is only used by syncGenericChange.xul, but it seems unnecessary to have
    a separate stylesheet for it. */
 .data {
   font-size: 90%;
   font-weight: bold;
 }
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -350,18 +350,26 @@ toolbar:not([mode="icons"]) #restore-but
 }
 
 .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
 .toolbarbutton-1[type="menu-button"] > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
 #restore-button[disabled="true"] > .toolbarbutton-icon {
   opacity: .4;
 }
 
+.toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
 .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker.png);
+}
+
+.toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
+  -moz-margin-end: 1px;
+}
+
+.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   width: 14px;
   padding-top: 2px;
   -moz-border-start: none !important;
 }
 
 toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   width: auto;
   padding-top: 0;
@@ -1932,17 +1940,16 @@ toolbarbutton.chevron > .toolbarbutton-m
   -moz-appearance: none;
   background-color: #fffcd6;
   border: 1px solid #dad8b6;
   padding: 5px 5px 5px 5px;
   font-weight: bold;
 }
 
 #notification-popup {
-  color: #fff;
   margin-left: -16px;
   margin-right: -16px;
 }
 
 #notification-popup-box {
   margin: 0 3px;
 }
 
--- a/browser/themes/winstripe/browser/browser-aero.css
+++ b/browser/themes/winstripe/browser/browser-aero.css
@@ -28,29 +28,22 @@
     border-top: none;
     -moz-border-left-colors: rgba(255,255,255,.5) rgba(83,42,6,.9);
     -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(83,42,6,.9);
     -moz-border-right-colors: rgba(255,255,255,.5) rgba(83,42,6,.9);
     box-shadow: 0 1px 0 rgba(255,255,255,.25) inset,
                 0 0 2px 1px rgba(255,255,255,.25) inset;
   }
 
-  #main-window[privatebrowsingmode=temporary] #appmenu-button:not(:-moz-window-inactive) {
+  #main-window[privatebrowsingmode=temporary] #appmenu-button {
     -moz-border-left-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
     -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
     -moz-border-right-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
   }
 
-  #appmenu-button:-moz-window-inactive {
-    -moz-border-left-colors: rgba(255,255,255,.4) rgba(0,0,0,.5);
-    -moz-border-bottom-colors: rgba(255,255,255,.4) rgba(0,0,0,.5);
-    -moz-border-right-colors: rgba(255,255,255,.4) rgba(0,0,0,.5);
-    box-shadow: 0 0 0 1px rgba(255,255,255,.25) inset;
-  }
-
   /* Bug 413060, comment 16: Vista Aero is a special case where we use a
      tooltip appearance for the address bar popup panels */
   #identity-popup,
   #editBookmarkPanel {
     -moz-appearance: tooltip;
     color: InfoText;
   }
 
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -121,26 +121,21 @@
   color: white;
   text-shadow: 0 0 1px rgba(0,0,0,.7),
                0 1px 1.5px rgba(0,0,0,.5);
   font-weight: bold;
   padding: .1em 1.5em .15em;
   margin: 0;
 }
 
-#main-window[privatebrowsingmode=temporary] #appmenu-button:not(:-moz-window-inactive) {
+#main-window[privatebrowsingmode=temporary] #appmenu-button {
   background-image: -moz-linear-gradient(rgb(153,38,211), rgb(105,19,163) 95%);
   border-color: rgba(43,8,65,.9);
 }
 
-#appmenu-button:-moz-window-inactive {
-  background-image: none;
-  border-color: rgba(0,0,0,.4);
-}
-
 #appmenu-button:hover:not(:active):not([open]) {
   background-image: -moz-radial-gradient(center bottom, farthest-side, rgba(252,240,89,.5) 10%, rgba(252,240,89,0) 70%),
                     -moz-radial-gradient(center bottom, farthest-side, rgb(236,133,0), rgba(255,229,172,0)),
                     -moz-linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%);
   border-color: rgba(83,42,6,.9);
   box-shadow: 0 1px 0 rgba(255,255,255,.1) inset,
               0 0 1.5px 1px rgba(250,234,169,.7) inset,
               0 -1px 0 rgba(250,234,169,.5) inset;
@@ -297,24 +292,16 @@
 #appmenu_privateBrowsing {
   list-style-image: url("chrome://browser/skin/Privacy-16.png");
 }
 
 #appmenu_addons {
   list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
 }
 
-#BMB_subscribeToPage:not([disabled]),
-#BMB_subscribeToPageMenu,
-#appmenu_subscribeToPage:not([disabled]),
-#appmenu_subscribeToPageMenu {
-  list-style-image: url("chrome://browser/skin/feeds/feed-icons-16.png");
-  -moz-image-region: rect(0px 16px 16px 0px);
-}
-
 #BMB_bookmarkThisPage,
 #appmenu_bookmarkThisPage {
   list-style-image: url("chrome://browser/skin/places/bookmark.png");
   -moz-image-region: rect(0 16px 16px 0);
 }
 
 /* ::::: titlebar ::::: */
 
@@ -1867,17 +1854,17 @@ toolbarbutton.bookmark-item[dragover="tr
   -moz-margin-end: 10px;
 }
 
 .popup-notification-icon[popupid="geolocation"] {
   list-style-image: url(chrome://browser/skin/Geolocation-64.png);
 }
 
 .geolocation-text-link {
-  padding-top: 5px;
+  margin-top: 17px;
 }
 
 .popup-notification-icon[popupid="xpinstall-disabled"],
 .popup-notification-icon[popupid="addon-install-blocked"],
 .popup-notification-icon[popupid="addon-install-failed"],
 .popup-notification-icon[popupid="addon-install-complete"] {
   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
   width: 32px;
@@ -1931,16 +1918,25 @@ toolbarbutton.bookmark-item[dragover="tr
 }
 
 #download-monitor {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
   -moz-image-region: rect(0, 108px, 18px, 90px);
 }
 
 /* Bookmarks roots menu-items */
+#appmenu_subscribeToPage:not([disabled]),
+#appmenu_subscribeToPageMenu,
+#subscribeToPageMenuitem:not([disabled]),
+#subscribeToPageMenupopup,
+#BMB_subscribeToPageMenuitem:not([disabled]),
+#BMB_subscribeToPageMenupopup {
+  list-style-image: url("chrome://browser/skin/feeds/feedIcon16.png");
+}
+
 #bookmarksToolbarFolderMenu,
 #appmenu_bookmarksToolbar,
 #BMB_bookmarksToolbar {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
   -moz-image-region: auto;
 }
 
 #appmenu_unsortedBookmarks,
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -355,16 +355,17 @@ user_pref("javascript.options.jitprofili
 user_pref("gfx.color_management.force_srgb", true);
 user_pref("network.manage-offline-status", false);
 user_pref("test.mousescroll", true);
 user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
 user_pref("network.http.prompt-temp-redirect", false);
 user_pref("media.cache_size", 100);
 user_pref("security.warn_viewing_mixed", false);
 user_pref("app.update.enabled", false);
+user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
 
 // Only load extensions from the application and user profile
 // AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
 user_pref("extensions.enabledScopes", 5);
 // Disable metadata caching for installed add-ons by default
 user_pref("extensions.getAddons.cache.enabled", false);
 
 user_pref("extensions.testpilot.runStudies", false);
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -110,33 +110,45 @@ def checkForCrashes(dumpDir, symbolsPath
     except:
       testName = "unknown"
 
   foundCrash = False
   dumps = glob.glob(os.path.join(dumpDir, '*.dmp'))
   for d in dumps:
     log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName)
     if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath):
-      nullfd = open(os.devnull, 'w')
-      # eat minidump_stackwalk errors
-      subprocess.call([stackwalkPath, d, symbolsPath], stderr=nullfd)
-      nullfd.close()
+      p = subprocess.Popen([stackwalkPath, d, symbolsPath],
+                           stdout=subprocess.PIPE,
+                           stderr=subprocess.PIPE)
+      (out, err) = p.communicate()
+      if len(out) > 3:
+        # minidump_stackwalk is chatty, so ignore stderr when it succeeds.
+        print out
+      else:
+        print "stderr from minidump_stackwalk:"
+        print err
+      if p.returncode != 0:
+        print "minidump_stackwalk exited with return code %d" % p.returncode
     elif stackwalkCGI and symbolsPath and isURL(symbolsPath):
       f = None
       try:
         f = open(d, "rb")
         sys.path.append(os.path.join(os.path.dirname(__file__), "poster.zip"))
         from poster.encode import multipart_encode
         from poster.streaminghttp import register_openers
         import urllib2
         register_openers()
         datagen, headers = multipart_encode({"minidump": f,
                                              "symbols": symbolsPath})
         request = urllib2.Request(stackwalkCGI, datagen, headers)
-        print urllib2.urlopen(request).read()
+        result = urllib2.urlopen(request).read()
+        if len(result) > 3:
+          print result
+        else:
+          print "stackwalkCGI returned nothing."
       finally:
         if f:
           f.close()
     else:
       if not symbolsPath:
         print "No symbols path given, can't process dump."
       if not stackwalkPath and not stackwalkCGI:
         print "Neither MINIDUMP_STACKWALK nor MINIDUMP_STACKWALK_CGI is set, can't process dump."
--- a/chrome/src/nsChromeRegistryChrome.cpp
+++ b/chrome/src/nsChromeRegistryChrome.cpp
@@ -452,28 +452,28 @@ EnumerateOverride(nsIURI* aURIKey,
     chromeURI, overrideURI
   };
   overrides->AppendElement(override);
   return (PLDHashOperator)PL_DHASH_NEXT;
 }
 
 struct EnumerationArgs
 {
-  nsTArray<ChromePackage>& packages;
+  InfallibleTArray<ChromePackage>& packages;
   const nsCString& selectedLocale;
   const nsCString& selectedSkin;
 };
 
 void
 nsChromeRegistryChrome::SendRegisteredChrome(
     mozilla::dom::PContentParent* aParent)
 {
-  nsTArray<ChromePackage> packages;
-  nsTArray<ResourceMapping> resources;
-  nsTArray<OverrideMapping> overrides;
+  InfallibleTArray<ChromePackage> packages;
+  InfallibleTArray<ResourceMapping> resources;
+  InfallibleTArray<OverrideMapping> overrides;
 
   EnumerationArgs args = {
     packages, mSelectedLocale, mSelectedSkin
   };
   PL_DHashTableEnumerate(&mPackagesHash, CollectPackages, &args);
 
   nsCOMPtr<nsIIOService> io (do_GetIOService());
   NS_ENSURE_TRUE(io, );
--- a/config/JarMaker.py
+++ b/config/JarMaker.py
@@ -39,16 +39,17 @@
 processing jar.mn files.
 
 See the documentation for jar.mn on MDC for further details on the format.
 '''
 
 import sys
 import os
 import os.path
+import errno
 import re
 import logging
 from time import localtime
 from optparse import OptionParser
 from MozZipFile import ZipFile
 from cStringIO import StringIO
 from datetime import datetime
 
@@ -440,17 +441,17 @@ class JarMaker(object):
     def getDestModTime(self, aPath):
       return getModTime(os.path.join(self.basepath, aPath))
     def getOutput(self, name):
       out = self.ensureDirFor(name)
       # remove previous link or file
       try:
         os.remove(out)
       except OSError, e:
-        if e.errno != 2:
+        if e.errno != errno.ENOENT:
           raise
       return open(out, 'wb')
     def ensureDirFor(self, name):
       out = os.path.join(self.basepath, name)
       outdir = os.path.dirname(out)
       if not os.path.isdir(outdir):
         os.makedirs(outdir)
       return out
@@ -460,17 +461,17 @@ class JarMaker(object):
     creating a symlink including creating the parent directories.
     '''
     def symlink(self, src, dest):
       out = self.ensureDirFor(dest)
       # remove previous link or file
       try:
         os.remove(out)
       except OSError, e:
-        if e.errno != 2:
+        if e.errno != errno.ENOENT:
           raise
       os.symlink(src, out)
 
 def main():
   jm = JarMaker()
   p = jm.getCommandLineParser()
   (options, args) = p.parse_args()
   jm.processIncludes(options.I)
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -127,16 +127,17 @@ export::
 		-DMOZ_TREE_CAIRO=$(MOZ_TREE_CAIRO) \
 		-DMOZ_ENABLE_LIBXUL=$(MOZ_ENABLE_LIBXUL) \
 		-DMOZ_NATIVE_HUNSPELL=$(MOZ_NATIVE_HUNSPELL) \
 		-DMOZ_NATIVE_BZ2=$(MOZ_NATIVE_BZ2) \
 		-DMOZ_NATIVE_ZLIB=$(MOZ_NATIVE_ZLIB) \
 		-DMOZ_NATIVE_PNG=$(MOZ_NATIVE_PNG) \
 		-DMOZ_NATIVE_JPEG=$(MOZ_NATIVE_JPEG) \
 		-DMOZ_NATIVE_LIBEVENT=$(MOZ_NATIVE_LIBEVENT) \
+		-DMOZ_NATIVE_LIBVPX=$(MOZ_NATIVE_LIBVPX) \
 		$(srcdir)/system-headers | $(PERL) $(topsrcdir)/nsprpub/config/make-system-wrappers.pl system_wrappers
 	$(INSTALL) system_wrappers $(DIST)
 
 GARBAGE_DIRS += system_wrappers
 endif
 
 ifdef WRAP_STL_INCLUDES
 ifdef GNU_CXX
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -96,17 +96,16 @@ MOZ_JS_LIBS		   = @MOZ_JS_LIBS@
 
 MOZ_DEBUG	= @MOZ_DEBUG@
 MOZ_DEBUG_SYMBOLS = @MOZ_DEBUG_SYMBOLS@
 MOZ_DEBUG_ENABLE_DEFS		= @MOZ_DEBUG_ENABLE_DEFS@
 MOZ_DEBUG_DISABLE_DEFS	= @MOZ_DEBUG_DISABLE_DEFS@
 MOZ_DEBUG_FLAGS	= @MOZ_DEBUG_FLAGS@
 MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@
 MOZ_EXTENSIONS  = @MOZ_EXTENSIONS@
-MOZ_IMG_ENCODERS= @MOZ_IMG_ENCODERS@
 MOZ_JSDEBUGGER  = @MOZ_JSDEBUGGER@
 MOZ_IPC 	= @MOZ_IPC@
 MOZ_IPDL_TESTS 	= @MOZ_IPDL_TESTS@
 MOZ_LEAKY	= @MOZ_LEAKY@
 MOZ_MEMORY      = @MOZ_MEMORY@
 MOZ_PROFILING   = @MOZ_PROFILING@
 MOZ_JPROF       = @MOZ_JPROF@
 MOZ_SHARK       = @MOZ_SHARK@
@@ -161,17 +160,21 @@ MOZ_RAW = @MOZ_RAW@
 MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@
 MOZ_WAVE = @MOZ_WAVE@
 MOZ_MEDIA = @MOZ_MEDIA@
 MOZ_VORBIS = @MOZ_VORBIS@
 MOZ_TREMOR = @MOZ_TREMOR@
 MOZ_WEBM = @MOZ_WEBM@
 VPX_AS = @VPX_AS@
 VPX_ASFLAGS = @VPX_ASFLAGS@
+VPX_DASH_C_FLAG = @VPX_DASH_C_FLAG@
+VPX_AS_CONVERSION = @VPX_AS_CONVERSION@
+VPX_ASM_SUFFIX = @VPX_ASM_SUFFIX@
 VPX_X86_ASM = @VPX_X86_ASM@
+VPX_ARM_ASM = @VPX_ARM_ASM@
 NS_PRINTING = @NS_PRINTING@
 MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
 MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
 MOC= @MOC@
 MOZ_NSS_PATCH = @MOZ_NSS_PATCH@
 MOZ_WEBGL = @MOZ_WEBGL@
 
 MOZ_JAVAXPCOM = @MOZ_JAVAXPCOM@
@@ -227,16 +230,20 @@ MOZ_AUTH_EXTENSION = @MOZ_AUTH_EXTENSION
 MOZ_NATIVE_HUNSPELL = @SYSTEM_HUNSPELL@
 MOZ_HUNSPELL_LIBS = @MOZ_HUNSPELL_LIBS@
 MOZ_HUNSPELL_CFLAGS = @MOZ_HUNSPELL_CFLAGS@
 
 MOZ_NATIVE_LIBEVENT = @MOZ_NATIVE_LIBEVENT@
 MOZ_LIBEVENT_LIBS = @MOZ_LIBEVENT_LIBS@
 MOZ_LIBEVENT_INCLUDES = @MOZ_LIBEVENT_INCLUDES@
 
+MOZ_NATIVE_LIBVPX = @MOZ_NATIVE_LIBVPX@
+MOZ_LIBVPX_LIBS = @MOZ_LIBVPX_LIBS@
+MOZ_LIBVPX_INCLUDES = @MOZ_LIBVPX_INCLUDES@
+
 MOZ_NATIVE_ZLIB	= @SYSTEM_ZLIB@
 MOZ_NATIVE_BZ2	= @SYSTEM_BZ2@
 MOZ_NATIVE_JPEG	= @SYSTEM_JPEG@
 MOZ_NATIVE_PNG	= @SYSTEM_PNG@
 MOZ_TREE_CAIRO = @MOZ_TREE_CAIRO@
 MOZ_TREE_PIXMAN = @MOZ_TREE_PIXMAN@
 
 MOZ_UPDATE_XTERM = @MOZ_UPDATE_XTERM@
@@ -600,17 +607,16 @@ OS_TEST=@OS_TEST@
 SOLARIS_SUNPRO_CC = @SOLARIS_SUNPRO_CC@
 SOLARIS_SUNPRO_CXX = @SOLARIS_SUNPRO_CXX@
 
 # For AIX build
 AIX_OBJMODEL = @AIX_OBJMODEL@
 
 # For OS/2 build
 MOZ_OS2_TOOLS = @MOZ_OS2_TOOLS@
-MOZ_OS2_USE_DECLSPEC = @MOZ_OS2_USE_DECLSPEC@
 MOZ_OS2_HIGH_MEMORY = @MOZ_OS2_HIGH_MEMORY@
 
 HAVE_XIE=@HAVE_XIE@
 
 MOZ_PSM=@MOZ_PSM@
 
 # Gssapi (krb5) libraries and headers for the Negotiate auth method
 GSSAPI_INCLUDES = @GSSAPI_INCLUDES@
--- a/config/config.mk
+++ b/config/config.mk
@@ -229,17 +229,17 @@ OS_LDFLAGS += -OPT:NOICF
 endif
 
 #
 # Handle trace-malloc in optimized builds.
 # No opt to give sane callstacks.
 #
 ifdef NS_TRACE_MALLOC
 MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG
-OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF -OPT:nowin98
+OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF
 endif # NS_TRACE_MALLOC
 
 endif # MOZ_DEBUG
 endif # WINNT && !GNU_CC
 
 #
 # Build using PIC by default
 # Do not use PIC if not building a shared lib (see exceptions below)
--- a/config/nsStaticComponents.cpp.in
+++ b/config/nsStaticComponents.cpp.in
@@ -54,20 +54,18 @@
 
 %MODULE_LIST%
 #line 57 "nsStaticComponents.cpp.in"
 
 #undef MODULE
 
 
 #define MODULE(_name) \
-    NSMODULE_NAME(_name),
+    &NSMODULE_NAME(_name),
 
 /**
  * The nsStaticModuleInfo
  */
-static const mozilla::Module *const kStaticModules[] = {
+const mozilla::Module *const *const kPStaticModules[] = {
 	%MODULE_LIST%
 #line 70 "nsStaticComponents.cpp.in"
         NULL
 };
-
-mozilla::Module const *const *const kPStaticModules = kStaticModules;
--- a/config/nsStaticComponents.h
+++ b/config/nsStaticComponents.h
@@ -38,11 +38,11 @@
 #ifndef nsStaticComponents_h__
 #define nsStaticComponents_h__
 
 #include "mozilla/Module.h"
 
 // These symbols are provided by nsStaticComponents.cpp, and also by other
 // static component providers such as nsStaticXULComponents (libxul).
 
-extern mozilla::Module const *const *const kPStaticModules;
+extern mozilla::Module const *const *const kPStaticModules[];
 
 #endif
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1244,36 +1244,20 @@ endif
 ifeq ($(OS_ARCH),OS2)
 $(DEF_FILE): $(OBJS) $(SHARED_LIBRARY_LIBS)
 	rm -f $@
 	echo LIBRARY $(SHARED_LIBRARY_NAME) INITINSTANCE TERMINSTANCE > $@
 	echo PROTMODE >> $@
 	echo CODE    LOADONCALL MOVEABLE DISCARDABLE >> $@
 	echo DATA    PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@
 	echo EXPORTS >> $@
-ifeq ($(IS_COMPONENT),1)
-ifeq ($(HAS_EXTRAEXPORTS),1)
-ifndef MOZ_OS2_USE_DECLSPEC
-	$(FILTER) $(OBJS) $(SHARED_LIBRARY_LIBS) >> $@
-endif	
-else
-	echo    _NSModule >> $@
-endif
-else
-ifndef MOZ_OS2_USE_DECLSPEC
-	$(FILTER) $(OBJS) $(SHARED_LIBRARY_LIBS) >> $@
-endif	
-endif
+
 	$(ADD_TO_DEF_FILE)
 
-ifdef MOZ_OS2_USE_DECLSPEC
 $(IMPORT_LIBRARY): $(SHARED_LIBRARY)
-else
-$(IMPORT_LIBRARY): $(DEF_FILE)
-endif
 	rm -f $@
 	$(IMPLIB) $@ $^
 	$(RANLIB) $@
 endif # OS/2
 
 $(HOST_LIBRARY): $(HOST_OBJS) Makefile
 	rm -f $@
 	$(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
--- a/config/system-headers
+++ b/config/system-headers
@@ -1046,8 +1046,12 @@ proxy.h
 contentaction/contentaction.h
 #endif
 #ifndef MOZ_TREE_PIXMAN
 pixman.h
 #endif
 #if MOZ_ENABLE_MEEGOTOUCHSHARE
 shareuiinterface.h
 #endif
+#if MOZ_NATIVE_LIBVPX==1
+vpx/vpx_decoder.h
+vpx/vp8dx.h
+#endif
--- a/configure.in
+++ b/configure.in
@@ -987,17 +987,17 @@ AC_MSG_CHECKING([for full perl installat
 _perl_res=$?
 if test "$_perl_res" != 0; then
     AC_MSG_RESULT([no])
     AC_MSG_ERROR([Cannot find Config.pm or \$Config{archlib}.  A full perl installation is required.])
 else
     AC_MSG_RESULT([yes])    
 fi
 
-MOZ_PATH_PROGS(PYTHON, $PYTHON python2.6 python2.5 python2.4 python)
+MOZ_PATH_PROGS(PYTHON, $PYTHON python2.7 python2.6 python2.5 python)
 if test -z "$PYTHON"; then
     AC_MSG_ERROR([python was not found in \$PATH])
 fi
 
 if test -z "$COMPILE_ENVIRONMENT"; then
     NSINSTALL_BIN='$(PYTHON) $(topsrcdir)/config/nsinstall.py'
 fi
 AC_SUBST(NSINSTALL_BIN)
@@ -1841,18 +1841,16 @@ dnl ====================================
 case "$host" in
 *-beos*)
     HOST_CFLAGS="$HOST_CFLAGS -DXP_BEOS -DBeOS -DBEOS -D_POSIX_SOURCE -DNO_X11"
     HOST_NSPR_MDCPUCFG='\"md/_beos.cfg\"'
     HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}"
     ;;
 
 *cygwin*|*mingw*|*mks*|*msvc*|*wince|*winmo)
-    # we need Python 2.5 on Windows
-    PYTHON_VERSION=2.5
     if test -n "$_WIN32_MSVC"; then
         HOST_AR=lib
         HOST_AR_FLAGS='-NOLOGO -OUT:"$@"'
         HOST_CFLAGS="$HOST_CFLAGS -TC -nologo -Fd\$(HOST_PDBFILE)"
         HOST_RANLIB='echo ranlib'
     else
         HOST_CFLAGS="$HOST_CFLAGS -mno-cygwin"
     fi
@@ -1916,18 +1914,17 @@ case "$host" in
     ;;
 
 *)
     HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX"
     HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}"
     ;;
 esac
 
-dnl We require version 2.4 or newer of Python to build,
-dnl and 2.5 or newer on Windows.
+dnl We require version 2.5 or newer of Python to build.
 AC_MSG_CHECKING([for minimum required Python version >= $PYTHON_VERSION])
 changequote(,)
 $PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1])" $PYTHON_VERSION
 _python_res=$?
 changequote([,])
 if test "$_python_res" != 0; then
     AC_MSG_ERROR([Python $PYTHON_VERSION or higher is required.])
 fi
@@ -2640,17 +2637,17 @@ ia64*-hpux*)
     DSO_PIC_CFLAGS=
     AR=emxomfar
     AR_FLAGS='r $@'
     CFLAGS="$CFLAGS -Zomf"
     CXXFLAGS="$CXXFLAGS -Zomf"
     DSO_LDOPTS='-Zdll'
     BIN_FLAGS='-Zlinker /ST:0x100000'
     IMPLIB='emximp -o'
-    FILTER='emxexp -o'
+    FILTER='true'
     LDFLAGS='-Zmap'
     WARNINGS_AS_ERRORS='-Werror'
     MOZ_DEBUG_FLAGS="-g -fno-inline"
     MOZ_OPTIMIZE_FLAGS="-O2"
     MOZ_OPTIMIZE_LDFLAGS="-s -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA"
     DYNAMIC_XPCOM_LIBS='-L$(LIBXUL_DIST)/lib $(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
     LIBXUL_LIBS='-L$(LIBXUL_DIST)/lib $(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
     TARGET_MD_ARCH=os2
@@ -2676,19 +2673,18 @@ ia64*-hpux*)
     _DEFINES_CXXFLAGS="$_DEFINES_CXXFLAGS -Uunix -U__unix -U__unix__"
 
     AC_CACHE_CHECK(for __declspec(dllexport),
         ac_os2_declspec,
         [AC_TRY_COMPILE([__declspec(dllexport) void ac_os2_declspec(void) {}],
                         [return 0;],
                         ac_os2_declspec="yes",
                         ac_os2_declspec="no")])
-    if test "$ac_os2_declspec" = "yes"; then
-        FILTER='true'
-        MOZ_OS2_USE_DECLSPEC='1'
+    if test "$ac_os2_declspec" != "yes"; then
+        AC_MSG_ERROR([Compiler does not support __declspec(dllexport), install GCC-4.3.2 or newer])
     fi
     ;;
 
 alpha*-*-osf*)
     if test "$GNU_CC"; then
       MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$@ -o $@'
       MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$@ -o $@'
 
@@ -3403,21 +3399,19 @@ dnl against libSystem causes issues when
 case $target in
 *-darwin*)
     ;;
 *-beos*)
     ;;
 *-os2*)
     ;;
 *)
-    AC_CHECK_LIB(m, atan)
-    AC_CHECK_LIB(dl, dlopen,
-    AC_CHECK_HEADER(dlfcn.h, 
-        LIBS="-ldl $LIBS"
-        AC_DEFINE(HAVE_LIBDL)))
+    AC_SEARCH_LIBS(dlopen, dl, 
+        AC_CHECK_HEADER(dlfcn.h, 
+        AC_DEFINE(HAVE_DLOPEN)))
     ;;
 esac
 
 _SAVE_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -D_GNU_SOURCE"
 AC_CHECK_FUNCS(dladdr)
 CFLAGS="$_SAVE_CFLAGS"
 
@@ -4723,20 +4717,20 @@ dnl Detect yasm
 dnl ======================
 
 AC_MSG_CHECKING([for YASM assembler])
 AC_CHECK_PROGS(YASM, yasm, "")
 
 if test -n "$YASM"; then
   dnl Pull out yasm's version string
   changequote(,)
-  _YASM_VER_FILTER='s|.* ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*|\1|p'
+  _YASM_VER_FILTER='s|.* \([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\).*|\1|p'
   changequote([,])
 
-  YASM_VERSION=`yasm --version | sed -nre "$_YASM_VER_FILTER"`
+  YASM_VERSION=`yasm --version | sed -ne "$_YASM_VER_FILTER"`
   _YASM_MAJOR_VERSION=`echo ${YASM_VERSION} | $AWK -F\. '{ print $1 }'`
   _YASM_MINOR_VERSION=`echo ${YASM_VERSION} | $AWK -F\. '{ print $2 }'`
   _YASM_RELEASE=`      echo ${YASM_VERSION} | $AWK -F\. '{ print $3 }'`
   _YASM_BUILD=`        echo ${YASM_VERSION} | $AWK -F\. '{ print $4 }'`
 fi
 
 if test -z "$SKIP_LIBRARY_CHECKS"; then
 dnl system JPEG support
@@ -4937,17 +4931,16 @@ dnl ====================================
 MOZ_ARG_HEADER(Application)
 
 BUILD_STATIC_LIBS=
 ENABLE_TESTS=1
 MOZ_ACTIVEX_SCRIPTING_SUPPORT=
 MOZ_BRANDING_DIRECTORY=
 MOZ_OFFICIAL_BRANDING=
 MOZ_FEEDS=1
-MOZ_IMG_ENCODERS_DEFAULT="png jpeg"
 MOZ_INSTALLER=1
 MOZ_IPC=1
 MOZ_JAVAXPCOM=
 MOZ_JSDEBUGGER=1
 MOZ_JSLOADER=1
 MOZ_MATHML=1
 MOZ_MORK=
 MOZ_MORKREADER=1
@@ -4959,17 +4952,21 @@ MOZ_RAW=
 MOZ_SYDNEYAUDIO=
 MOZ_VORBIS=
 MOZ_TREMOR=
 MOZ_WAVE=1
 MOZ_MEDIA=
 MOZ_WEBM=1
 VPX_AS=
 VPX_ASFLAGS=
+VPX_AS_DASH_C_FLAG=
+VPX_AS_CONVERSION=
+VPX_ASM_SUFFIX=
 VPX_X86_ASM=
+VPX_ARM_ASM=
 MOZ_PANGO=1
 MOZ_PERMISSIONS=1
 MOZ_PLACES=1
 MOZ_PLAINTEXT_EDITOR_ONLY=
 MOZ_PLUGINS=1
 MOZ_PREF_EXTENSIONS=1
 MOZ_PROFILELOCKING=1
 MOZ_PSM=1
@@ -5989,33 +5986,77 @@ fi
 dnl ========================================================
 dnl = Disable VP8 decoder support
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(webm,
 [  --disable-webm          Disable support for WebM media (VP8 video and Vorbis audio)],
     MOZ_WEBM=,
     MOZ_WEBM=1)
 
+dnl system libvpx Support
+dnl ========================================================
+MOZ_ARG_WITH_STRING(system-libvpx,
+[  --with-system-libvpx=[PFX]
+                          Use system libvpx [installed at prefix PFX]],
+    LIBVPX_DIR=$withval)
+
+MOZ_NATIVE_LIBVPX=
+MOZ_LIBVPX_INCLUDES=
+MOZ_LIBVPX_LIBS=
+
 if test -n "$MOZ_WEBM"; then
     AC_DEFINE(MOZ_WEBM)
+
+    if test -n "$LIBVPX_DIR" -a "$LIBVPX_DIR" != no; then
+        _SAVE_CFLAGS=$CFLAGS
+        _SAVE_LDFLAGS=$LDFLAGS
+        _SAVE_LIBS=$LIBS
+        if test "${LIBVPX_DIR}" = "yes"; then
+            LIBVPX_DIR=/usr
+        fi
+        CFLAGS="-I${LIBVPX_DIR}/include $CFLAGS"
+        LDFLAGS="-L${LIBVPX_DIR}/lib $LDFLAGS"
+        AC_CHECK_HEADER(vpx/vpx_decoder.h,
+                        [if test ! -f "${LIBVPX_DIR}/include/vpx/vpx_decoder.h"; then
+                             AC_MSG_ERROR([vpx/vpx_decoder.h found, but is not in ${LIBVPX_DIR}/include])
+                         fi],
+                        AC_MSG_ERROR([--with-system-libvpx requested but vpx/vpx_decoder.h not found]))
+        AC_CHECK_LIB(vpx, vpx_codec_dec_init_ver,
+                     [MOZ_NATIVE_LIBVPX=1
+                      MOZ_LIBVPX_INCLUDES="-I${LIBVPX_DIR}/include"
+                      MOZ_LIBVPX_LIBS="-L${LIBVPX_DIR}/lib -lvpx"],
+                     ([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found]))
+        CFLAGS=$_SAVE_CFLAGS
+        LDFLAGS=$_SAVE_LDFLAGS
+        LIBS=$_SAVE_LIBS
+    fi
+fi
+
+AC_SUBST(MOZ_NATIVE_LIBVPX)
+AC_SUBST(MOZ_LIBVPX_INCLUDES)
+AC_SUBST(MOZ_LIBVPX_LIBS)
+
+if test -n "$MOZ_WEBM" -a -z "$MOZ_NATIVE_LIBVPX"; then
     MOZ_SYDNEYAUDIO=1
     MOZ_MEDIA=1
     case "$target_cpu" in
     arm*)
         MOZ_TREMOR=1
     ;;
     *)
         MOZ_VORBIS=1
     ;;
     esac
 
 
     dnl Detect if we can use an assembler to compile optimized assembly for libvpx.
-    dnl We currently require yasm on all platforms and require yasm 1.1.0 on Win32.
+    dnl We currently require yasm on all x86 platforms and require yasm 1.1.0 on Win32.
+    dnl We currently require gcc on all arm platforms.
     VPX_AS=$YASM
+    VPX_ASM_SUFFIX=asm
 
     dnl See if we have assembly on this platform.  
     case "$OS_ARCH:$CPU_ARCH" in
     Linux:x86)
       VPX_ASFLAGS="-f elf32 -rnasm -pnasm"
       VPX_X86_ASM=1
     ;;
     Linux:x86_64)
@@ -6052,24 +6093,37 @@ if test -n "$MOZ_WEBM"; then
         elif test -n "$COMPILE_ENVIRONMENT" -a "$_YASM_MAJOR_VERSION" -lt "1" -o \( "$_YASM_MAJOR_VERSION" -eq "1" -a "$_YASM_MINOR_VERSION" -lt "1" \) ; then
           AC_MSG_ERROR([yasm 1.1 or greater is required to build libvpx on Win32, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION.  Upgrade to the newest version (included in MozillaBuild 1.5.1 and newer) or configure with --disable-webm (which disables the WebM video format). See https://developer.mozilla.org/en/YASM for more details.])
         else
           VPX_ASFLAGS="-f win32 -rnasm -pnasm -DPIC"
           VPX_X86_ASM=1
         fi
       fi
     ;;
+    *:arm*)
+      if test -n "$GNU_AS" ; then
+        VPX_AS=$AS
+        dnl These flags are a lie; they're just used to enable the requisite
+        dnl opcodes; actual arch detection is done at runtime.
+        VPX_ASFLAGS="-march=armv7-a -mfpu=neon"
+        VPX_DASH_C_FLAG="-c"
+        VPX_AS_CONVERSION="$PERL ${srcdir}/media/libvpx/build/make/ads2gas.pl"
+        VPX_ASM_SUFFIX="$ASM_SUFFIX"
+        VPX_ARM_ASM=1
+      fi
     esac
 
     if test -n "$COMPILE_ENVIRONMENT" -a -n "$VPX_X86_ASM" -a -z "$VPX_AS"; then
       AC_MSG_ERROR([yasm is a required build tool for this architecture when webm is enabled. You may either install yasm or --disable-webm (which disables the WebM video format). See https://developer.mozilla.org/en/YASM for more details.])
     fi
 
     if test -n "$VPX_X86_ASM"; then
       AC_DEFINE(VPX_X86_ASM)
+    elif test -n "$VPX_ARM_ASM"; then
+      AC_DEFINE(VPX_ARM_ASM)
     else
       AC_MSG_WARN([No assembler or assembly support for libvpx. Using unoptimized C routines.])
     fi
 fi
 
 dnl ========================================================
 dnl = Disable Wave decoder support
 dnl ========================================================
@@ -6362,25 +6416,21 @@ if test `echo "$MOZ_EXTENSIONS" | grep -
 fi
 
 dnl cookie must be built before tridentprofile. put it at list's end.
 if test `echo "$MOZ_EXTENSIONS" | grep -c tridentprofile` -ne 0; then
   MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|tridentprofile||'`
   MOZ_EXTENSIONS="$MOZ_EXTENSIONS tridentprofile"
 fi
 
-dnl xforms requires xtf and schema-validation
+dnl xforms requires xtf
 if test -z "$MOZ_XTF" -a `echo "$MOZ_EXTENSIONS" | grep -c xforms` -ne 0; then
     AC_MSG_WARN([Cannot build XForms without XTF support.  Removing XForms from MOZ_EXTENSIONS.])
     MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|xforms||g'`
 fi
-if test `echo "$MOZ_EXTENSIONS" | grep -c xforms` -ne 0 && test `echo "$MOZ_EXTENSIONS" | grep -c schema-validation` -eq 0; then
-    AC_MSG_WARN([Cannot build XForms without schema validation.  Removing XForms from MOZ_EXTENSIONS.])
-    MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|xforms||g'`
-fi
 
 if test `echo "$MOZ_EXTENSIONS" | grep -c auth` -ne 0; then
     AC_MSG_WARN([auth is no longer an extension, use --disable-negotiateauth to disable.])
     MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|auth||g'`
 fi
 
 if test `echo "$MOZ_EXTENSIONS" | grep -c 'cookie\|permissions'` -ne 0; then
     AC_MSG_WARN([cookie and permissions are no longer extensions, use --disable-permissions to disable.])
@@ -6414,43 +6464,16 @@ dnl Ensure every extension exists, to av
 dnl when trying to build a nonexistent extension.
 for extension in $MOZ_EXTENSIONS; do
     if test ! -d "${srcdir}/extensions/${extension}"; then
         AC_MSG_ERROR([Unrecognized extension provided to --enable-extensions: ${extension}.])
     fi
 done
 
 dnl ========================================================
-dnl Image encoders
-dnl ========================================================
-MOZ_ARG_ENABLE_STRING(image-encoders,
-[  --enable-image-encoders[={mod1,mod2,default,all,none}]
-                          Enable specific image encoders],
-[ for option in `echo $enableval | sed 's/,/ /g'`; do
-    if test "$option" = "yes" -o "$option" = "all"; then
-        addencoder="$MOZ_IMG_ENCODERS_DEFAULT"
-    elif test "$option" = "no" -o "$option" = "none"; then
-        MOZ_IMG_ENCODERS=""
-        addencoder=""
-    elif test "$option" = "default"; then
-        addencoder="$MOZ_IMG_ENCODERS_DEFAULT"
-    elif test `echo "$option" | grep -c \^-` != 0; then
-        option=`echo $option | sed 's/^-//'`
-        addencoder=`echo "$MOZ_IMG_ENCODERS" | sed "s/ ${option}//"`
-    else
-        addencoder="$option"
-    fi
-    MOZ_IMG_ENCODERS="$MOZ_IMG_ENCODERS $addencoder"
-done],
-    MOZ_IMG_ENCODERS="$MOZ_IMG_ENCODERS_DEFAULT")
-
-dnl Remove dupes
-MOZ_IMG_ENCODERS=`${PERL} ${srcdir}/build/unix/uniq.pl ${MOZ_IMG_ENCODERS}`
-
-dnl ========================================================
 dnl MathML on by default
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(mathml,
 [  --disable-mathml        Disable MathML support],
     MOZ_MATHML=,
     MOZ_MATHML=1 )
 if test "$MOZ_MATHML"; then
   AC_DEFINE(MOZ_MATHML)
@@ -8568,17 +8591,17 @@ if test "$MOZ_TREE_CAIRO"; then
     AC_SUBST(PNG_FUNCTIONS_FEATURE)
     AC_SUBST(QT_SURFACE_FEATURE)
 
     MOZ_CAIRO_LIBS='$(call EXPAND_LIBNAME_PATH,mozcairo,$(DEPTH)/gfx/cairo/cairo/src)'" $CAIRO_FT_LIBS"
 
     if test "$MOZ_TREE_PIXMAN"; then
         MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS"' $(call EXPAND_LIBNAME_PATH,mozlibpixman,$(DEPTH)/gfx/cairo/libpixman/src)'
     else
-        PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.17.3)
+        PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.19.2)
         MOZ_CAIRO_CFLAGS="$MOZ_CAIRO_CFLAGS $PIXMAN_CFLAGS"
         MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $PIXMAN_LIBS"
     fi
 
     if test "$MOZ_X11"; then
         MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $XLDFLAGS -lXrender -lfreetype -lfontconfig"
     fi
 
@@ -8843,17 +8866,16 @@ AC_SUBST(MOZ_PSM)
 AC_SUBST(MOZ_DEBUG)
 AC_SUBST(MOZ_DEBUG_SYMBOLS)
 AC_SUBST(MOZ_DEBUG_ENABLE_DEFS)
 AC_SUBST(MOZ_DEBUG_DISABLE_DEFS)
 AC_SUBST(MOZ_DEBUG_FLAGS)
 AC_SUBST(MOZ_DEBUG_LDFLAGS)
 AC_SUBST(WARNINGS_AS_ERRORS)
 AC_SUBST(MOZ_EXTENSIONS)
-AC_SUBST(MOZ_IMG_ENCODERS)
 AC_SUBST(MOZ_JSDEBUGGER)
 AC_SUBST(MOZ_PLUGINS)
 AC_SUBST(MOZ_LOG_REFCNT)
 AC_SUBST(MOZ_LEAKY)
 AC_SUBST(MOZ_JPROF)
 AC_SUBST(MOZ_SHARK)
 AC_SUBST(MOZ_CALLGRIND)
 AC_SUBST(MOZ_VTUNE)
@@ -8906,17 +8928,16 @@ AC_SUBST(XPCOM_LIBS)
 AC_SUBST(XPCOM_FROZEN_LDOPTS)
 AC_SUBST(XPCOM_GLUE_LDOPTS)
 AC_SUBST(XPCOM_STANDALONE_GLUE_LDOPTS)
 
 AC_SUBST(USE_DEPENDENT_LIBS)
 
 AC_SUBST(MOZ_BUILD_ROOT)
 AC_SUBST(MOZ_OS2_TOOLS)
-AC_SUBST(MOZ_OS2_USE_DECLSPEC)
 
 AC_SUBST(MOZ_POST_DSO_LIB_COMMAND)
 AC_SUBST(MOZ_POST_PROGRAM_COMMAND)
 AC_SUBST(MOZ_TIMELINE)
 AC_SUBST(OGLES_SDK_DIR)
 
 AC_SUBST(MOZ_APP_NAME)
 AC_SUBST(MOZ_APP_DISPLAYNAME)
@@ -9073,17 +9094,21 @@ AC_SUBST(MOZ_SYDNEYAUDIO)
 AC_SUBST(MOZ_WAVE)
 AC_SUBST(MOZ_VORBIS)
 AC_SUBST(MOZ_TREMOR)
 AC_SUBST(MOZ_WEBM)
 AC_SUBST(MOZ_OGG)
 AC_SUBST(MOZ_ALSA_LIBS)
 AC_SUBST(VPX_AS)
 AC_SUBST(VPX_ASFLAGS)
+AC_SUBST(VPX_DASH_C_FLAG)
+AC_SUBST(VPX_AS_CONVERSION)
+AC_SUBST(VPX_ASM_SUFFIX)
 AC_SUBST(VPX_X86_ASM)
+AC_SUBST(VPX_ARM_ASM)
 
 if test "$USING_HCC"; then
    CC='${topsrcdir}/build/hcc'
    CC="$CC '$_OLDCC'"
    CXX='${topsrcdir}/build/hcpp'
    CXX="$CXX '$_OLDCXX'"
    AC_SUBST(CC)
    AC_SUBST(CXX)
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1695,16 +1695,24 @@ public:
    * A sub document isn't tabbable when it's a zombie document.
    *
    * @param aElement element to test.
    *
    * @return Whether the subdocument is tabbable.
    */
   static bool IsSubDocumentTabbable(nsIContent* aContent);
 
+  /**
+   * Flushes the layout tree (recursively)
+   *
+   * @param aWindow the window the flush should start at
+   *
+   */
+  static void FlushLayoutForTree(nsIDOMWindow* aWindow);
+
 private:
 
   static PRBool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
 
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -116,18 +116,18 @@ class Loader;
 namespace dom {
 class Link;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 
 #define NS_IDOCUMENT_IID      \
-{ 0x7fb1e97d, 0xbd2c, 0x47cf, \
-  { 0xa3, 0x05, 0x5b, 0x31, 0xd4, 0x1d, 0x3a, 0x52 } }
+{ 0xc38a7935, 0xc854, 0x4df7, \
+  { 0x8f, 0xd4, 0xa2, 0x6f, 0x0d, 0x27, 0x9f, 0x31 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Document states
 
 // RTL locale: specific to the XUL localedir attribute
 #define NS_DOCUMENT_STATE_RTL_LOCALE              NS_DEFINE_EVENT_STATE_MACRO(0)
@@ -1275,16 +1275,21 @@ public:
   PRBool HasAnimationController()  { return !!mAnimationController; }
 
   // Getter for this document's SMIL Animation Controller. Performs lazy
   // initialization, if this document supports animation and if
   // mAnimationController isn't yet initialized.
   virtual nsSMILAnimationController* GetAnimationController() = 0;
 #endif // MOZ_SMIL
 
+  // Makes the images on this document capable of having their animation
+  // active or suspended. An Image will animate as long as at least one of its
+  // owning Documents needs it to animate; otherwise it can suspend.
+  virtual void SetImagesNeedAnimating(PRBool aAnimating) = 0;
+
   /**
    * Prevents user initiated events from being dispatched to the document and
    * subdocuments.
    */
   virtual void SuppressEventHandling(PRUint32 aIncrease = 1) = 0;
 
   /**
    * Unsuppress event handling.
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -733,17 +733,17 @@ public:
    * observer that is already observing the node must not be added without
    * being removed first.
    */
   void AddMutationObserver(nsIMutationObserver* aMutationObserver)
   {
     nsSlots* s = GetSlots();
     if (s) {
       NS_ASSERTION(s->mMutationObservers.IndexOf(aMutationObserver) ==
-                   nsTArray_base::NoIndex,
+                   nsTArray<int>::NoIndex,
                    "Observer already in the list");
       s->mMutationObservers.AppendElement(aMutationObserver);
     }
   }
 
   /**
    * Same as above, but only adds the observer if its not observing
    * the node already.
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -80,47 +80,44 @@ var gPrefObserver = {
       this._debugEnabled = this._branch.getBoolPref("debug");
   },
 
 };
 
 
 function CSPWarning(aMsg) {
   var textMessage = 'CSP WARN:  ' + aMsg + "\n";
-  dump(textMessage);
 
   var consoleMsg = Components.classes["@mozilla.org/scripterror;1"]
                     .createInstance(Components.interfaces.nsIScriptError);
   consoleMsg.init('CSP: ' + aMsg, null, null, 0, 0,
                   Components.interfaces.nsIScriptError.warningFlag,
                   "Content Security Policy");
   Components.classes["@mozilla.org/consoleservice;1"]
                     .getService(Components.interfaces.nsIConsoleService)
                     .logMessage(consoleMsg);
 }
 
 function CSPError(aMsg) {
   var textMessage = 'CSP ERROR:  ' + aMsg + "\n";
-  dump(textMessage);
 
   var consoleMsg = Components.classes["@mozilla.org/scripterror;1"]
                     .createInstance(Components.interfaces.nsIScriptError);
   consoleMsg.init('CSP: ' + aMsg, null, null, 0, 0,
                   Components.interfaces.nsIScriptError.errorFlag,
                   "Content Security Policy");
   Components.classes["@mozilla.org/consoleservice;1"]
                     .getService(Components.interfaces.nsIConsoleService)
                     .logMessage(consoleMsg);
 }
 
 function CSPdebug(aMsg) {
   if (!gPrefObserver.debugEnabled) return;
 
   aMsg = 'CSP debug: ' + aMsg + "\n";
-  dump(aMsg);
   Components.classes["@mozilla.org/consoleservice;1"]
                     .getService(Components.interfaces.nsIConsoleService)
                     .logStringMessage(aMsg);
 }
 
 //:::::::::::::::::::::::: CLASSES ::::::::::::::::::::::::::// 
 
 /**
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -53,18 +53,19 @@
 #include "nsCOMPtr.h"
 
 typedef PRUptrdiff PtrBits;
 class nsAString;
 class nsIAtom;
 class nsICSSStyleRule;
 class nsISVGValue;
 class nsIDocument;
-template<class E> class nsTArray;
-template<class E> class nsTPtrArray;
+template<class E, class A> class nsTArray;
+template<class E, class A> class nsTPtrArray;
+struct nsTArrayDefaultAllocator;
 
 #define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12
 
 #define NS_ATTRVALUE_BASETYPE_MASK (PtrBits(3))
 #define NS_ATTRVALUE_POINTERVALUE_MASK (~NS_ATTRVALUE_BASETYPE_MASK)
 
 #define NS_ATTRVALUE_INTEGERTYPE_BITS 4
 #define NS_ATTRVALUE_INTEGERTYPE_MASK (PtrBits((1 << NS_ATTRVALUE_INTEGERTYPE_BITS) - 1))
@@ -376,17 +377,17 @@ private:
   // aStrict is set PR_TRUE if stringifying the return value equals with
   // aValue.
   PRInt32 StringToInteger(const nsAString& aValue,
                           PRBool* aStrict,
                           PRInt32* aErrorCode,
                           PRBool aCanBePercent = PR_FALSE,
                           PRBool* aIsPercent = nsnull) const;
 
-  static nsTPtrArray<const EnumTable>* sEnumTableArray;
+  static nsTPtrArray<const EnumTable, nsTArrayDefaultAllocator>* sEnumTableArray;
 
   PtrBits mBits;
 };
 
 /**
  * Implementation of inline methods
  */
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4798,18 +4798,22 @@ static void ProcessViewportToken(nsIDocu
   while ((tip != end) && (*tip != '='))
     ++tip;
 
   /* If we didn't find an '=', punt. */
   if (tip == end)
     return;
 
   /* Extract the key and value. */
-  const nsAString &key = Substring(tail, tip);
-  const nsAString &value = Substring(++tip, end);
+  const nsAString &key =
+    nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(tail, tip),
+                                                        PR_TRUE);
+  const nsAString &value =
+    nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(++tip, end),
+                                                        PR_TRUE);
 
   /* Check for known keys. If we find a match, insert the appropriate
    * information into the document header. */
   nsCOMPtr<nsIAtom> key_atom = do_GetAtom(key);
   if (key_atom == nsGkAtoms::height)
     aDocument->SetHeaderData(nsGkAtoms::viewport_height, value);
   else if (key_atom == nsGkAtoms::width)
     aDocument->SetHeaderData(nsGkAtoms::viewport_width, value);
@@ -4818,50 +4822,63 @@ static void ProcessViewportToken(nsIDocu
   else if (key_atom == nsGkAtoms::minimum_scale)
     aDocument->SetHeaderData(nsGkAtoms::viewport_minimum_scale, value);
   else if (key_atom == nsGkAtoms::maximum_scale)
     aDocument->SetHeaderData(nsGkAtoms::viewport_maximum_scale, value);
   else if (key_atom == nsGkAtoms::user_scalable)
     aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value);
 }
 
-#define IS_SEPARATOR(c) ((c == ' ') || (c == ',') || (c == ';'))
+#define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
+                         (c == '\t') || (c == '\n') || (c == '\r'))
+
 /* static */
 nsresult
 nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,
                                     const nsAString &viewportInfo) {
 
   /* We never fail. */
   nsresult rv = NS_OK;
 
   /* Iterators. */
   nsAString::const_iterator tip, tail, end;
   viewportInfo.BeginReading(tip);
   tail = tip;
   viewportInfo.EndReading(end);
 
   /* Read the tip to the first non-separator character. */
-  while ((tip != end) && IS_SEPARATOR(*tip))
+  while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
     ++tip;
 
   /* Read through and find tokens separated by separators. */
   while (tip != end) {
-    
+
     /* Synchronize tip and tail. */
     tail = tip;
 
     /* Advance tip past non-separator characters. */
     while ((tip != end) && !IS_SEPARATOR(*tip))
       ++tip;
 
+    /* Allow white spaces that surround the '=' character */
+    if ((tip != end) && (*tip == '=')) {
+      ++tip;
+
+      while ((tip != end) && nsCRT::IsAsciiSpace(*tip))
+        ++tip;
+
+      while ((tip != end) && !(IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
+        ++tip;
+    }
+
     /* Our token consists of the characters between tail and tip. */
     ProcessViewportToken(aDocument, Substring(tail, tip));
 
     /* Skip separators. */
-    while ((tip != end) && IS_SEPARATOR(*tip))
+    while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
       ++tip;
   }
 
   return rv;
 
 }
 
 #undef IS_SEPARATOR
@@ -6281,16 +6298,50 @@ nsContentUtils::IsSubDocumentTabbable(ns
   contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
 
   // If there are 2 viewers for the current docshell, that
   // means the current document is a zombie document.
   // Only navigate into the subdocument if it's not a zombie.
   return !zombieViewer;
 }
 
+void
+nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow)
+{
+    nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
+    if (!piWin)
+        return;
+
+    // Note that because FlushPendingNotifications flushes parents, this
+    // is O(N^2) in docshell tree depth.  However, the docshell tree is
+    // usually pretty shallow.
+
+    nsCOMPtr<nsIDOMDocument> domDoc;
+    aWindow->GetDocument(getter_AddRefs(domDoc));
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+    if (doc) {
+        doc->FlushPendingNotifications(Flush_Layout);
+    }
+
+    nsCOMPtr<nsIDocShellTreeNode> node =
+        do_QueryInterface(piWin->GetDocShell());
+    if (node) {
+        PRInt32 i = 0, i_end;
+        node->GetChildCount(&i_end);
+        for (; i < i_end; ++i) {
+            nsCOMPtr<nsIDocShellTreeItem> item;
+            node->GetChildAt(i, getter_AddRefs(item));
+            nsCOMPtr<nsIDOMWindow> win = do_GetInterface(item);
+            if (win) {
+                FlushLayoutForTree(win);
+            }
+        }
+    }
+}
+
 void nsContentUtils::RemoveNewlines(nsString &aString)
 {
   // strip CR/LF and null
   static const char badChars[] = {'\r', '\n', 0};
   aString.StripChars(badChars);
 }
 
 void
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -200,16 +200,18 @@ static NS_DEFINE_CID(kDOMEventGroupCID, 
 #include "nsHTMLStyleSheet.h"
 #include "nsHTMLCSSStyleSheet.h"
 
 #include "mozilla/dom/Link.h"
 #include "nsIHTMLDocument.h"
 
 using namespace mozilla::dom;
 
+typedef nsTArray<Link*> LinkArray;
+
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gDocumentLeakPRLog;
 static PRLogModuleInfo* gCspPRLog;
 #endif
 
 #define NAME_NOT_VALID ((nsBaseContentList*)1)
 
@@ -3897,17 +3899,17 @@ nsDocument::InternalAllowXULXBL()
   return PR_FALSE;
 }
 
 // Note: We don't hold a reference to the document observer; we assume
 // that it has a live reference to the document.
 void
 nsDocument::AddObserver(nsIDocumentObserver* aObserver)
 {
-  NS_ASSERTION(mObservers.IndexOf(aObserver) == nsTArray_base::NoIndex,
+  NS_ASSERTION(mObservers.IndexOf(aObserver) == nsTArray<int>::NoIndex,
                "Observer already in the list");
   mObservers.AppendElement(aObserver);
   AddMutationObserver(aObserver);
 }
 
 PRBool
 nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
 {
@@ -5538,16 +5540,23 @@ nsDocument::GetAnimationController()
   if (mAnimationController && shell) {
     nsPresContext *context = shell->GetPresContext();
     if (context &&
         context->ImageAnimationMode() == imgIContainer::kDontAnimMode) {
       mAnimationController->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
     }
   }
 
+  // If we're hidden (or being hidden), notify the newly-created animation
+  // controller. (Skip this check for SVG-as-an-image documents, though,
+  // because they don't get OnPageShow / OnPageHide calls).
+  if (!mIsShowing && !mIsBeingUsedAsImage) {
+    mAnimationController->OnPageHide();
+  }
+
   return mAnimationController;
 }
 #endif // MOZ_SMIL
 
 struct DirTable {
   const char* mName;
   PRUint8     mValue;
 };
@@ -7536,33 +7545,33 @@ nsDocument::DestroyElementMaps()
   mStyledLinks.Clear();
   mIdentifierMap.Clear();
 }
 
 static
 PLDHashOperator
 EnumerateStyledLinks(nsPtrHashKey<Link>* aEntry, void* aArray)
 {
-  nsTArray<Link*>* array = static_cast<nsTArray<Link*>*>(aArray);
+  LinkArray* array = static_cast<LinkArray*>(aArray);
   (void)array->AppendElement(aEntry->GetKey());
   return PL_DHASH_NEXT;
 }
 
 void
 nsDocument::RefreshLinkHrefs()
 {
   // Get a list of all links we know about.  We will reset them, which will
   // remove them from the document, so we need a copy of what is in the
   // hashtable.
-  nsTArray<Link*> linksToNotify(mStyledLinks.Count());
+  LinkArray linksToNotify(mStyledLinks.Count());
   (void)mStyledLinks.EnumerateEntries(EnumerateStyledLinks, &linksToNotify);
 
   // Reset all of our styled links.
   MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_STATE, PR_TRUE);
-  for (nsTArray_base::size_type i = 0; i < linksToNotify.Length(); i++) {
+  for (LinkArray::size_type i = 0; i < linksToNotify.Length(); i++) {
     linksToNotify[i]->ResetLinkState(true);
   }
 }
 
 NS_IMETHODIMP
 nsDocument::GetScriptTypeID(PRUint32 *aScriptType)
 {
     NS_ERROR("No default script type here - ask some element");
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -914,16 +914,18 @@ public:
   nsTArray<nsCString> mFileDataUris;
 
 #ifdef MOZ_SMIL
   // Returns our (lazily-initialized) animation controller.
   // If HasAnimationController is true, this is guaranteed to return non-null.
   nsSMILAnimationController* GetAnimationController();
 #endif // MOZ_SMIL
 
+  void SetImagesNeedAnimating(PRBool aAnimating);
+
   virtual void SuppressEventHandling(PRUint32 aIncrease);
 
   virtual void UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents);
   
   void DecreaseEventSuppression() { --mEventsSuppressed; }
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
                                                          nsIDocument)
@@ -1247,22 +1249,16 @@ private:
 
   // Tracking for images in the document.
   nsDataHashtable< nsPtrHashKey<imgIRequest>, PRUint32> mImageTracker;
 
 #ifdef DEBUG
 protected:
   PRBool mWillReparent;
 #endif
-
-protected:
-  // Makes the images on this document capable of having their animation
-  // active or suspended. An Image will animate as long as at least one of its
-  // owning Documents needs it to animate; otherwise it can suspend.
-  void SetImagesNeedAnimating(PRBool aAnimating);
 };
 
 #define NS_DOCUMENT_INTERFACE_TABLE_BEGIN(_class)                             \
   NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class)                            \
   NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMDocument, nsDocument)      \
   NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMNSDocument, nsDocument)    \
   NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMDocumentEvent, nsDocument) \
   NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMDocumentView, nsDocument)  \
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -648,17 +648,28 @@ nsFrameLoader::Show(PRInt32 marginWidth,
 #ifdef MOZ_IPC
   if (mRemoteFrame) {
     return ShowRemoteFrame(GetSubDocumentSize(frame));
   }
 #endif
 
   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
   NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
-  baseWindow->InitWindow(nsnull, view->GetWidget(), 0, 0, 10, 10);
+  nsIntSize size;
+  if (!(frame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
+    // We have a useful size already; use it, since we might get no
+    // more size updates.
+    size = GetSubDocumentSize(frame);
+  } else {
+    // Pick some default size for now.  Using 10x10 because that's what the
+    // code here used to do.
+    size.SizeTo(10, 10);
+  }
+  baseWindow->InitWindow(nsnull, view->GetWidget(), 0, 0,
+                         size.width, size.height);
   // This is kinda whacky, this "Create()" call doesn't really
   // create anything, one starts to wonder why this was named
   // "Create"...
   baseWindow->Create();
   baseWindow->SetVisibility(PR_TRUE);
 
   // Trigger editor re-initialization if midas is turned on in the
   // sub-document. This shouldn't be necessary, but given the way our
@@ -707,18 +718,17 @@ nsFrameLoader::ShowRemoteFrame(const nsI
 
   // FIXME/bug 589337: Show()/Hide() is pretty expensive for
   // cross-process layers; need to figure out what behavior we really
   // want here.  For now, hack.
   if (!mRemoteBrowserShown) {
     mRemoteBrowser->Show(size);
     mRemoteBrowserShown = PR_TRUE;
 
-    nsCOMPtr<nsIChromeFrameMessageManager> dummy;
-    GetMessageManager(getter_AddRefs(dummy)); // Initialize message manager.
+    EnsureMessageManager();
   } else {
     mRemoteBrowser->Move(size);
   }
 
   return true;
 }
 #endif
 
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -229,17 +229,17 @@ nsFrameMessageManager::SendSyncMessage()
   NS_ASSERTION(!IsWindowLevel(), "Should not call SendSyncMessage in chrome");
   NS_ASSERTION(!mParentManager, "Should not have parent manager in content!");
   if (mSyncCallback) {
     NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
     nsString messageName;
     nsString json;
     nsresult rv = GetParamsForMessage(messageName, json);
     NS_ENSURE_SUCCESS(rv, rv);
-    nsTArray<nsString> retval;
+    InfallibleTArray<nsString> retval;
     if (mSyncCallback(mCallbackData, messageName, json, &retval)) {
       nsAXPCNativeCallContext* ncc = nsnull;
       rv = nsContentUtils::XPConnect()->GetCurrentNativeCallContext(&ncc);
       NS_ENSURE_SUCCESS(rv, rv);
       NS_ENSURE_STATE(ncc);
 
       JSContext* ctx = nsnull;
       rv = ncc->GetJSContext(&ctx);
@@ -321,17 +321,17 @@ nsFrameMessageManager::GetDocShell(nsIDo
   return NS_OK;
 }
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       const nsAString& aMessage,
                                       PRBool aSync, const nsAString& aJSON,
                                       JSObject* aObjectsArray,
-                                      nsTArray<nsString>* aJSONRetVal,
+                                      InfallibleTArray<nsString>* aJSONRetVal,
                                       JSContext* aContext)
 {
   JSContext* ctx = mContext ? mContext : aContext;
   if (!ctx) {
     nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&ctx);
   }
   if (mListeners.Length()) {
     nsCOMPtr<nsIAtom> name = do_GetAtom(aMessage);
@@ -737,17 +737,17 @@ bool SendAsyncMessageToChildProcess(void
     return cp->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
   }
   return true;
 }
 
 bool SendSyncMessageToParentProcess(void* aCallbackData,
                                     const nsAString& aMessage,
                                     const nsAString& aJSON,
-                                    nsTArray<nsString>* aJSONRetVal)
+                                    InfallibleTArray<nsString>* aJSONRetVal)
 {
   mozilla::dom::ContentChild* cc =
     mozilla::dom::ContentChild::GetSingleton();
   if (cc) {
     return
       cc->SendSyncMessage(nsString(aMessage), nsString(aJSON), aJSONRetVal);
   }
   return true;
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -61,17 +61,17 @@ struct nsMessageListenerInfo
   nsCOMPtr<nsIFrameMessageListener> mListener;
   nsCOMPtr<nsIAtom> mMessage;
 };
 
 typedef bool (*nsLoadScriptCallback)(void* aCallbackData, const nsAString& aURL);
 typedef bool (*nsSyncMessageCallback)(void* aCallbackData,
                                       const nsAString& aMessage,
                                       const nsAString& aJSON,
-                                      nsTArray<nsString>* aJSONRetVal);
+                                      InfallibleTArray<nsString>* aJSONRetVal);
 typedef bool (*nsAsyncMessageCallback)(void* aCallbackData,
                                        const nsAString& aMessage,
                                        const nsAString& aJSON);
 
 class nsFrameMessageManager : public nsIContentFrameMessageManager,
                               public nsIChromeFrameMessageManager
 {
 public:
@@ -124,17 +124,17 @@ public:
   NS_DECL_NSIFRAMEMESSAGEMANAGER
   NS_DECL_NSISYNCMESSAGESENDER
   NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
   NS_DECL_NSICHROMEFRAMEMESSAGEMANAGER
 
   nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
                           PRBool aSync, const nsAString& aJSON,
                           JSObject* aObjectsArray,
-                          nsTArray<nsString>* aJSONRetVal,
+                          InfallibleTArray<nsString>* aJSONRetVal,
                           JSContext* aContext = nsnull);
   void AddChildManager(nsFrameMessageManager* aManager,
                        PRBool aLoadScripts = PR_TRUE);
   void RemoveChildManager(nsFrameMessageManager* aManager)
   {
     mChildManagers.RemoveObject(aManager);
   }
 
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -49,17 +49,17 @@
 #include "nsScriptLoader.h"
 #include "nsIJSContextStack.h"
 #include "nsFrameLoader.h"
 #include "nsIPrivateDOMEvent.h"
 
 bool SendSyncMessageToParent(void* aCallbackData,
                              const nsAString& aMessage,
                              const nsAString& aJSON,
-                             nsTArray<nsString>* aJSONRetVal)
+                             InfallibleTArray<nsString>* aJSONRetVal)
 {
   nsInProcessTabChildGlobal* tabChild =
     static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
   nsCOMPtr<nsIContent> owner = tabChild->mOwner;
   nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
   asyncMessages.SwapElements(tabChild->mASyncMessages);
   PRUint32 len = asyncMessages.Length();
   for (PRUint32 i = 0; i < len; ++i) {
--- a/content/base/src/nsReferencedElement.cpp
+++ b/content/base/src/nsReferencedElement.cpp
@@ -100,44 +100,55 @@ nsReferencedElement::Reset(nsIContent* a
   if (ref.IsEmpty())
     return;
 
   // Get the current document
   nsIDocument *doc = aFromContent->GetCurrentDoc();
   if (!doc)
     return;
 
-  // This will be the URI of the document the content belongs to
-  // (the URI of the XBL document if the content is anonymous
-  // XBL content)
-  nsCOMPtr<nsIURL> documentURL = do_QueryInterface(doc->GetDocumentURI());
   nsIContent* bindingParent = aFromContent->GetBindingParent();
-  PRBool isXBL = PR_FALSE;
   if (bindingParent) {
     nsXBLBinding* binding = doc->BindingManager()->GetBinding(bindingParent);
     if (binding) {
-      // XXX sXBL/XBL2 issue
-      // If this is an anonymous XBL element then the URI is
-      // relative to the binding document. A full fix requires a
-      // proper XBL2 implementation but for now URIs that are
-      // relative to the binding document should be resolve to the
-      // copy of the target element that has been inserted into the
-      // bound document.
-      documentURL = do_QueryInterface(binding->PrototypeBinding()->DocURI());
-      isXBL = PR_TRUE;
+      nsCOMPtr<nsIURL> bindingDocumentURL =
+        do_QueryInterface(binding->PrototypeBinding()->DocURI());
+      if (EqualExceptRef(url, bindingDocumentURL)) {
+        // XXX sXBL/XBL2 issue
+        // Our content is an anonymous XBL element from a binding inside the
+        // same document that the referenced URI points to. In order to avoid
+        // the risk of ID collisions we restrict ourselves to anonymous
+        // elements from this binding; specifically, URIs that are relative to
+        // the binding document should resolve to the copy of the target
+        // element that has been inserted into the bound document.
+        // If the URI points to a different document we don't need this
+        // restriction.
+        nsINodeList* anonymousChildren =
+          doc->BindingManager()->GetAnonymousNodesFor(bindingParent);
+
+        if (anonymousChildren) {
+          PRUint32 length;
+          anonymousChildren->GetLength(&length);
+          for (PRUint32 i = 0; i < length && !mElement; ++i) {
+            mElement =
+              nsContentUtils::MatchElementId(anonymousChildren->GetNodeAt(i), ref);
+          }
+        }
+
+        // We don't have watching working yet for XBL, so bail out here.
+        return;
+      }
     }
   }
+
+  nsCOMPtr<nsIURL> documentURL = do_QueryInterface(doc->GetDocumentURI());
   if (!documentURL)
     return;
 
   if (!EqualExceptRef(url, documentURL)) {
-    // Don't take the XBL codepath here, since we'll want to just
-    // normally set up our external resource document and then watch
-    // it as needed.
-    isXBL = PR_FALSE;
     nsRefPtr<nsIDocument::ExternalResourceLoad> load;
     doc = doc->RequestExternalResource(url, aFromContent, getter_AddRefs(load));
     if (!doc) {
       if (!load || !aWatch) {
         // Nothing will ever happen here
         return;
       }
 
@@ -146,34 +157,16 @@ nsReferencedElement::Reset(nsIContent* a
       mPendingNotification = observer;
       if (observer) {
         load->AddObserver(observer);
       }
       // Keep going so we set up our watching stuff a bit
     }
   }
 
-  // Get the element
-  if (isXBL) {
-    nsINodeList* anonymousChildren =
-      doc->BindingManager()-> GetAnonymousNodesFor(bindingParent);
-
-    if (anonymousChildren) {
-      PRUint32 length;
-      anonymousChildren->GetLength(&length);
-      for (PRUint32 i = 0; i < length && !mElement; ++i) {
-        mElement =
-          nsContentUtils::MatchElementId(anonymousChildren->GetNodeAt(i), ref);
-      }
-    }
-
-    // We don't have watching working yet for XBL, so bail out here.
-    return;
-  }
-
   if (aWatch) {
     nsCOMPtr<nsIAtom> atom = do_GetAtom(ref);
     if (!atom)
       return;
     atom.swap(mWatchID);
   }
 
   mReferencingImage = aReferenceImage;
--- a/content/base/src/nsScriptElement.cpp
+++ b/content/base/src/nsScriptElement.cpp
@@ -10,17 +10,17 @@
  * 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 Corporation.
+ * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Jonas Sicking <jonas@sicking.cc> (original developer)
  *
  * 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
@@ -141,65 +141,35 @@ void
 nsScriptElement::ContentInserted(nsIDocument *aDocument,
                                  nsIContent* aContainer,
                                  nsIContent* aChild,
                                  PRInt32 aIndexInContainer)
 {
   MaybeProcessScript();
 }
 
-static PRBool
-InNonScriptingContainer(nsIContent* aNode)
-{
-  aNode = aNode->GetParent();
-  while (aNode) {
-    // XXX noframes and noembed are currently unconditionally not
-    // displayed and processed. This might change if we support either
-    // prefs or per-document container settings for not allowing
-    // frames or plugins.
-    if (aNode->IsHTML()) {
-      nsIAtom *localName = aNode->Tag();
-      if (localName == nsGkAtoms::iframe ||
-          localName == nsGkAtoms::noframes ||
-          localName == nsGkAtoms::noembed) {
-        return PR_TRUE;
-      }
-    }
-    aNode = aNode->GetParent();
-  }
-
-  return PR_FALSE;
-}
-
 nsresult
 nsScriptElement::MaybeProcessScript()
 {
   nsCOMPtr<nsIContent> cont =
     do_QueryInterface((nsIScriptElement*) this);
 
   NS_ASSERTION(cont->DebugGetSlots()->mMutationObservers.Contains(this),
                "You forgot to add self as observer");
 
   if (mAlreadyStarted || !mDoneAddingChildren || !cont->IsInDoc() ||
       mMalformed || !HasScriptContent()) {
     return NS_OK;
   }
 
   FreezeUriAsyncDefer();
 
-  if (InNonScriptingContainer(cont)) {
-    // Make sure to flag ourselves as evaluated
-    mAlreadyStarted = PR_TRUE;
-    return NS_OK;
-  }
-
-  nsresult scriptresult = NS_OK;
   nsRefPtr<nsScriptLoader> loader = cont->GetOwnerDoc()->ScriptLoader();
   mAlreadyStarted = PR_TRUE;
-  scriptresult = loader->ProcessScriptElement(this);
+  nsresult scriptresult = loader->ProcessScriptElement(this);
 
   // The only error we don't ignore is NS_ERROR_HTMLPARSER_BLOCK
   // However we don't want to override other success values
   // (such as NS_CONTENT_SCRIPT_IS_EVENTHANDLER)
   if (NS_FAILED(scriptresult) &&
       scriptresult != NS_ERROR_HTMLPARSER_BLOCK) {
     scriptresult = NS_OK;
   }
--- a/content/base/test/test_bug453736.html
+++ b/content/base/test/test_bug453736.html
@@ -8,62 +8,28 @@ https://bugzilla.mozilla.org/show_bug.cg
   <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=453736">Mozilla Bug 453736</a>
 <p id="display"></p>
 <div id="content" style="display: none">
-
 </div>
 <pre id="test">
 <script type="application/javascript">
-
 /** Test for Bug 453736 **/
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function() {
   const scriptCreationFuncs = [
     function() { return document.createElement("script"); },
     function() { return document.createElementNS("http://www.w3.org/2000/svg", "script"); }
   ];
 
-  const noScriptContainers = ["iframe", "noframes", "noembed"];
-  for (var i = 0; i < noScriptContainers.length; ++i) {
-    for each (var func in scriptCreationFuncs) {
-      var cont = noScriptContainers[i];
-      var node = document.createElement(cont);
-      document.body.appendChild(node);
-      var s = func();
-      s.setAttribute("type", "application/javascript");
-      s.appendChild(document.createTextNode('window["'+cont+'ScriptRan"] = true'));
-
-      window[cont+"ScriptRan"] = false;
-      document.body.appendChild(s.cloneNode(true));
-      is(window[cont+"ScriptRan"], true,
-         "Clone of non-inserted script created with " + func +" should run");
-   
-      window[cont+"ScriptRan"] = false;
-      node.appendChild(s);
-      is(window[cont+"ScriptRan"], false,
-         "Script created with " + func +" shouldn't run when inserting in <"+cont+">");
-
-      window[cont+"ScriptRan"] = false;
-      document.body.appendChild(s);
-      is(window[cont+"ScriptRan"], false,
-         "Script created with " + func + " shouldn't run when moving out of <"+cont+">");
-
-      window[cont+"ScriptRan"] = false;
-      document.body.appendChild(s.cloneNode(true));
-      is(window[cont+"ScriptRan"], false,
-         "Clone of script inside <" + cont + "> created with " + func + " shouldn't run");
-    }
-  }
-
-  const scriptContainers = ["div"];
+  const scriptContainers = ["div", "iframe", "noframes", "noembed"];
   for (var i = 0; i < scriptContainers.length; ++i) {
     for each (var func in scriptCreationFuncs) {
       var cont = scriptContainers[i];
       var node = document.createElement(cont);
       document.body.appendChild(node);
       var s = func();
       s.setAttribute("type", "application/javascript");
       s.appendChild(document.createTextNode('window["'+cont+'ScriptRan"] = true'));
@@ -82,16 +48,12 @@ addLoadEvent(function() {
       document.body.appendChild(s.cloneNode(true));
       is(window[cont+"ScriptRan"], false,
          "Clone of script inside <" + cont + "> created with " + func + " shouldn't run");
     }
   }
 
   SimpleTest.finish();
 });
-
-
-
-
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_x-frame-options.html
+++ b/content/base/test/test_x-frame-options.html
@@ -11,34 +11,45 @@
 <div id="content" style="display: none">
 
 </div>
 
 <iframe style="width:100%;height:300px;" id="harness"></iframe>
 <script class="testbody" type="text/javascript">
 
 var path = "/tests/content/base/test/";
-// contains { test_frame_id : expected_result }
-var testExpectedResults = { "control1": true,
-                            "control2": true,
-                            "deny": false,
-                            "sameorigin1": true,
-                            "sameorigin2": false
-                          };
 
 var testFramesLoaded = function() {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   var harness = document.getElementById("harness");
 
-  for (var t in testExpectedResults) {
-    var frame = harness.contentDocument.getElementById(t);
-    // test if frame loaded by checking for a contentDocument we can access
-    test = frame.contentDocument.getElementById("test");
-    is(test != null, testExpectedResults[t], "test "+t);
-  }
+  // iframe from same origin, no X-F-O header - should load
+  var frame = harness.contentDocument.getElementById("control1");
+  var test1 = frame.contentDocument.getElementById("test").textContent;
+  is(test1, "control1", "test control1");
+
+  // iframe from different origin, no X-F-O header - should load
+  frame = harness.contentDocument.getElementById("control2");
+  var test2 = frame.contentDocument.getElementById("test").textContent;
+  is(test2, "control2", "test control2");
+
+  // iframe from same origin, X-F-O: DENY - should not load
+  frame = harness.contentDocument.getElementById("deny");
+  var test3 = frame.contentDocument.getElementById("test");
+  is(test3, null, "test deny");
+
+  // iframe from same origin, X-F-O: SAMEORIGIN - should load
+  frame = harness.contentDocument.getElementById("sameorigin1");
+  var test4 = frame.contentDocument.getElementById("test").textContent;
+  is(test4, "sameorigin1", "test sameorigin1");
+
+  // iframe from different origin, X-F-O: SAMEORIGIN - should not load
+  frame = harness.contentDocument.getElementById("sameorigin2");
+  var test5 = frame.contentDocument.getElementById("test");
+  is(test5, null, "test sameorigin2");
 
   // call tests to check principal comparison, e.g. a document can open a window
   // to a data: or javascript: document which frames an
   // X-Frame-Options: SAMEORIGIN document and the frame should load
   testFrameInJSURI();
 }
 
 // test that a document can be framed under a javascript: URL opened by the
--- a/content/canvas/src/DocumentRendererChild.cpp
+++ b/content/canvas/src/DocumentRendererChild.cpp
@@ -59,62 +59,28 @@
 using namespace mozilla::ipc;
 
 DocumentRendererChild::DocumentRendererChild()
 {}
 
 DocumentRendererChild::~DocumentRendererChild()
 {}
 
-static void
-FlushLayoutForTree(nsIDOMWindow* aWindow)
-{
-    nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
-    if (!piWin)
-        return;
-
-    // Note that because FlushPendingNotifications flushes parents, this
-    // is O(N^2) in docshell tree depth.  However, the docshell tree is
-    // usually pretty shallow.
-
-    nsCOMPtr<nsIDOMDocument> domDoc;
-    aWindow->GetDocument(getter_AddRefs(domDoc));
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
-    if (doc) {
-        doc->FlushPendingNotifications(Flush_Layout);
-    }
-
-    nsCOMPtr<nsIDocShellTreeNode> node =
-        do_QueryInterface(piWin->GetDocShell());
-    if (node) {
-        PRInt32 i = 0, i_end;
-        node->GetChildCount(&i_end);
-        for (; i < i_end; ++i) {
-            nsCOMPtr<nsIDocShellTreeItem> item;
-            node->GetChildAt(i, getter_AddRefs(item));
-            nsCOMPtr<nsIDOMWindow> win = do_GetInterface(item);
-            if (win) {
-                FlushLayoutForTree(win);
-            }
-        }
-    }
-}
-
 bool
 DocumentRendererChild::RenderDocument(nsIDOMWindow *window,
                                       const nsRect& documentRect,
                                       const gfxMatrix& transform,
                                       const nsString& bgcolor,
                                       PRUint32 renderFlags,
                                       PRBool flushLayout, 
                                       const nsIntSize& renderSize,
                                       nsCString& data)
 {
     if (flushLayout)
-        FlushLayoutForTree(window);
+        nsContentUtils::FlushLayoutForTree(window);
 
     nsCOMPtr<nsPresContext> presContext;
     nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
     if (win) {
         nsIDocShell* docshell = win->GetDocShell();
         if (docshell) {
             docshell->GetPresContext(getter_AddRefs(presContext));
         }
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -338,20 +338,20 @@ WebGLContext::SetDimensions(PRInt32 widt
             }
         }
     }
 
     // if we're forcing osmesa, do it first
     if (forceOSMesa) {
         gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
         if (!gl || !InitAndValidateGL()) {
-            LogMessage("WebGL: OSMesa forced, but creating context failed -- aborting!");
+            LogMessage("OSMesa forced, but creating context failed -- aborting!");
             return NS_ERROR_FAILURE;
         }
-        LogMessage("WebGL: Using software rendering via OSMesa (THIS WILL BE SLOW)");
+        LogMessage("Using software rendering via OSMesa (THIS WILL BE SLOW)");
     }
 
 #ifdef XP_WIN
     // On Windows, we may have a choice of backends, including straight
     // OpenGL, D3D through ANGLE via EGL, or straight EGL/GLES2.
     // We don't differentiate the latter two yet, but we allow for
     // a env var to try EGL first, instead of last; there's also a pref,
     // the env var being set overrides the pref
@@ -394,18 +394,28 @@ WebGLContext::SetDimensions(PRInt32 widt
     if (!gl && useOpenGL) {
         gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
         if (gl && !InitAndValidateGL()) {
             gl = nsnull;
         }
     }
 #endif
 
+    // finally, try OSMesa
     if (!gl) {
-        LogMessage("WebGL: Can't get a usable WebGL context");
+        gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
+        if (!gl || !InitAndValidateGL()) {
+            gl = nsnull;
+        } else {
+            LogMessage("Using software rendering via OSMesa (THIS WILL BE SLOW)");
+        }
+    }
+
+    if (!gl) {
+        LogMessage("Can't get a usable WebGL context");
         return NS_ERROR_FAILURE;
     }
 
 #ifdef DEBUG
     printf_stderr ("--- WebGL context created: %p\n", gl.get());
 #endif
 
     mWidth = width;
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -469,20 +469,17 @@ protected:
     // textures bound to 
     nsTArray<WebGLObjectRefPtr<WebGLTexture> > mBound2DTextures;
     nsTArray<WebGLObjectRefPtr<WebGLTexture> > mBoundCubeMapTextures;
 
     WebGLObjectRefPtr<WebGLBuffer> mBoundArrayBuffer;
     WebGLObjectRefPtr<WebGLBuffer> mBoundElementArrayBuffer;
     WebGLObjectRefPtr<WebGLProgram> mCurrentProgram;
 
-    // XXX these 3 are wrong types, and aren't used atm (except for the length of the attachments)
-    nsTArray<WebGLObjectRefPtr<WebGLTexture> > mFramebufferColorAttachments;
-    nsRefPtr<WebGLFramebuffer> mFramebufferDepthAttachment;
-    nsRefPtr<WebGLFramebuffer> mFramebufferStencilAttachment;
+    PRUint32 mMaxFramebufferColorAttachments;
 
     nsRefPtr<WebGLFramebuffer> mBoundFramebuffer;
     nsRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
 
     // lookup tables for GL name -> object wrapper
     nsRefPtrHashtable<nsUint32HashKey, WebGLTexture> mMapTextures;
     nsRefPtrHashtable<nsUint32HashKey, WebGLBuffer> mMapBuffers;
     nsRefPtrHashtable<nsUint32HashKey, WebGLProgram> mMapPrograms;
@@ -505,16 +502,17 @@ protected:
 public:
     // console logging helpers
     static void LogMessage(const char *fmt, ...);
     static void LogMessage(const char *fmt, va_list ap);
     void LogMessageIfVerbose(const char *fmt, ...);
     void LogMessageIfVerbose(const char *fmt, va_list ap);
 
     friend class WebGLTexture;
+    friend class WebGLFramebuffer;
 };
 
 // this class is a mixin for the named type wrappers, and is used
 // by WebGLObjectRefPtr to tell the object who holds references, so that
 // we can zero them out appropriately when the object is deleted, because
 // it will be unbound in the GL.
 class WebGLZeroingObject
 {
@@ -998,22 +996,24 @@ public:
 
             PRBool areAllLevel0ImagesDefined = PR_TRUE;
             for (size_t face = 0; face < mFacesCount; ++face) {
                     areAllLevel0ImagesDefined &= ImageInfoAt(0, face).mIsDefined;
             }
 
             if (!areAllLevel0ImagesDefined) {
                 if (mTarget == LOCAL_GL_TEXTURE_2D) {
-                    mContext->LogMessage("We are currently drawing stuff, but some 2D texture has not yet been "
-                                         "uploaded any image at level 0. Until it's uploaded, this texture will look black.");
+                    mContext->LogMessageIfVerbose(
+                        "We are currently drawing stuff, but some 2D texture has not yet been "
+                        "uploaded any image at level 0. Until it's uploaded, this texture will look black.");
                 } else {
-                    mContext->LogMessage("We are currently drawing stuff, but some cube map texture has not yet been "
-                                         "uploaded any image at level 0, for at least one of its six faces. "
-                                         "Until it's uploaded, this texture will look black.");
+                    mContext->LogMessageIfVerbose(
+                        "We are currently drawing stuff, but some cube map texture has not yet been "
+                        "uploaded any image at level 0, for at least one of its six faces. "
+                        "Until it's uploaded, this texture will look black.");
                 }
                 mFakeBlackStatus = DoNeedFakeBlack;
                 return PR_TRUE;
             }
 
             // ok, done with the stupid special cases above. Now actually implementing the cases defined in section 3.8.2.
 
             const char *msg_rendering_as_black
@@ -1229,16 +1229,17 @@ public:
     PRBool NextGeneration()
     {
         if (!(mGeneration+1).valid())
             return PR_FALSE; // must exit without changing mGeneration
         ++mGeneration;
         mMapUniformLocations.Clear();
         return PR_TRUE;
     }
+    
 
     already_AddRefed<WebGLUniformLocation> GetUniformLocationObject(GLint glLocation);
 
     /* Called only after LinkProgram */
     PRBool UpdateInfo(gl::GLContext *gl);
 
     /* Getters for cached program info */
     WebGLint UniformMaxNameLength() const { return mUniformMaxNameLength; }
@@ -1260,84 +1261,371 @@ protected:
     GLint mAttribMaxNameLength;
     GLint mUniformCount;
     GLint mAttribCount;
     std::vector<bool> mAttribsInUse;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLProgram, WEBGLPROGRAM_PRIVATE_IID)
 
+#define WEBGLRENDERBUFFER_PRIVATE_IID \
+    {0x3cbc2067, 0x5831, 0x4e3f, {0xac, 0x52, 0x7e, 0xf4, 0x5c, 0x04, 0xff, 0xae}}
+class WebGLRenderbuffer :
+    public nsIWebGLRenderbuffer,
+    public WebGLZeroingObject,
+    public WebGLRectangleObject,
+    public WebGLContextBoundObject
+{
+public:
+    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLRENDERBUFFER_PRIVATE_IID)
+
+    WebGLRenderbuffer(WebGLContext *context, WebGLuint name, WebGLuint secondBufferName = 0) :
+        WebGLContextBoundObject(context),
+        mName(name),
+        mInternalFormat(0),
+        mDeleted(PR_FALSE), mInitialized(PR_FALSE)
+    { }
+
+    void Delete() {
+        if (mDeleted)
+            return;
+        ZeroOwners();
+        mDeleted = PR_TRUE;
+    }
+    PRBool Deleted() const { return mDeleted; }
+    WebGLuint GLName() const { return mName; }
+
+    PRBool Initialized() const { return mInitialized; }
+    void SetInitialized(PRBool aInitialized) { mInitialized = aInitialized; }
+
+    WebGLenum InternalFormat() const { return mInternalFormat; }
+    void SetInternalFormat(WebGLenum aInternalFormat) { mInternalFormat = aInternalFormat; }
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIWEBGLRENDERBUFFER
+
+protected:
+    WebGLuint mName;
+    WebGLenum mInternalFormat;
+
+    PRBool mDeleted;
+    PRBool mInitialized;
+
+    friend class WebGLFramebuffer;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(WebGLRenderbuffer, WEBGLRENDERBUFFER_PRIVATE_IID)
+
 #define WEBGLFRAMEBUFFER_PRIVATE_IID \
     {0x0052a16f, 0x4bc9, 0x4a55, {0x9d, 0xa3, 0x54, 0x95, 0xaa, 0x4e, 0x80, 0xb9}}
 class WebGLFramebuffer :
     public nsIWebGLFramebuffer,
     public WebGLZeroingObject,
     public WebGLRectangleObject,
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLFRAMEBUFFER_PRIVATE_IID)
 
     WebGLFramebuffer(WebGLContext *context, WebGLuint name) :
         WebGLContextBoundObject(context),
-        mName(name), mDeleted(PR_FALSE)
+        mName(name), mDeleted(PR_FALSE),
+        mHasDepthAttachment(PR_FALSE),
+        mHasStencilAttachment(PR_FALSE),
+        mHasDepthStencilAttachment(PR_FALSE)
     { }
 
     void Delete() {
         if (mDeleted)
             return;
         ZeroOwners();
         mDeleted = PR_TRUE;
     }
     PRBool Deleted() { return mDeleted; }
     WebGLuint GLName() { return mName; }
 
+    nsresult FramebufferRenderbuffer(WebGLenum target,
+                                     WebGLenum attachment,
+                                     WebGLenum rbtarget,
+                                     nsIWebGLRenderbuffer *rbobj)
+    {
+        WebGLuint renderbuffername;
+        PRBool isNull;
+        WebGLRenderbuffer *wrb;
+
+        if (!mContext->GetConcreteObjectAndGLName("framebufferRenderbuffer: renderbuffer",
+                                                  rbobj, &wrb, &renderbuffername, &isNull))
+        {
+            return NS_OK;
+        }
+
+        if (target != LOCAL_GL_FRAMEBUFFER)
+            return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
+
+        if (rbtarget != LOCAL_GL_RENDERBUFFER)
+            return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
+
+        const char *badAttachmentFormatMsg =
+            "framebufferRenderbuffer: this renderbuffer does not have a suitable format for this attachment point";
+
+        switch (attachment) {
+        case LOCAL_GL_DEPTH_ATTACHMENT:
+            if (!isNull) {
+                if (wrb->mInternalFormat != LOCAL_GL_DEPTH_COMPONENT16)
+                    return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
+            }
+            mDepthOrStencilRenderbufferAttachment = wrb;
+            mHasDepthAttachment = !isNull;
+            break;
+        case LOCAL_GL_STENCIL_ATTACHMENT:
+            if (!isNull) {
+                if (wrb->mInternalFormat != LOCAL_GL_STENCIL_INDEX8)
+                    return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
+            }
+            mDepthOrStencilRenderbufferAttachment = wrb;
+            mHasStencilAttachment = !isNull;
+            break;
+        case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
+            if (!isNull) {
+                if (wrb->mInternalFormat != LOCAL_GL_DEPTH_STENCIL)
+                    return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
+            }
+            mDepthOrStencilRenderbufferAttachment = wrb;
+            mHasDepthStencilAttachment = !isNull;
+            break;
+        default:
+            // finish checking that the 'attachment' parameter is among the allowed values
+            if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
+                 attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mMaxFramebufferColorAttachments))
+            {
+                return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: attachment", attachment);
+            }
+            if (!isNull) {
+                if (wrb->mInternalFormat != LOCAL_GL_RGBA4 &&
+                    wrb->mInternalFormat != LOCAL_GL_RGB565 &&
+                    wrb->mInternalFormat != LOCAL_GL_RGB5_A1)
+                {
+                    return mContext->ErrorInvalidOperation(badAttachmentFormatMsg);
+                }
+            }
+            mColorRenderbufferAttachment = wrb;
+            break;
+        }
+
+        // dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
+        if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
+            setDimensions(wrb);
+
+        mContext->MakeContextCurrent();
+        mContext->gl->fFramebufferRenderbuffer(target, attachment, rbtarget, renderbuffername);
+
+        return NS_OK;
+    }
+
+    nsresult FramebufferTexture2D(WebGLenum target,
+                                  WebGLenum attachment,
+                                  WebGLenum textarget,
+                                  nsIWebGLTexture *tobj,
+                                  WebGLint level)
+    {
+        WebGLuint texturename;
+        PRBool isNull;
+        WebGLTexture *wtex;
+
+        if (!mContext->GetConcreteObjectAndGLName("framebufferTexture2D: texture",
+                                                  tobj, &wtex, &texturename, &isNull))
+        {
+            return NS_OK;
+        }
+
+        if (target != LOCAL_GL_FRAMEBUFFER)
+            return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
+
+        if (!isNull && textarget != LOCAL_GL_TEXTURE_2D &&
+            (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
+            textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
+            return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
+
+        if (!isNull && level > 0)
+            return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
+
+        switch (attachment) {
+        case LOCAL_GL_DEPTH_ATTACHMENT:
+        case LOCAL_GL_STENCIL_ATTACHMENT:
+        case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
+            return mContext->ErrorInvalidOperation("framebufferTexture2D: depth and stencil attachments can "
+                          "only be renderbuffers, not textures, as there is no suitable texture format.");
+            break;
+        default:
+            if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
+                 attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mMaxFramebufferColorAttachments))
+            {
+                return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: attachment", attachment);
+            }
+            // nothing to do for color buffers. all textures have a color-renderable format.
+            break;
+        }
+
+        // dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
+        if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
+            setDimensions(wtex);
+
+        mContext->MakeContextCurrent();
+        mContext->gl->fFramebufferTexture2D(target, attachment, textarget, texturename, level);
+
+        return NS_OK;
+    }
+
+    // implement inline, as it's performance critical (called by draw-functions).
+    // the generic case for which we're optimizing is the case where there's nothing to initialize.
+    inline PRBool CheckAndInitializeRenderbuffers()
+    {
+        if (HasConflictingAttachments()) {
+            mContext->SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
+            return PR_FALSE;
+        }
+
+        if ((mColorRenderbufferAttachment          && !mColorRenderbufferAttachment->Initialized()) ||
+            (mDepthOrStencilRenderbufferAttachment && !mDepthOrStencilRenderbufferAttachment->Initialized()))
+        {
+            InitializeRenderbuffers();
+        }
+
+        return PR_TRUE;
+    }
+
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLFRAMEBUFFER
+
+    PRBool HasConflictingAttachments() const {
+        return int(mHasDepthAttachment) +
+               int(mHasStencilAttachment) +
+               int(mHasDepthStencilAttachment) > 1;
+    }
+
 protected:
+
+    // protected because WebGLContext should only call InitializeRenderbuffers
+    void InitializeRenderbuffers()
+    {
+        mContext->MakeContextCurrent();
+
+        if (mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) != LOCAL_GL_FRAMEBUFFER_COMPLETE)
+            return;
+
+        PRBool initializeColorBuffer = mColorRenderbufferAttachment &&
+                                       !mColorRenderbufferAttachment->Initialized();
+        PRBool initializeDepthOrStencilBuffer = mDepthOrStencilRenderbufferAttachment &&
+                                                !mDepthOrStencilRenderbufferAttachment->Initialized();
+        PRBool initializeDepthBuffer = initializeDepthOrStencilBuffer && HasDepthBuffer();
+        PRBool initializeStencilBuffer = initializeDepthOrStencilBuffer && HasStencilBuffer();
+
+        realGLboolean savedColorMask[] = {0}, savedDepthMask = 0;
+        GLuint savedStencilMask = 0;
+        GLfloat savedColorClearValue[] = {0.f}, savedDepthClearValue = 0.f;
+        GLint savedStencilClearValue = 0;
+        GLuint clearBits = 0;
+
+        realGLboolean wasScissorTestEnabled = mContext->gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST);
+        mContext->gl->fDisable(LOCAL_GL_SCISSOR_TEST);
+
+        realGLboolean wasDitherEnabled = mContext->gl->fIsEnabled(LOCAL_GL_DITHER);
+        mContext->gl->fDisable(LOCAL_GL_DITHER);
+
+        mContext->gl->PushViewportRect(nsIntRect(0,0,width(),height()));
+
+        if (initializeColorBuffer) {
+            mContext->gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, savedColorMask);
+            mContext->gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, savedColorClearValue);
+            mContext->gl->fColorMask(1, 1, 1, 1);
+            mContext->gl->fClearColor(0.f, 0.f, 0.f, 0.f);
+            clearBits |= LOCAL_GL_COLOR_BUFFER_BIT;
+        }
+
+        if (initializeDepthBuffer) {
+            mContext->gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &savedDepthMask);
+            mContext->gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &savedDepthClearValue);
+            mContext->gl->fDepthMask(1);
+            mContext->gl->fClearDepth(0.f);
+            clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
+        }
+
+        if (initializeStencilBuffer) {
+            mContext->gl->fGetIntegerv(LOCAL_GL_STENCIL_WRITEMASK, reinterpret_cast<GLint*>(&savedStencilMask));
+            mContext->gl->fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &savedStencilClearValue);
+            mContext->gl->fStencilMask(0xffffffff);
+            mContext->gl->fClearStencil(0);
+            clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
+        }
+
+        // the one useful line of code
+        mContext->gl->fClear(clearBits);
+
+        if (initializeColorBuffer) {
+            mContext->gl->fColorMask(savedColorMask[0],
+                                     savedColorMask[1],
+                                     savedColorMask[2],
+                                     savedColorMask[3]);
+            mContext->gl->fClearColor(savedColorClearValue[0],
+                                      savedColorClearValue[1],
+                                      savedColorClearValue[2],
+                                      savedColorClearValue[3]);
+            mColorRenderbufferAttachment->SetInitialized(PR_TRUE);
+        }
+
+        if (initializeDepthBuffer) {
+            mContext->gl->fDepthMask(savedDepthMask);
+            mContext->gl->fClearDepth(savedDepthClearValue);
+            mDepthOrStencilRenderbufferAttachment->SetInitialized(PR_TRUE);
+        }
+
+        if (initializeStencilBuffer) {
+            mContext->gl->fStencilMask(savedStencilMask);
+            mContext->gl->fClearStencil(savedStencilClearValue);
+            mDepthOrStencilRenderbufferAttachment->SetInitialized(PR_TRUE);
+        }
+
+        mContext->gl->PopViewportRect();
+
+        if (wasDitherEnabled)
+            mContext->gl->fEnable(LOCAL_GL_DITHER);
+        else
+            mContext->gl->fDisable(LOCAL_GL_DITHER);
+
+        if (wasScissorTestEnabled)
+            mContext->gl->fEnable(LOCAL_GL_DITHER);
+        else
+            mContext->gl->fDisable(LOCAL_GL_SCISSOR_TEST);
+    }
+
+    PRBool HasDepthBuffer() const {
+        return mHasDepthAttachment || mHasDepthStencilAttachment;
+    }
+
+    PRBool HasStencilBuffer() const {
+        return mHasStencilAttachment || mHasDepthStencilAttachment;
+    }
+
     WebGLuint mName;
     PRBool mDeleted;
+
+    // we only store pointers to attached renderbuffers, not to attached textures, because
+    // we will only need to initialize renderbuffers. Textures are already initialized.
+    nsRefPtr<WebGLRenderbuffer> mColorRenderbufferAttachment;
+    nsRefPtr<WebGLRenderbuffer> mDepthOrStencilRenderbufferAttachment;
+
+    // these boolean values keep track of all attachments: renderbuffers and textures.
+    // thus they are not at all redundant with the above member pointers.
+    PRBool mHasDepthAttachment;
+    PRBool mHasStencilAttachment;
+    PRBool mHasDepthStencilAttachment;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLFramebuffer, WEBGLFRAMEBUFFER_PRIVATE_IID)
 
-#define WEBGLRENDERBUFFER_PRIVATE_IID \
-    {0x3cbc2067, 0x5831, 0x4e3f, {0xac, 0x52, 0x7e, 0xf4, 0x5c, 0x04, 0xff, 0xae}}
-class WebGLRenderbuffer :
-    public nsIWebGLRenderbuffer,
-    public WebGLZeroingObject,
-    public WebGLRectangleObject,
-    public WebGLContextBoundObject
-{
-public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLRENDERBUFFER_PRIVATE_IID)
-
-    WebGLRenderbuffer(WebGLContext *context, WebGLuint name) :
-        WebGLContextBoundObject(context),
-        mName(name), mDeleted(PR_FALSE)
-    { }
-
-    void Delete() {
-        if (mDeleted)
-            return;
-        ZeroOwners();
-        mDeleted = PR_TRUE;
-    }
-    PRBool Deleted() { return mDeleted; }
-    WebGLuint GLName() { return mName; }
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIWEBGLRENDERBUFFER
-protected:
-    WebGLuint mName;
-    PRBool mDeleted;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLRenderbuffer, WEBGLRENDERBUFFER_PRIVATE_IID)
-
 #define WEBGLUNIFORMLOCATION_PRIVATE_IID \
     {0x01a8a614, 0xb109, 0x42f1, {0xb4, 0x40, 0x8d, 0x8b, 0x87, 0x0b, 0x43, 0xa7}}
 class WebGLUniformLocation :
     public nsIWebGLUniformLocation,
     public WebGLZeroingObject,
     public WebGLContextBoundObject
 {
 public:
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -344,17 +344,17 @@ WebGLContext::BlendFuncSeparate(WebGLenu
     gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::BufferData(PRInt32 dummy)
 {
     // this should never be called
-    LogMessage("BufferData");
+    LogMessageIfVerbose("BufferData");
     return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 WebGLContext::BufferData_size(WebGLenum target, WebGLsizei size, WebGLenum usage)
 {
     WebGLBuffer *boundBuffer = NULL;
 
@@ -517,26 +517,34 @@ WebGLContext::BufferSubData_array(WebGLe
 
 NS_IMETHODIMP
 WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
 {
     *retval = 0;
 
     MakeContextCurrent();
     if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnum("CheckFramebufferStatus: target must be FRAMEBUFFER");
-
-    *retval = gl->fCheckFramebufferStatus(target);
+        return ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
+
+    if (mBoundFramebuffer && mBoundFramebuffer->HasConflictingAttachments())
+        *retval = LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
+    else
+        *retval = gl->fCheckFramebufferStatus(target);
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::Clear(PRUint32 mask)
 {
     MakeContextCurrent();
+
+    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+        return NS_OK;
+
     gl->fClear(mask);
     Invalidate();
 
     return NS_OK;
 }
 
 GL_SAME_METHOD_4(ClearColor, ClearColor, WebGLfloat, WebGLfloat, WebGLfloat, WebGLfloat)
 
@@ -755,16 +763,17 @@ WebGLContext::DeleteRenderbuffer(nsIWebG
             must be taken when deleting a renderbuffer object if the image of the renderbuffer
             is attached to a framebuffer object. In this case, if the deleted renderbuffer object is
             attached to the currently bound framebuffer object, it is 
             automatically detached.  However, attachments to any other framebuffer objects are the
             responsibility of the application.
     */
 
     gl->fDeleteRenderbuffers(1, &rbufname);
+
     rbuf->Delete();
     mMapRenderbuffers.Remove(rbufname);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::DeleteTexture(nsIWebGLTexture *tobj)
@@ -1042,16 +1051,19 @@ WebGLContext::DrawArrays(GLenum mode, We
         return ErrorInvalidOperation("DrawArrays: bound vertex attribute buffers do not have sufficient size for given first and count");
 
     // If count is 0, there's nothing to do.
     if (count == 0)
         return NS_OK;
 
     MakeContextCurrent();
 
+    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+        return NS_OK;
+
     BindFakeBlackTextures();
     DoFakeVertexAttrib0(checked_firstPlusCount.value());
 
     gl->fDrawArrays(mode, first, count);
 
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
@@ -1119,16 +1131,19 @@ WebGLContext::DrawElements(WebGLenum mod
     }
 
     // If count is 0, there's nothing to do.
     if (count == 0)
         return NS_OK;
 
     MakeContextCurrent();
 
+    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+        return NS_OK;
+
     BindFakeBlackTextures();
     DoFakeVertexAttrib0(checked_neededCount.value());
 
     gl->fDrawElements(mode, count, type, (GLvoid*) (byteOffset));
 
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
@@ -1166,100 +1181,36 @@ WebGLContext::EnableVertexAttribArray(We
     MakeContextCurrent();
 
     gl->fEnableVertexAttribArray(index);
     mAttribBuffers[index].enabled = PR_TRUE;
 
     return NS_OK;
 }
 
-// XXX need to track this -- see glDeleteRenderbuffer above and man page for DeleteRenderbuffers
 NS_IMETHODIMP
 WebGLContext::FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, WebGLenum rbtarget, nsIWebGLRenderbuffer *rbobj)
 {
-    WebGLuint renderbuffername;
-    PRBool isNull;
-    WebGLRenderbuffer *wrb;
-
-    if (!GetConcreteObjectAndGLName("framebufferRenderbuffer: renderbuffer", rbobj, &wrb, &renderbuffername, &isNull))
-        return NS_OK;
-
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
-
-    if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
-         attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mFramebufferColorAttachments.Length()) &&
-        attachment != LOCAL_GL_DEPTH_ATTACHMENT &&
-        attachment != LOCAL_GL_STENCIL_ATTACHMENT)
-    {
-        return ErrorInvalidEnumInfo("framebufferRenderbuffer: attachment", attachment);
-    }
-
-    if (rbtarget != LOCAL_GL_RENDERBUFFER)
-        return ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
-
-    if (!mBoundFramebuffer)
-        return ErrorInvalidOperation("FramebufferRenderbuffer: cannot modify framebuffer 0");
-
-    // dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
-    if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
-        mBoundFramebuffer->setDimensions(wrb);
-
-    MakeContextCurrent();
-
-    gl->fFramebufferRenderbuffer(target, attachment, rbtarget, renderbuffername);
-
-    return NS_OK;
+    if (mBoundFramebuffer)
+        return mBoundFramebuffer->FramebufferRenderbuffer(target, attachment, rbtarget, rbobj);
+    else
+        return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
 }
 
 NS_IMETHODIMP
 WebGLContext::FramebufferTexture2D(WebGLenum target,
                                    WebGLenum attachment,
                                    WebGLenum textarget,
                                    nsIWebGLTexture *tobj,
                                    WebGLint level)
 {
-    WebGLuint texturename;
-    PRBool isNull;
-    WebGLTexture *wtex;
-
-    if (!GetConcreteObjectAndGLName("framebufferTexture2D: texture", tobj, &wtex, &texturename, &isNull))
-        return NS_OK;
-
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
-
-    if ((attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
-         attachment >= LOCAL_GL_COLOR_ATTACHMENT0 + mFramebufferColorAttachments.Length()) &&
-        attachment != LOCAL_GL_DEPTH_ATTACHMENT &&
-        attachment != LOCAL_GL_STENCIL_ATTACHMENT)
-        return ErrorInvalidEnumInfo("framebufferTexture2D: attachment", attachment);
-
-    if (textarget != LOCAL_GL_TEXTURE_2D &&
-        (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
-         textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
-        return ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
-
-    if (level != 0)
-        return ErrorInvalidValue("FramebufferTexture2D: level must be 0");
-
-    if (!mBoundFramebuffer)
-        return ErrorInvalidOperation("FramebufferTexture2D: cannot modify framebuffer 0");
-
-    // dimensions are kept for readPixels primarily, function only uses COLOR_ATTACHMENT0
-    if (attachment == LOCAL_GL_COLOR_ATTACHMENT0)
-        mBoundFramebuffer->setDimensions(wtex);
-
-    // XXXXX we need to store/reference this attachment!
-
-    MakeContextCurrent();
-
-    gl->fFramebufferTexture2D(target, attachment, textarget, texturename, level);
-
-    return NS_OK;
+    if (mBoundFramebuffer)
+        return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level);
+    else
+        return ErrorInvalidOperation("framebufferTexture2D: cannot modify framebuffer 0");
 }
 
 GL_SAME_METHOD_0(Flush, Flush)
 
 GL_SAME_METHOD_0(Finish, Finish)
 
 NS_IMETHODIMP
 WebGLContext::FrontFace(WebGLenum mode)
@@ -2535,18 +2486,16 @@ WebGLContext::ReadPixels_base(WebGLint x
 //         case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
 //         case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
       case LOCAL_GL_UNSIGNED_BYTE:
         break;
       default:
         return ErrorInvalidEnumInfo("ReadPixels: type", type);
     }
 
-    MakeContextCurrent();
-
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * size;
 
     PRUint32 packAlignment = mPixelStorePackAlignment;
 
     // alignedRowSize = row size rounded up to next multiple of packAlignment
     CheckedUint32 checked_alignedRowSize
         = ((checked_plainRowSize + packAlignment-1) / packAlignment) * packAlignment;
 
@@ -2554,16 +2503,22 @@ WebGLContext::ReadPixels_base(WebGLint x
         = (height-1) * checked_alignedRowSize + checked_plainRowSize;
 
     if (!checked_neededByteLength.valid())
         return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
 
     if (checked_neededByteLength.value() > byteLength)
         return ErrorInvalidOperation("ReadPixels: buffer too small");
 
+    MakeContextCurrent();
+
+    // prevent readback of arbitrary video memory through uninitialized renderbuffers!
+    if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
+        return NS_OK;
+
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, boundWidth, boundHeight)) {
         // the easy case: we're not reading out-of-range pixels
         gl->fReadPixels(x, y, width, height, format, type, data);
     } else {
         // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
         // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
         // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
         // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
@@ -2640,42 +2595,67 @@ WebGLContext::ReadPixels_buf(WebGLint x,
     return ReadPixels_base(x, y, width, height, format, type,
                            pixels ? pixels->data : 0,
                            pixels ? pixels->byteLength : 0);
 }
 
 NS_IMETHODIMP
 WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, WebGLsizei width, WebGLsizei height)
 {
+
+    if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName())
+        return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
+
     if (target != LOCAL_GL_RENDERBUFFER)
-        return ErrorInvalidEnumInfo("RenderbufferStorage: target", target);
+        return ErrorInvalidEnumInfo("renderbufferStorage: target", target);
+
+    if (width <= 0 || height <= 0)
+        return ErrorInvalidValue("renderbufferStorage: width and height must be > 0");
+
+    if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName())
+        return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
+
+    MakeContextCurrent();
+
+    // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
+    WebGLenum internalformatForGL = internalformat;
 
     switch (internalformat) {
-      case LOCAL_GL_RGBA4:
-      // XXX case LOCAL_GL_RGB565:
-      case LOCAL_GL_RGB5_A1:
-      case LOCAL_GL_DEPTH_COMPONENT:
-      case LOCAL_GL_DEPTH_COMPONENT16:
-      case LOCAL_GL_STENCIL_INDEX8:
-          break;
-      default:
-          return ErrorInvalidEnumInfo("RenderbufferStorage: internalformat", internalformat);
+    case LOCAL_GL_RGBA4:
+    case LOCAL_GL_RGB5_A1:
+        // 16-bit RGBA formats are not supported on desktop GL
+        if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGBA8;
+        break;
+    case LOCAL_GL_RGB565:
+        // the RGB565 format is not supported on desktop GL
+        if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGB8;
+        break;
+    case LOCAL_GL_DEPTH_COMPONENT16:
+    case LOCAL_GL_STENCIL_INDEX8:
+        // nothing to do for these ones
+        break;
+    case LOCAL_GL_DEPTH_STENCIL:
+        // this one is available in newer OpenGL (at least since 3.1); will probably become available
+        // in OpenGL ES 3 (at least it will have some DEPTH_STENCIL) and is the same value that
+        // is otherwise provided by EXT_packed_depth_stencil and OES_packed_depth_stencil extensions
+        // which means it's supported on most GL and GL ES systems already.
+        //
+        // So we just use it hoping that it's available (perhaps as an extension) and if it's not available,
+        // we just let the GL generate an error and don't do anything about it ourselves.
+        internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
+        break;
+    default:
+        ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
     }
 
-    if (width <= 0 || height <= 0)
-        return ErrorInvalidValue("RenderbufferStorage: width and height must be > 0");
-
-    if (mBoundRenderbuffer)
-        mBoundRenderbuffer->setDimensions(width, height);
-
-    MakeContextCurrent();
-    gl->fRenderbufferStorage(target, internalformat, width, height);
-
-    // now we need to initialize the renderbuffer to 0 as per the thread "about RenderBufferStorage"
-    // on the public_webgl list
+    gl->fRenderbufferStorage(target, internalformatForGL, width, height);
+
+    mBoundRenderbuffer->SetInternalFormat(internalformat);
+    mBoundRenderbuffer->setDimensions(width, height);
+    mBoundRenderbuffer->SetInitialized(PR_FALSE);
 
     return NS_OK;
 }
 
 GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, WebGLfloat, WebGLboolean)
 
 NS_IMETHODIMP
 WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
@@ -3178,16 +3158,24 @@ NS_IMETHODIMP
 WebGLContext::ValidateProgram(nsIWebGLProgram *pobj)
 {
     WebGLuint progname;
     if (!GetGLName<WebGLProgram>("validateProgram", pobj, &progname))
         return NS_OK;
 
     MakeContextCurrent();
 
+#ifdef XP_MACOSX
+    if (gl->Vendor() == gl::GLContext::VendorNVIDIA) {
+        LogMessageIfVerbose("validateProgram: implemented as a no-operation "
+                            "on Mac/NVIDIA to work around a driver crash");
+        return NS_OK;
+    }
+#endif
+
     gl->fValidateProgram(progname);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::CreateFramebuffer(nsIWebGLFramebuffer **retval)
 {
@@ -3240,17 +3228,16 @@ WebGLContext::CompileShader(nsIWebGLShad
     WebGLuint shadername;
     if (!GetConcreteObjectAndGLName("compileShader", sobj, &shader, &shadername))
         return NS_OK;
     MakeContextCurrent();
 
 #if defined(USE_ANGLE)
     if (shader->NeedsTranslation() && mShaderValidation) {
         ShHandle compiler = 0;
-        int debugFlags = 0;
         ShBuiltInResources resources;
         memset(&resources, 0, sizeof(ShBuiltInResources));
 
         resources.MaxVertexAttribs = mGLMaxVertexAttribs;
         resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
         resources.MaxVaryingVectors = mGLMaxVaryingVectors;
         resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
         resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -357,20 +357,16 @@ WebGLContext::InitAndValidateGL()
     mUniformTextures.Clear();
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
 
     mBoundArrayBuffer = nsnull;
     mBoundElementArrayBuffer = nsnull;
     mCurrentProgram = nsnull;
 
-    mFramebufferColorAttachments.Clear();
-    mFramebufferDepthAttachment = nsnull;
-    mFramebufferStencilAttachment = nsnull;
-
     mBoundFramebuffer = nsnull;
     mBoundRenderbuffer = nsnull;
 
     mMapTextures.Clear();
     mMapBuffers.Clear();
     mMapPrograms.Clear();
     mMapShaders.Clear();
     mMapFramebuffers.Clear();
@@ -428,17 +424,17 @@ WebGLContext::InitAndValidateGL()
 #if 0
     // Leaving this code in here, even though it's ifdef'd out, for
     // when we support more than 1 color attachment.
     gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, (GLint*) &val);
 #else
     // Always 1 for GLES2
     val = 1;
 #endif
-    mFramebufferColorAttachments.SetLength(val);
+    mMaxFramebufferColorAttachments = val;
 
 #if defined(DEBUG_vladimir) && defined(USE_GLES2)
     gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, (GLint*) &val);
     fprintf(stderr, "GL_IMPLEMENTATION_COLOR_READ_FORMAT: 0x%04x\n", val);
 
     gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*) &val);
     fprintf(stderr, "GL_IMPLEMENTATION_COLOR_READ_TYPE: 0x%04x\n", val);
 #endif
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -3557,51 +3557,16 @@ nsCanvasRenderingContext2D::GetGlobalCom
     else CANVAS_OP_TO_THEBES_OP("xor", XOR)
     else return NS_ERROR_FAILURE;
 
 #undef CANVAS_OP_TO_THEBES_OP
 
     return NS_OK;
 }
 
-
-static void
-FlushLayoutForTree(nsIDOMWindow* aWindow)
-{
-    nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
-    if (!piWin)
-        return;
-
-    // Note that because FlushPendingNotifications flushes parents, this
-    // is O(N^2) in docshell tree depth.  However, the docshell tree is
-    // usually pretty shallow.
-
-    nsCOMPtr<nsIDOMDocument> domDoc;
-    aWindow->GetDocument(getter_AddRefs(domDoc));
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
-    if (doc) {
-        doc->FlushPendingNotifications(Flush_Layout);
-    }
-
-    nsCOMPtr<nsIDocShellTreeNode> node =
-        do_QueryInterface(piWin->GetDocShell());
-    if (node) {
-        PRInt32 i = 0, i_end;
-        node->GetChildCount(&i_end);
-        for (; i < i_end; ++i) {
-            nsCOMPtr<nsIDocShellTreeItem> item;
-            node->GetChildAt(i, getter_AddRefs(item));
-            nsCOMPtr<nsIDOMWindow> win = do_GetInterface(item);
-            if (win) {
-                FlushLayoutForTree(win);
-            }
-        }
-    }
-}
-
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY,
                                        float aW, float aH,
                                        const nsAString& aBGColor,
                                        PRUint32 flags)
 {
     NS_ENSURE_ARG(aWindow != nsnull);
 
@@ -3620,17 +3585,17 @@ nsCanvasRenderingContext2D::DrawWindow(n
     if (!nsContentUtils::IsCallerTrustedForRead()) {
       // not permitted to use DrawWindow
       // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_DOM_SECURITY_ERR;
     }
 
     // Flush layout updates
     if (!(flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH))
-        FlushLayoutForTree(aWindow);
+        nsContentUtils::FlushLayoutForTree(aWindow);
 
     nsRefPtr<nsPresContext> presContext;
     nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aWindow);
     if (win) {
         nsIDocShell* docshell = win->GetDocShell();
         if (docshell) {
             docshell->GetPresContext(getter_AddRefs(presContext));
         }
--- a/content/canvas/test/webgl/failing_tests.txt
+++ b/content/canvas/test/webgl/failing_tests.txt
@@ -1,27 +1,22 @@
 conformance/canvas-test.html
 conformance/constants.html
 conformance/context-attributes-alpha-depth-stencil-antialias.html
 conformance/context-attributes.html
 conformance/context-type-test.html
-conformance/framebuffer-object-attachment.html
-conformance/get-active-test.html
-conformance/gl-enum-tests.html
 conformance/gl-get-calls.html
 conformance/gl-teximage.html
 conformance/glsl-conformance.html
 conformance/methods.html
 conformance/program-test.html
 conformance/read-pixels-pack-alignment.html
 conformance/tex-image-and-sub-image-2d-with-video.html
-conformance/tex-image-with-format-and-type.html
 conformance/tex-image-with-invalid-data.html
 conformance/tex-input-validation.html
-conformance/texture-active-bind.html
 more/conformance/constants.html
 more/conformance/getContext.html
 more/conformance/quickCheckAPI.html
 more/conformance/quickCheckAPIBadArgs.html
 more/functions/bufferDataBadArgs.html
 more/functions/copyTexImage2D.html
 more/functions/copyTexImage2DBadArgs.html
 more/functions/copyTexSubImage2D.html
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -1350,35 +1350,16 @@ const char* nsDOMEvent::GetEventName(PRU
   // XXXldb We can hit this case for nsEvent objects that we didn't
   // create and that are not user defined events since this function and
   // SetEventType are incomplete.  (But fixing that requires fixing the
   // arrays in nsEventListenerManager too, since the events for which
   // this is a problem generally *are* created by nsDOMEvent.)
   return nsnull;
 }
 
-nsresult
-nsDOMEvent::ReportWrongPropertyAccessWarning(const char* aPropertyName)
-{
-  nsCOMPtr<nsIDocument> doc(GetDocumentForReport(mEvent));
-
-  nsAutoString propertyName, type;
-  GetType(type);
-  propertyName.AssignASCII(aPropertyName);
-  const PRUnichar *strings[] = { propertyName.get(), type.get() };
-
-  return nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
-                                         "WrongEventPropertyAccessWarning",
-                                         strings, NS_ARRAY_LENGTH(strings),
-                                         doc ? doc->GetDocumentURI() : nsnull,
-                                         EmptyString(), 0, 0,
-                                         nsIScriptError::warningFlag,
-                                         "DOM Events");
-}
-
 NS_IMETHODIMP
 nsDOMEvent::GetPreventDefault(PRBool* aReturn)
 {
   NS_ENSURE_ARG_POINTER(aReturn);
   *aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
   return NS_OK;
 }
 
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -220,17 +220,16 @@ public:
   static void Shutdown();
 
   static const char* GetEventName(PRUint32 aEventType);
 protected:
 
   // Internal helper functions
   nsresult SetEventType(const nsAString& aEventTypeArg);
   already_AddRefed<nsIContent> GetTargetFromFrame();
-  nsresult ReportWrongPropertyAccessWarning(const char* aPropertyName);
 
   nsEvent*                    mEvent;
   nsRefPtr<nsPresContext>     mPresContext;
   nsCOMPtr<nsIDOMEventTarget> mTmpRealOriginalTarget;
   nsIDOMEventTarget*          mExplicitOriginalTarget;
   nsString                    mCachedType;
   PRPackedBool                mEventIsInternal;
   PRPackedBool                mPrivateDataDuplicated;
--- a/content/events/src/nsDOMKeyboardEvent.cpp
+++ b/content/events/src/nsDOMKeyboardEvent.cpp
@@ -109,24 +109,22 @@ nsDOMKeyboardEvent::GetMetaKey(PRBool* a
 NS_IMETHODIMP
 nsDOMKeyboardEvent::GetCharCode(PRUint32* aCharCode)
 {
   NS_ENSURE_ARG_POINTER(aCharCode);
 
   switch (mEvent->message) {
   case NS_KEY_UP:
   case NS_KEY_DOWN:
-    ReportWrongPropertyAccessWarning("charCode");
     *aCharCode = 0;
     break;
   case NS_KEY_PRESS:
     *aCharCode = ((nsKeyEvent*)mEvent)->charCode;
     break;
   default:
-    ReportWrongPropertyAccessWarning("charCode");
     break;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMKeyboardEvent::GetKeyCode(PRUint32* aKeyCode)
 {
@@ -134,17 +132,16 @@ nsDOMKeyboardEvent::GetKeyCode(PRUint32*
 
   switch (mEvent->message) {
   case NS_KEY_UP:
   case NS_KEY_PRESS:
   case NS_KEY_DOWN:
     *aKeyCode = ((nsKeyEvent*)mEvent)->keyCode;
     break;
   default:
-    ReportWrongPropertyAccessWarning("keyCode");
     *aKeyCode = 0;
     break;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -164,17 +161,16 @@ nsDOMKeyboardEvent::GetWhich(PRUint32* a
         if (keyCode == NS_VK_RETURN || keyCode == NS_VK_BACK) {
           *aWhich = keyCode;
           return NS_OK;
         }
         return GetCharCode(aWhich);
       }
       break;
     default:
-      ReportWrongPropertyAccessWarning("which");
       *aWhich = 0;
       break;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -285,18 +285,23 @@ nsUITimerCallback::Notify(nsITimer* aTim
 {
   nsCOMPtr<nsIObserverService> obs =
     mozilla::services::GetObserverService();
   if (!obs)
     return NS_ERROR_FAILURE;
   if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
     gMouseOrKeyboardEventCounter = 0;
     obs->NotifyObservers(nsnull, "user-interaction-inactive", nsnull);
+    if (gUserInteractionTimer) {
+      gUserInteractionTimer->Cancel();
+      NS_RELEASE(gUserInteractionTimer);
+    }
   } else {
     obs->NotifyObservers(nsnull, "user-interaction-active", nsnull);
+    nsEventStateManager::UpdateUserActivityTimer();
   }
   mPreviousCount = gMouseOrKeyboardEventCounter;
   return NS_OK;
 }
 
 enum {
  MOUSE_SCROLL_N_LINES,
  MOUSE_SCROLL_PAGE,
@@ -779,29 +784,40 @@ nsEventStateManager::nsEventStateManager
     mRClickCount(0),
     m_haveShutdown(PR_FALSE),
     mLastLineScrollConsumedX(PR_FALSE),
     mLastLineScrollConsumedY(PR_FALSE),
     mClickHoldContextMenu(PR_FALSE)
 {
   if (sESMInstanceCount == 0) {
     gUserInteractionTimerCallback = new nsUITimerCallback();
-    if (gUserInteractionTimerCallback) {
+    if (gUserInteractionTimerCallback)
       NS_ADDREF(gUserInteractionTimerCallback);
-      CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
-      if (gUserInteractionTimer) {
-        gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
-                                                NS_USER_INTERACTION_INTERVAL,
-                                                nsITimer::TYPE_REPEATING_SLACK);
-      }
-    }
+    UpdateUserActivityTimer();
   }
   ++sESMInstanceCount;
 }
 
+nsresult
+nsEventStateManager::UpdateUserActivityTimer(void)
+{
+  if (!gUserInteractionTimerCallback)
+    return NS_OK;
+
+  if (!gUserInteractionTimer)
+    CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
+
+  if (gUserInteractionTimer) {
+    gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
+                                            NS_USER_INTERACTION_INTERVAL,
+                                            nsITimer::TYPE_ONE_SHOT);
+  }
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsEventStateManager::Init()
 {
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (!observerService)
     return NS_ERROR_FAILURE;
 
@@ -1066,16 +1082,17 @@ nsEventStateManager::PreHandleEvent(nsPr
         aEvent->message != NS_MOUSE_EXIT) ||
        aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ||
        aEvent->eventStructType == NS_KEY_EVENT)) {
     if (gMouseOrKeyboardEventCounter == 0) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       if (obs) {
         obs->NotifyObservers(nsnull, "user-interaction-active", nsnull);
+        UpdateUserActivityTimer();
       }
     }
     ++gMouseOrKeyboardEventCounter;
   }
 
   *aStatus = nsEventStatus_eIgnore;
 
   nsMouseWheelTransaction::OnEvent(aEvent);
@@ -3009,25 +3026,28 @@ nsEventStateManager::PostHandleEvent(nsP
           nsContentUtils::GetBoolPref(sysNumLinesKey.get());
 
         if (useSysNumLines) {
           if (msEvent->scrollFlags & nsMouseScrollEvent::kIsFullPage)
             action = MOUSE_SCROLL_PAGE;
         }
 
         if (aEvent->message == NS_MOUSE_PIXEL_SCROLL) {
-          if (action == MOUSE_SCROLL_N_LINES) {
+          if (action == MOUSE_SCROLL_N_LINES ||
+              (msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
              action = MOUSE_SCROLL_PIXELS;
           } else {
             // Do not scroll pixels when zooming
             action = -1;
           }
         } else if (msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) {
-          if (action == MOUSE_SCROLL_N_LINES) {
-            // We shouldn't scroll lines when a pixel scroll event will follow.
+          if (action == MOUSE_SCROLL_N_LINES ||
+              (msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
+            // Don't scroll lines when a pixel scroll event will follow.
+            // Also, don't do history scrolling or zooming for momentum scrolls.
             action = -1;
           }
         }
 
         switch (action) {
         case MOUSE_SCROLL_N_LINES:
           DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::LINES,
                        useSysNumLines);
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -49,16 +49,18 @@
 #include "nsITimer.h"
 #include "nsCOMPtr.h"
 #include "nsIDocument.h"
 #include "nsCOMArray.h"
 #include "nsIFrame.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsIScrollableFrame.h"
+#include "nsFocusManager.h"
+#include "nsIDocument.h"
 
 class nsIPresShell;
 class nsIDocShell;
 class nsIDocShellTreeNode;
 class nsIDocShellTreeItem;
 class imgIContainer;
 class nsDOMDataTransfer;
 
@@ -399,16 +401,19 @@ protected:
   nsCOMPtr<nsIDocument> mDocument;   // Doesn't necessarily need to be owner
 
   PRUint32 mLClickCount;
   PRUint32 mMClickCount;
   PRUint32 mRClickCount;
 
   PRPackedBool m_haveShutdown;
 
+
+public:
+  static nsresult UpdateUserActivityTimer(void);
   // Array for accesskey support
   nsCOMArray<nsIContent> mAccessKeys;
 
   // Unlocks pixel scrolling
   PRPackedBool mLastLineScrollConsumedX;
   PRPackedBool mLastLineScrollConsumedY;
 
   static PRInt32 sUserInputEventDepth;
@@ -431,41 +436,59 @@ protected:
 
 /**
  * This class is used while processing real user input. During this time, popups
  * are allowed. For mousedown events, mouse capturing is also permitted.
  */
 class nsAutoHandlingUserInputStatePusher
 {
 public:
-  nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput, PRBool aIsMouseDown)
-    : mIsHandlingUserInput(aIsHandlingUserInput), mIsMouseDown(aIsMouseDown)
+  nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput,
+                                     nsEvent* aEvent,
+                                     nsIDocument* aDocument)
+    : mIsHandlingUserInput(aIsHandlingUserInput),
+      mIsMouseDown(aEvent && aEvent->message == NS_MOUSE_BUTTON_DOWN),
+      mResetFMMouseDownState(PR_FALSE)
   {
     if (aIsHandlingUserInput) {
       nsEventStateManager::StartHandlingUserInput();
-      if (aIsMouseDown) {
+      if (mIsMouseDown) {
         nsIPresShell::SetCapturingContent(nsnull, 0);
         nsIPresShell::AllowMouseCapture(PR_TRUE);
+        if (aDocument && NS_IS_TRUSTED_EVENT(aEvent)) {
+          nsFocusManager* fm = nsFocusManager::GetFocusManager();
+          if (fm) {
+            fm->SetMouseButtonDownHandlingDocument(aDocument);
+            mResetFMMouseDownState = PR_TRUE;
+          }
+        }
       }
     }
   }
 
   ~nsAutoHandlingUserInputStatePusher()
   {
     if (mIsHandlingUserInput) {
       nsEventStateManager::StopHandlingUserInput();
       if (mIsMouseDown) {
         nsIPresShell::AllowMouseCapture(PR_FALSE);
+        if (mResetFMMouseDownState) {
+          nsFocusManager* fm = nsFocusManager::GetFocusManager();
+          if (fm) {
+            fm->SetMouseButtonDownHandlingDocument(nsnull);
+          }
+        }
       }
     }
   }
 
 protected:
   PRBool mIsHandlingUserInput;
   PRBool mIsMouseDown;
+  PRBool mResetFMMouseDownState;
 
 private:
   // Hide so that this class can only be stack-allocated
   static void* operator new(size_t /*size*/) CPP_THROW_NEW { return nsnull; }
   static void operator delete(void* /*memory*/) {}
 };
 
 #endif // nsEventStateManager_h__
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -86,16 +86,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug508479.html \
 		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 \
 		$(NULL)
 
 #bug 585630
new file mode 100644
--- /dev/null
+++ b/content/events/test/test_bug574663.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=574663
+-->
+<head>
+  <title>Test for Bug 574663</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/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=574663">Mozilla Bug 574663</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript;version=1.7">
+
+/** Test for Bug 574663 **/
+
+// This test depends on general.smoothScroll being off.
+
+function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum) {
+  var win = scrollbox.ownerDocument.defaultView;
+  let event = {
+    'type': "DOMMouseScroll",
+    'axis': "vertical",
+    'delta': direction,
+    'hasPixels': true,
+    'ctrlKey': ctrl,
+    'isMomentum': momentum,
+  };
+  // first a line scroll
+  synthesizeMouseScroll(scrollbox, 10, 10, event, win);
+  // then 5 pixel scrolls
+  event.delta *= 3;
+  event.type = "MozMousePixelScroll";
+  event.hasPixels = false;
+  for (let i = 0; i < 5; ++i) {
+    synthesizeMouseScroll(scrollbox, 10, 10, event, win);
+  }
+}
+
+function runTest() {
+  var win = open('data:text/html,<!DOCTYPE html>\n' +
+    '<div id="scrollbox" style="height: 100px; overflow: auto;">' +
+    '  <div style="height: 1000px;"></div>' +
+    '</div>', '_blank', 'width=300,height=300');
+  SimpleTest.waitForFocus(function () {
+    var scrollbox = win.document.getElementById("scrollbox");
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    let winUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    let outstandingTests = [
+      [false, false],
+      [false, true],
+      [true, false],
+      [true, true],
+    ];
+    function nextTest() {
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      if (!outstandingTests.length) {
+        win.close();
+        clearPrefs();
+        SimpleTest.finish();
+        return;
+      }
+
+      let [ctrlKey, isMomentum] = outstandingTests.shift();
+      let scrollTopBefore = scrollbox.scrollTop;
+      let zoomFactorBefore = winUtils.screenPixelsPerCSSPixel;
+      sendTouchpadScrollMotion(scrollbox, 1, ctrlKey, isMomentum);
+
+      setTimeout(function () {
+        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+        if (!ctrlKey) {
+          let postfix = isMomentum ? ", even after releasing the touchpad" : "";
+          // Normal scroll: scroll
+          is(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Normal scrolling shouldn't change zoom" + postfix);
+          isnot(scrollbox.scrollTop, scrollTopBefore, "Normal scrolling should scroll" + postfix);
+        } else {
+          if (!isMomentum) {
+            isnot(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Ctrl-scrolling should zoom while the user is touching the touchpad");
+            is(scrollbox.scrollTop, scrollTopBefore, "Ctrl-scrolling shouldn't scroll while the user is touching the touchpad");
+          } else {
+            is(winUtils.screenPixelsPerCSSPixel, zoomFactorBefore, "Momentum scrolling shouldn't zoom, even when pressing Ctrl");
+            isnot(scrollbox.scrollTop, scrollTopBefore, "Momentum scrolling should scroll, even when pressing Ctrl");
+          }
+        }
+        // Revert the effect.
+        sendTouchpadScrollMotion(scrollbox, -1, ctrlKey, isMomentum);
+        setTimeout(nextTest, 0);
+      }, 0);
+    }
+    nextTest();
+  }, win);
+}
+
+function initPrefs()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
+                  getService(Components.interfaces.nsIPrefBranch2);
+  // Disables the app level scroll acceleration
+  prefSvc.setIntPref("mousewheel.acceleration.start", -1);
+  prefSvc.setBoolPref("mousewheel.system_scroll_override_on_root_content.enabled", false);
+}
+
+function clearPrefs()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
+                  getService(Components.interfaces.nsIPrefBranch2);
+
+  if (prefSvc.prefHasUserValue("mousewheel.acceleration.start"))
+    prefSvc.clearUserPref("mousewheel.acceleration.start");
+  if (prefSvc.prefHasUserValue("mousewheel.system_scroll_override_on_root_content.enabled"))
+    prefSvc.clearUserPref("mousewheel.system_scroll_override_on_root_content.enabled");
+}
+
+window.onload = function () {
+  initPrefs();
+  SimpleTest.executeSoon(runTest);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+
+</body>
+</html>
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2100,16 +2100,39 @@ nsGenericHTMLElement::SetIntAttr(nsIAtom
 {
   nsAutoString value;
   value.AppendInt(aValue);
 
   return SetAttr(kNameSpaceID_None, aAttr, value, PR_TRUE);
 }
 
 nsresult
+nsGenericHTMLElement::GetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aDefault,
+                                         PRUint32* aResult)
+{
+  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
+  if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
+    *aResult = attrVal->GetIntegerValue();
+  }
+  else {
+    *aResult = aDefault;
+  }
+  return NS_OK;
+}
+
+nsresult
+nsGenericHTMLElement::SetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aValue)
+{
+  nsAutoString value;
+  value.AppendInt(aValue);
+
+  return SetAttr(kNameSpaceID_None, aAttr, value, PR_TRUE);
+}
+
+nsresult
 nsGenericHTMLElement::GetFloatAttr(nsIAtom* aAttr, float aDefault, float* aResult)
 {
   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
   if (attrVal && attrVal->Type() == nsAttrValue::eFloatValue) {
     *aResult = attrVal->GetFloatValue();
   }
   else {
     *aResult = aDefault;
@@ -2317,16 +2340,20 @@ nsGenericHTMLFormElement::nsGenericHTMLF
   : nsGenericHTMLElement(aNodeInfo)
   , mForm(nsnull)
   , mFieldSet(nsnull)
 {
 }
 
 nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
 {
+  if (mFieldSet) {
+    static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
+  }
+
   // Check that this element doesn't know anything about its form at this point.
   NS_ASSERTION(!mForm, "mForm should be null at this point!");
 }
 
 NS_IMPL_QUERY_INTERFACE_INHERITED1(nsGenericHTMLFormElement,
                                    nsGenericHTMLElement,
                                    nsIFormControl)
 
@@ -2934,23 +2961,30 @@ nsGenericHTMLFormElement::UpdateFieldSet
 
   for (parent = GetParent(); parent;
        prev = parent, parent = parent->GetParent()) {
     if (parent->IsHTML(nsGkAtoms::fieldset)) {
       nsHTMLFieldSetElement* fieldset =
         static_cast<nsHTMLFieldSetElement*>(parent);
 
       if (!prev || fieldset->GetFirstLegend() != prev) {
+        if (mFieldSet) {
+          static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
+        }
         mFieldSet = fieldset;
+        fieldset->AddElement(this);
         return;
       }
     }
   }
 
   // No fieldset found.
+  if (mFieldSet) {
+    static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
+  }
   mFieldSet = nsnull;
 }
 
 void
 nsGenericHTMLFormElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
 {
   if (!aNotify) {
     return;
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -649,16 +649,39 @@ protected:
    * in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Integer value of attribute.
    */
   NS_HIDDEN_(nsresult) SetIntAttr(nsIAtom* aAttr, PRInt32 aValue);
 
   /**
+   * Helper method for NS_IMPL_UINT_ATTR macro.
+   * Gets the unsigned integer-value of an attribute, returns specified default
+   * value if the attribute isn't set or isn't set to an integer. Only works for
+   * attributes in null namespace.
+   *
+   * @param aAttr    name of attribute.
+   * @param aDefault default-value to return if attribute isn't set.
+   * @param aResult  result value [out]
+   */
+  NS_HIDDEN_(nsresult) GetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aDefault,
+                                          PRUint32* aValue);
+
+  /**
+   * Helper method for NS_IMPL_UINT_ATTR macro.
+   * Sets value of attribute to specified unsigned integer. Only works for
+   * attributes in null namespace.
+   *
+   * @param aAttr    name of attribute.
+   * @param aValue   Integer value of attribute.
+   */
+  NS_HIDDEN_(nsresult) SetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aValue);
+
+  /**
    * Helper method for NS_IMPL_FLOAT_ATTR macro.
    * Gets the float-value of an attribute, returns specified default value
    * if the attribute isn't set or isn't set to a float. Only works for
    * attributes in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aDefault default-value to return if attribute isn't set.
    * @param aResult  result value [out]
@@ -870,16 +893,29 @@ public:
     UpdateFieldSet();
 
     // The disabled state may have change because the element might not be in
     // the first legend anymore.
     FieldSetDisabledChanged(nsEventStates(), aNotify);
   }
 
   /**
+   * This callback is called by a fieldset on all it's elements when it's being
+   * destroyed. When called, the elements should check that aFieldset is there
+   * first parent fieldset and null mFieldset in that case only.
+   *
+   * @param aFieldSet The fieldset being removed.
+   */
+  void ForgetFieldSet(nsIContent* aFieldset) {
+    if (mFieldSet == aFieldset) {
+      mFieldSet = nsnull;
+    }
+  }
+
+  /**
    * Returns if the control can be disabled.
    */
   PRBool CanBeDisabled() const;
 
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
 
@@ -1112,16 +1148,60 @@ protected:
   }                                                                       \
   NS_IMETHODIMP                                                           \
   _class::Set##_method(PRInt32 aValue)                                    \
   {                                                                       \
     return SetIntAttr(nsGkAtoms::_atom, aValue);                        \
   }
 
 /**
+ * A macro to implement the getter and setter for a given unsigned integer
+ * valued content property. The method uses GetUnsignedIntAttr and
+ * SetUnsignedIntAttr methods.
+ */
+#define NS_IMPL_UINT_ATTR(_class, _method, _atom)                         \
+  NS_IMPL_UINT_ATTR_DEFAULT_VALUE(_class, _method, _atom, 0)
+
+#define NS_IMPL_UINT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default) \
+  NS_IMETHODIMP                                                           \
+  _class::Get##_method(PRUint32* aValue)                                  \
+  {                                                                       \
+    return GetUnsignedIntAttr(nsGkAtoms::_atom, _default, aValue);        \
+  }                                                                       \
+  NS_IMETHODIMP                                                           \
+  _class::Set##_method(PRUint32 aValue)                                   \
+  {                                                                       \
+    return SetUnsignedIntAttr(nsGkAtoms::_atom, aValue);                  \
+  }
+
+/**
+ * A macro to implement the getter and setter for a given unsigned integer
+ * valued content property. The method uses GetUnsignedIntAttr and
+ * SetUnsignedIntAttr methods. This macro is similar to NS_IMPL_UINT_ATTR except
+ * that it throws an exception if the set value is null.
+ */
+#define NS_IMPL_UINT_ATTR_NON_ZERO(_class, _method, _atom)                \
+  NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(_class, _method, _atom, 1)
+
+#define NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(_class, _method, _atom, _default) \
+  NS_IMETHODIMP                                                           \
+  _class::Get##_method(PRUint32* aValue)                                  \
+  {                                                                       \
+    return GetUnsignedIntAttr(nsGkAtoms::_atom, _default, aValue);        \
+  }                                                                       \
+  NS_IMETHODIMP                                                           \
+  _class::Set##_method(PRUint32 aValue)                                   \
+  {                                                                       \
+    if (aValue == 0) {                                                    \
+      return NS_ERROR_DOM_INDEX_SIZE_ERR;                                 \
+    }                                                                     \
+    return SetUnsignedIntAttr(nsGkAtoms::_atom, aValue);                  \
+  }
+
+/**
  * A macro to implement the getter and setter for a given float
  * valued content property. The method uses the generic GetAttr and
  * SetAttr methods.
  */
 #define NS_IMPL_FLOAT_ATTR(_class, _method, _atom)                    \
   NS_IMPL_FLOAT_ATTR_DEFAULT_VALUE(_class, _method, _atom, 0.0)
 
 #define NS_IMPL_FLOAT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default)  \
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -368,18 +368,17 @@ nsHTMLCanvasElement::MozGetAsFileImpl(co
 }
 
 nsresult
 nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
                                       nsICanvasRenderingContextInternal **aContext)
 {
   NS_ENSURE_ARG(aContext);
 
-  nsCString ctxId;
-  ctxId.Assign(NS_LossyConvertUTF16toASCII(aContextId));
+  NS_LossyConvertUTF16toASCII ctxId(aContextId);
 
   // check that ctxId is clamped to A-Za-z0-9_-
   for (PRUint32 i = 0; i < ctxId.Length(); i++) {
     if ((ctxId[i] < 'A' || ctxId[i] > 'Z') &&
         (ctxId[i] < 'a' || ctxId[i] > 'z') &&
         (ctxId[i] < '0' || ctxId[i] > '9') &&
         (ctxId[i] != '-') &&
         (ctxId[i] != '_'))
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -53,16 +53,20 @@ nsHTMLFieldSetElement::nsHTMLFieldSetEle
   , mFirstLegend(nsnull)
 {
   // <fieldset> is always barred from constraint validation.
   SetBarredFromConstraintValidation(PR_TRUE);
 }
 
 nsHTMLFieldSetElement::~nsHTMLFieldSetElement()
 {
+  PRUint32 length = mDependentElements.Length();
+  for (PRUint32 i=0; i<length; ++i) {
+    mDependentElements[i]->ForgetFieldSet(this);
+  }
 }
 
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHTMLFieldSetElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mElements)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
--- a/content/html/content/src/nsHTMLFieldSetElement.h
+++ b/content/html/content/src/nsHTMLFieldSetElement.h
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsHTMLFieldSetElement_h___
 #define nsHTMLFieldSetElement_h___
 
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLFieldSetElement.h"
 #include "nsIConstraintValidation.h"
+#include "nsTPtrArray.h"
 
 
 class nsHTMLFieldSetElement : public nsGenericHTMLFormElement,
                               public nsIDOMHTMLFieldSetElement,
                               public nsIConstraintValidation
 {
 public:
   using nsIConstraintValidation::GetValidationMessage;
@@ -82,16 +83,24 @@ public:
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_FIELDSET; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
 
   const nsIContent* GetFirstLegend() const { return mFirstLegend; }
 
+  void AddElement(nsGenericHTMLFormElement* aElement) {
+    mDependentElements.AppendElement(aElement);
+  }
+
+  void RemoveElement(nsGenericHTMLFormElement* aElement) {
+    mDependentElements.RemoveElement(aElement);
+  }
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLFieldSetElement,
                                            nsGenericHTMLFormElement)
 private:
 
   /**
    * Notify all elements (in mElements) that the first legend of the fieldset
    * has now changed.
    */
@@ -99,13 +108,16 @@ private:
 
   // This function is used to generate the nsContentList (listed form elements).
   static PRBool MatchListedElements(nsIContent* aContent, PRInt32 aNamespaceID,
                                     nsIAtom* aAtom, void* aData);
 
   // listed form controls elements.
   nsRefPtr<nsContentList> mElements;
 
+  // List of elements which have this fieldset as first fieldset ancestor.
+  nsTPtrArray<nsGenericHTMLFormElement> mDependentElements;
+
   nsIContent* mFirstLegend;
 };
 
 #endif /* nsHTMLFieldSetElement_h___ */
 
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -876,17 +876,19 @@ nsHTMLFormElement::SubmitSubmission(nsFo
   //
   // Submit
   //
   nsCOMPtr<nsIDocShell> docShell;
 
   {
     nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
 
-    nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput, PR_FALSE);
+    nsAutoHandlingUserInputStatePusher userInpStatePusher(
+                                         mSubmitInitiatedFromUserInput,
+                                         nsnull, doc);
 
     nsCOMPtr<nsIInputStream> postDataStream;
     rv = aFormSubmission->GetEncodedSubmission(actionURI,
                                                getter_AddRefs(postDataStream));
     NS_ENSURE_SUBMIT_SUCCESS(rv);
 
     rv = linkHandler->OnLinkClickSync(this, actionURI,
                                       target.get(),
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -16,16 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Pierre Phaneuf <pp@ludusdesign.com>
+ *   Geoff Lankow <geoff@darktrojan.net>
  *
  * 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
@@ -535,16 +536,19 @@ UploadLastDir::FetchLastUsedDirectory(ns
 
 nsresult
 UploadLastDir::StoreLastUsedDirectory(nsIURI* aURI, nsILocalFile* aFile)
 {
   NS_PRECONDITION(aURI, "aURI is null");
   NS_PRECONDITION(aFile, "aFile is null");
   nsCOMPtr<nsIFile> parentFile;
   aFile->GetParent(getter_AddRefs(parentFile));
+  if (!parentFile) {
+    return NS_OK;
+  }
   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(parentFile);
 
   // Store the data in memory instead of the CPS during private browsing mode
   if (mInPrivateBrowsing) {
     nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
       do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
     if (!hostnameGrouperService)
       return NS_ERROR_NOT_AVAILABLE;
@@ -972,17 +976,17 @@ NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Mu
 NS_IMPL_NON_NEGATIVE_INT_ATTR(nsHTMLInputElement, MaxLength, maxlength)
 NS_IMPL_STRING_ATTR(nsHTMLInputElement, Name, name)
 NS_IMPL_BOOL_ATTR(nsHTMLInputElement, ReadOnly, readonly)
 NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Required, required)
 NS_IMPL_URI_ATTR(nsHTMLInputElement, Src, src)
 NS_IMPL_INT_ATTR(nsHTMLInputElement, TabIndex, tabindex)
 NS_IMPL_STRING_ATTR(nsHTMLInputElement, UseMap, usemap)
 //NS_IMPL_STRING_ATTR(nsHTMLInputElement, Value, value)
-//NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Size, size, 0)
+NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(nsHTMLInputElement, Size, size, DEFAULT_COLS)
 NS_IMPL_STRING_ATTR(nsHTMLInputElement, Pattern, pattern)
 NS_IMPL_STRING_ATTR(nsHTMLInputElement, Placeholder, placeholder)
 NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Type, type,
                                 kInputDefaultType->tag)
 
 NS_IMETHODIMP
 nsHTMLInputElement::GetIndeterminate(PRBool* aValue)
 {
@@ -1014,39 +1018,16 @@ nsHTMLInputElement::SetIndeterminateInte
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetIndeterminate(PRBool aValue)
 {
   return SetIndeterminateInternal(aValue, PR_TRUE);
 }
 
-NS_IMETHODIMP
-nsHTMLInputElement::GetSize(PRUint32* aValue)
-{
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::size);
-  if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
-    *aValue = attrVal->GetIntegerValue();
-  }
-  else {
-    *aValue = 0;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHTMLInputElement::SetSize(PRUint32 aValue)
-{
-  nsAutoString val;
-  val.AppendInt(aValue);
-
-  return SetAttr(kNameSpaceID_None, nsGkAtoms::size, val, PR_TRUE);
-}
-
 NS_IMETHODIMP 
 nsHTMLInputElement::GetValue(nsAString& aValue)
 {
   nsTextEditorState* state = GetEditorState();
   if (state) {
     state->GetValue(aValue, PR_TRUE);
     return NS_OK;
   }
@@ -2686,17 +2667,17 @@ nsHTMLInputElement::ParseAttribute(PRInt
     }
     if (aAttribute == nsGkAtoms::height) {
       return aResult.ParseSpecialIntValue(aValue, PR_TRUE);
     }
     if (aAttribute == nsGkAtoms::maxlength) {
       return aResult.ParseNonNegativeIntValue(aValue);
     }
     if (aAttribute == nsGkAtoms::size) {
-      return aResult.ParseIntWithBounds(aValue, 0);
+      return aResult.ParsePositiveIntValue(aValue);
     }
     if (aAttribute == nsGkAtoms::border) {
       return aResult.ParseIntWithBounds(aValue, 0);
     }
     if (aAttribute == nsGkAtoms::align) {
       return ParseAlignValue(aValue, aResult);
     }
     if (aAttribute == nsGkAtoms::formmethod) {
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -222,17 +222,17 @@ public:
   NS_IMETHOD Run() {
     // Silently cancel if our load has been cancelled.
     if (IsCancelled())
       return NS_OK;
     LOG_EVENT(PR_LOG_DEBUG, ("%p Dispatching simple event source error", mElement.get()));
     return nsContentUtils::DispatchTrustedEvent(mElement->GetOwnerDoc(),
                                                 mSource,
                                                 NS_LITERAL_STRING("error"),
-                                                PR_TRUE,
+                                                PR_FALSE,
                                                 PR_TRUE);
   }
 };
 
 /**
  * There is a reference cycle involving this class: MediaLoadListener
  * holds a reference to the nsHTMLMediaElement, which holds a reference
  * to an nsIChannel, which holds a reference to this listener.
@@ -2261,17 +2261,17 @@ nsresult nsHTMLMediaElement::DispatchEve
   if (mPausedForInactiveDocument) {
     mPendingEvents.AppendElement(aName);
     return NS_OK;
   }
 
   return nsContentUtils::DispatchTrustedEvent(GetOwnerDoc(),
                                               static_cast<nsIContent*>(this),
                                               aName,
-                                              PR_TRUE,
+                                              PR_FALSE,
                                               PR_TRUE);
 }
 
 nsresult nsHTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
 {
   LOG_EVENT(PR_LOG_DEBUG, ("%p Queuing event %s", this,
             NS_ConvertUTF16toUTF8(aName).get()));
 
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -1212,18 +1212,17 @@ nsHTMLSelectElement::SetValue(const nsAS
   return rv;
 }
 
 
 NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Autofocus, autofocus)
 NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Disabled, disabled)
 NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Multiple, multiple)
 NS_IMPL_STRING_ATTR(nsHTMLSelectElement, Name, name)
-NS_IMPL_POSITIVE_INT_ATTR_DEFAULT_VALUE(nsHTMLSelectElement, Size, size,
-                                        GetDefaultSize())
+NS_IMPL_POSITIVE_INT_ATTR_DEFAULT_VALUE(nsHTMLSelectElement, Size, size, 0)
 NS_IMPL_INT_ATTR(nsHTMLSelectElement, TabIndex, tabindex)
 
 NS_IMETHODIMP
 nsHTMLSelectElement::Blur()
 {
   return nsGenericHTMLElement::Blur();
 }
 
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -490,24 +490,16 @@ protected:
   void VerifyOptionsArray();
 #endif
 
   virtual PRBool AcceptAutofocus() const
   {
     return PR_TRUE;
   }
 
-  /**
-   * Helper method to get the default size.
-   */
-  PRInt32 GetDefaultSize() const
-  {
-    return HasAttr(kNameSpaceID_None, nsGkAtoms::multiple) ? 4 : 1;
-  }
-
   /** The options[] array */
   nsRefPtr<nsHTMLOptionCollection> mOptions;
   /** false if the parser is in the middle of adding children. */
   PRPackedBool    mIsDoneAddingChildren;
   /** true if our disabled state has changed from the default **/
   PRPackedBool    mDisabledChanged;
   /** true if child nodes are being added or removed.
    *  Used by nsSafeOptionListMutation.
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp
+++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp
@@ -180,16 +180,17 @@ NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER
 
 
 nsHTMLSharedObjectElement::nsHTMLSharedObjectElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                                                      FromParser aFromParser)
   : nsGenericHTMLElement(aNodeInfo),
     mIsDoneAddingChildren(mNodeInfo->Equals(nsGkAtoms::embed) || !aFromParser)
 {
   RegisterFreezableElement();
+  SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
 }
 
 nsHTMLSharedObjectElement::~nsHTMLSharedObjectElement()
 {
   UnregisterFreezableElement();
   DestroyImageLoadingContent();
 }
 
@@ -450,16 +451,17 @@ nsHTMLSharedObjectElement::StartObjectLo
     // Be sure to call the nsIURI version if we have no attribute
     // That handles the case where no URI is specified. An empty string would
     // get interpreted as the page itself, instead of absence of URI.
     LoadObject(nsnull, aNotify, type);
   }
   else {
     LoadObject(uri, aNotify, type);
   }
+  SetIsNetworkCreated(PR_FALSE);
 }
 
 nsEventStates
 nsHTMLSharedObjectElement::IntrinsicState() const
 {
   return nsGenericHTMLElement::IntrinsicState() | ObjectState();
 }
 
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -234,12 +234,14 @@ include $(topsrcdir)/config/rules.mk
 		test_bug598643.html \
 		test_bug596350.html \
 		test_bug600155.html \
 		test_bug556007.html \
 		test_bug606817.html \
 		test_bug297761.html \
 		file_bug297761.html \
 		test_bug607145.html \
+		test_bug601061.html \
+		reflect.js \
 		$(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/reflect.js
@@ -0,0 +1,95 @@
+/**
+ * Checks that a given attribute name for a given element is correctly reflected
+ * as an unsigned int.
+ */
+function reflectUnsignedInt(aElement, aAttr, aNonNull, aDefault)
+{
+  function checkGetter(aElement, aAttr, aValue)
+  {
+    is(aElement[aAttr], aValue, "." + aAttr + " should be equals " + aValue);
+    is(aElement.getAttribute(aAttr), aValue,
+       "@" + aAttr + " should be equals " + aValue);
+  }
+
+  if (!aDefault) {
+    if (aNonNull) {
+      aDefault = 1;
+    } else {
+      aDefault = 0;
+    }
+  }
+
+  // Check default value.
+  is(aElement[aAttr], aDefault, "default value should be " + aDefault);
+  ok(!aElement.hasAttribute(aAttr), aAttr + " shouldn't be present");
+
+  var values = [ 1, 3, 42, 2147483647 ];
+
+  for each (var value in values) {
+    aElement[aAttr] = value;
+    checkGetter(aElement, aAttr, value);
+  }
+
+  for each (var value in values) {
+    aElement.setAttribute(aAttr, value);
+    checkGetter(aElement, aAttr, value);
+  }
+
+  // -3000000000 is equivalent to 1294967296 when using the IDL attribute.
+  aElement[aAttr] = -3000000000;
+  checkGetter(aElement, aAttr, 1294967296);
+  // When setting the content atribute, it's a string so it will be unvalid.
+  aElement.setAttribute(aAttr, -3000000000);
+  is(aElement.getAttribute(aAttr), -3000000000,
+     "@" + aAttr + " should be equals to " + -3000000000);
+  is(aElement[aAttr], aDefault,
+     "." + aAttr + " should be equals to " + aDefault);
+
+  var nonValidValues = [
+    /* invalid value, value in the unsigned int range */
+    [ -2147483648, 2147483648 ],
+    [ -1,          4294967295 ],
+    [ 3147483647,  3147483647 ],
+  ];
+
+  for each (var values in nonValidValues) {
+    aElement[aAttr] = values[0];
+    is(aElement.getAttribute(aAttr), values[1],
+       "@" + aAttr + " should be equals to " + values[1]);
+    is(aElement[aAttr], aDefault,
+       "." + aAttr + " should be equals to " + aDefault);
+  }
+
+  for each (var values in nonValidValues) {
+    aElement.setAttribute(aAttr, values[0]);
+    is(aElement.getAttribute(aAttr), values[0],
+       "@" + aAttr + " should be equals to " + values[0]);
+    is(aElement[aAttr], aDefault,
+       "." + aAttr + " should be equals to " + aDefault);
+  }
+
+  // Setting to 0 should throw an error if aNonNull is true.
+  var caught = false;
+  try {
+    aElement[aAttr] = 0;
+  } catch(e) {
+    caught = true;
+    is(e.code, DOMException.INDEX_SIZE_ERR, "exception should be INDEX_SIZE_ERR");
+  }
+
+  if (aNonNull) {
+    ok(caught, "an exception should have been caught");
+  } else {
+    ok(!caught, "no exception should have been caught");
+  }
+
+  // If 0 is set in @aAttr, it will be ignored when calling .aAttr.
+  aElement.setAttribute(aAttr, 0);
+  is(aElement.getAttribute(aAttr), 0, "@" + aAttr + " should be equals to 0");
+  if (aNonNull) {
+    is(aElement[aAttr], aDefault,
+       "." + aAttr + " should be equals to " + aDefault);
+  } else {
+    is(aElement[aAttr], 0, "." + aAttr + " should be equals to 0");
+  }
+}
--- a/content/html/content/test/test_bug430392.html
+++ b/content/html/content/test/test_bug430392.html
@@ -9,21 +9,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=430392">Mozilla Bug 430392</a>
 <p id="display"></p>
 <div id="content">
-  <div contenteditable="true" id="edit">
-    <span contenteditable="false">A</span> ;
-    <span contenteditable="false">B</span> ;
-    <span contenteditable="false">C</span>
-  </div>
+  <div contenteditable="true" id="edit"> <span contenteditable="false">A</span> ; <span contenteditable="false">B</span> ; <span contenteditable="false">C</span> </div>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 430392 **/
 
 function test() {
   var edit = document.getElementById("edit");
--- a/content/html/content/test/test_bug551846.html
+++ b/content/html/content/test/test_bug551846.html
@@ -117,43 +117,43 @@ function checkSetSizeException(element)
     caught = true;
   }
   ok(!caught, "Setting an invalid size in the content attribute shouldn't throw an exception");
 
   // reverting to defalut
   element.removeAttribute('size');
 }
 
-function checkSizeWhenChangeMultiple(element)
+function checkSizeWhenChangeMultiple(element, aDefaultNonMultiple, aDefaultMultiple)
 {
   s.setAttribute('size', -1)
-  is(s.size, 1, "Size IDL attribute should be 1");
+  is(s.size, aDefaultNonMultiple, "Size IDL attribute should be 1");
 
   s.multiple = true;
-  is(s.size, 4, "Size IDL attribute should be 4");
+  is(s.size, aDefaultMultiple, "Size IDL attribute should be 4");
 
   is(s.getAttribute('size'), -1, "Size content attribute should be -1");
 
   s.setAttribute('size', -2);
-  is(s.size, 4, "Size IDL attribute should be 4");
+  is(s.size, aDefaultMultiple, "Size IDL attribute should be 4");
 
   s.multiple = false;
-  is(s.size, 1, "Size IDL attribute should be 1");
+  is(s.size, aDefaultNonMultiple, "Size IDL attribute should be 1");
 
   is(s.getAttribute('size'), -2, "Size content attribute should be -2");
 }
 
 var s = document.getElementById('s');
 
-checkSizeReflection(s, 1);
+checkSizeReflection(s, 0);
 checkSetSizeException(s);
 
 s.setAttribute('multiple', 'true');
-checkSizeReflection(s, 4);
+checkSizeReflection(s, 0);
 checkSetSizeException(s);
 s.removeAttribute('multiple');
 
-checkSizeWhenChangeMultiple(s);
+checkSizeWhenChangeMultiple(s, 0, 0);
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug601061.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=601061
+-->
+<head>
+  <title>Test for Bug 601061</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="reflect.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=601061">Mozilla Bug 601061</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 601061 **/
+
+reflectUnsignedInt(document.createElement("input"), "size", true, 20);
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -214,16 +214,37 @@ ReportUseOfDeprecatedMethod(nsHTMLDocume
                                   nsnull, 0,
                                   static_cast<nsIDocument*>(aDoc)->
                                     GetDocumentURI(),
                                   EmptyString(), 0, 0,
                                   nsIScriptError::warningFlag,
                                   "DOM Events");
 }
 
+static nsresult
+RemoveFromAgentSheets(nsCOMArray<nsIStyleSheet> &aAgentSheets, const nsAString& url)
+{
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  for (PRInt32 i = aAgentSheets.Count() - 1; i >= 0; --i) {
+    nsIStyleSheet* sheet = aAgentSheets[i];
+    nsIURI* sheetURI = sheet->GetSheetURI();
+
+    PRBool equals = PR_FALSE;
+    uri->Equals(sheetURI, &equals);
+    if (equals) {
+      aAgentSheets.RemoveObjectAt(i);
+    }
+  }
+
+  return NS_OK;
+}
+
 nsresult
 NS_NewHTMLDocument(nsIDocument** aInstancePtrResult)
 {
   nsHTMLDocument* doc = new nsHTMLDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(doc);
   nsresult rv = doc->Init();
@@ -462,58 +483,16 @@ nsHTMLDocument::TryCacheCharset(nsICachi
     aCharsetSource = kCharsetFromCache;
 
     return PR_TRUE;
   }
 
   return PR_FALSE;
 }
 
-PRBool
-nsHTMLDocument::TryBookmarkCharset(nsIDocShell* aDocShell,
-                                   nsIChannel* aChannel,
-                                   PRInt32& aCharsetSource,
-                                   nsACString& aCharset)
-{
-  if (kCharsetFromBookmarks <= aCharsetSource) {
-    return PR_TRUE;
-  }
-
-  if (!aChannel) {
-    return PR_FALSE;
-  }
-
-  nsCOMPtr<nsICharsetResolver> bookmarksResolver =
-    do_GetService("@mozilla.org/embeddor.implemented/bookmark-charset-resolver;1");
-
-  if (!bookmarksResolver) {
-    return PR_FALSE;
-  }
-
-  PRBool wantCharset;         // ignored for now
-  nsCAutoString charset;
-  nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aDocShell));
-  nsCOMPtr<nsISupports> closure;
-  nsresult rv = bookmarksResolver->RequestCharset(webNav,
-                                                  aChannel,
-                                                  &wantCharset,
-                                                  getter_AddRefs(closure),
-                                                  charset);
-  // FIXME: Bug 337970
-  NS_ASSERTION(!wantCharset, "resolved charset notification not implemented!");
-
-  if (NS_SUCCEEDED(rv) && !charset.IsEmpty()) {
-    aCharset = charset;
-    aCharsetSource = kCharsetFromBookmarks;
-    return PR_TRUE;
-  }
-
-  return PR_FALSE;
-}
-
 static PRBool
 CheckSameOrigin(nsINode* aNode1, nsINode* aNode2)
 {
   NS_PRECONDITION(aNode1, "Null node?");
   NS_PRECONDITION(aNode2, "Null node?");
 
   PRBool equal;
   return
@@ -875,20 +854,16 @@ nsHTMLDocument::StartDocumentLoad(const 
 
       // Don't actually get the charset from the channel if this is a
       // wyciwyg channel; it'll always be UTF-16
       if (!wyciwygChannel &&
           TryChannelCharset(aChannel, charsetSource, charset)) {
         // Use the channel's charset (e.g., charset from HTTP
         // "Content-Type" header).
       }
-      else if (!scheme.EqualsLiteral("about") &&          // don't try to access bookmarks for about:blank
-               TryBookmarkCharset(docShell, aChannel, charsetSource, charset)) {
-        // Use the bookmark's charset.
-      }
       else if (cachingChan && !urlSpec.IsEmpty() &&
                TryCacheCharset(cachingChan, charsetSource, charset)) {
         // Use the cache's charset.
       }
       else if (TryDefaultCharset(muCV, charsetSource, charset)) {
         // Use the default charset.
         // previous document charset might be inherited as default charset.
       }
@@ -3156,22 +3131,30 @@ NotifyEditableStateChange(nsINode *aNode
 
 void
 nsHTMLDocument::TearingDownEditor(nsIEditor *aEditor)
 {
   if (IsEditingOn()) {
     EditingState oldState = mEditingState;
     mEditingState = eTearingDown;
 
-    nsCOMPtr<nsIEditorStyleSheets> editorss = do_QueryInterface(aEditor);
-    if (editorss) {
-      editorss->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
-      if (oldState == eDesignMode)
-        editorss->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/designmode.css"));
-    }
+    nsCOMPtr<nsIPresShell> presShell = GetShell();
+    if (!presShell)
+      return;
+
+    nsCOMArray<nsIStyleSheet> agentSheets;
+    presShell->GetAgentStyleSheets(agentSheets);
+
+    RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
+    if (oldState == eDesignMode)
+      RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
+
+    presShell->SetAgentStyleSheets(agentSheets);
+
+    presShell->ReconstructStyleData();
   }
 }
 
 nsresult
 nsHTMLDocument::TurnEditingOff()
 {
   NS_ASSERTION(mEditingState != eOff, "Editing is already off.");
 
@@ -3287,52 +3270,79 @@ nsHTMLDocument::EditingStateChanged()
     nsCOMPtr<nsIEditorDocShell> editorDocShell =
       do_QueryInterface(docshell, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     editorDocShell->GetEditor(getter_AddRefs(editor));
     if (!editor)
       return NS_ERROR_FAILURE;
 
-    nsCOMPtr<nsIEditorStyleSheets> editorss = do_QueryInterface(editor, &rv);
+    nsCOMPtr<nsIPresShell> presShell = GetShell();
+    NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
+
+    nsCOMArray<nsIStyleSheet> agentSheets;
+    rv = presShell->GetAgentStyleSheets(agentSheets);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    editorss->AddOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
+    nsCOMPtr<nsIURI> uri;
+    rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsRefPtr<nsCSSStyleSheet> sheet;
+    rv = LoadChromeSheetSync(uri, PR_TRUE, getter_AddRefs(sheet));
+    NS_ENSURE_TRUE(sheet, rv);
+
+    rv = agentSheets.AppendObject(sheet);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     // Should we update the editable state of all the nodes in the document? We
     // need to do this when the designMode value changes, as that overrides
     // specific states on the elements.
     if (designMode) {
       // designMode is being turned on (overrides contentEditable).
-      editorss->AddOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/designmode.css"));
-
-      // We need to flush styles here because we're setting an XBL binding in
-      // designmode.css.
-      FlushPendingNotifications(Flush_Style);
+      rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/designmode.css"));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = LoadChromeSheetSync(uri, PR_TRUE, getter_AddRefs(sheet));
+      NS_ENSURE_TRUE(sheet, rv);
+
+      rv = agentSheets.AppendObject(sheet);
+      NS_ENSURE_SUCCESS(rv, rv);
 
       // Disable scripting and plugins.
       rv = editSession->DisableJSAndPlugins(window);
       NS_ENSURE_SUCCESS(rv, rv);
 
       updateState = PR_TRUE;
       spellRecheckAll = oldState == eContentEditable;
     }
     else if (oldState == eDesignMode) {
       // designMode is being turned off (contentEditable is still on).
-      editorss->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/designmode.css"));
+      RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
 
       rv = editSession->RestoreJSAndPlugins(window);
       NS_ENSURE_SUCCESS(rv, rv);
 
       updateState = PR_TRUE;
     }
     else {
       // contentEditable is being turned on (and designMode is off).
       updateState = PR_FALSE;
     }
+
+    rv = presShell->SetAgentStyleSheets(agentSheets);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    presShell->ReconstructStyleData();
+
+    if (designMode) {
+      // We need to flush styles here because we're setting an XBL binding in
+      // designmode.css.
+      FlushPendingNotifications(Flush_Style);
+    }
   }
 
   mEditingState = newState;
 
   if (makeWindowEditable) {
     // Set the editor to not insert br's on return when in p
     // elements by default.
     // XXX Do we only want to do this for designMode?
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -304,20 +304,16 @@ protected:
                                nsACString& aCharset);
   static PRBool TryUserForcedCharset(nsIMarkupDocumentViewer* aMarkupDV,
                                      nsIDocumentCharsetInfo*  aDocInfo,
                                      PRInt32& aCharsetSource,
                                      nsACString& aCharset);
   static PRBool TryCacheCharset(nsICachingChannel* aCachingChannel,
                                 PRInt32& aCharsetSource,
                                 nsACString& aCharset);
-  static PRBool TryBookmarkCharset(nsIDocShell* aDocShell,
-                                   nsIChannel* aChannel,
-                                   PRInt32& aCharsetSource,
-                                   nsACString& aCharset);
   // aParentDocument could be null.
   PRBool TryParentCharset(nsIDocumentCharsetInfo*  aDocInfo,
                           nsIDocument* aParentDocument,
                           PRInt32& charsetSource, nsACString& aCharset);
   static PRBool UseWeakDocTypeDefault(PRInt32& aCharsetSource,
                                       nsACString& aCharset);
   static PRBool TryDefaultCharset(nsIMarkupDocumentViewer* aMarkupDV,
                                   PRInt32& aCharsetSource,
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -1258,21 +1258,24 @@ void nsBuiltinDecoderStateMachine::Advan
       // Decode one frame and display it
       NS_ASSERTION(videoData->mTime >= mStartTime, "Should have positive frame time");
       {
         MonitorAutoExit exitMon(mDecoder->GetMonitor());
         // If we have video, we want to increment the clock in steps of the frame
         // duration.
         RenderVideoFrame(videoData);
       }
-      mDecoder->GetMonitor().NotifyAll();
       frameDuration = videoData->mEndTime - videoData->mTime;
       videoData = nsnull;
     }
 
+    // Kick the decode thread in case it filled its buffers and put itself
+    // to sleep.
+    mDecoder->GetMonitor().NotifyAll();
+
     // Cap the current time to the larger of the audio and video end time.
     // This ensures that if we're running off the system clock, we don't
     // advance the clock to after the media end time.
     if (mVideoFrameEndTime != -1 || mAudioEndTime != -1) {
       // These will be non -1 if we've displayed a video frame, or played an audio sample.
       clock_time = NS_MIN(clock_time, NS_MAX(mVideoFrameEndTime, mAudioEndTime));
       if (clock_time > GetMediaTime()) {
         // Only update the playback position if the clock time is greater
--- a/content/media/nsMediaCache.cpp
+++ b/content/media/nsMediaCache.cpp
@@ -66,17 +66,17 @@ static const double NONSEEKABLE_READAHEA
 
 // Assume that any replaying or backward seeking will happen
 // this far in the future (in seconds). This is a random guess/estimate
 // penalty to account for the possibility that we might not replay at
 // all.
 static const PRUint32 REPLAY_DELAY = 30;
 
 // When looking for a reusable block, scan forward this many blocks
-// from the desired "best" block location to look for free blocks, 
+// from the desired "best" block location to look for free blocks,
 // before we resort to scanning the whole cache. The idea is to try to
 // store runs of stream blocks close-to-consecutively in the cache if we
 // can.
 static const PRUint32 FREE_BLOCK_SCAN_LIMIT = 16;
 
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 
@@ -551,31 +551,51 @@ nsMediaCache::Init()
 
   if (!mMonitor) {
     // the constructor failed
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   nsCOMPtr<nsIFile> tmp;
   nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmp));
-  if (NS_FAILED(rv))
-    return rv;
+  NS_ENSURE_SUCCESS(rv,rv);
+
   nsCOMPtr<nsILocalFile> tmpFile = do_QueryInterface(tmp);
-  if (!tmpFile)
-    return NS_ERROR_FAILURE;
-  rv = tmpFile->AppendNative(nsDependentCString("moz_media_cache"));
-  if (NS_FAILED(rv))
-    return rv;
-  rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
-  if (NS_FAILED(rv))
-    return rv;
+  NS_ENSURE_TRUE(tmpFile != nsnull, NS_ERROR_FAILURE);
+
+  // We put the media cache file in
+  // ${TempDir}/mozilla-media-cache/media_cache
+  rv = tmpFile->AppendNative(nsDependentCString("mozilla-media-cache"));
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
+    // Ensure the permissions are 0700. If not, we won't be able to create,
+    // read to and write from the media cache file in its subdirectory on
+    // non-Windows platforms.
+    PRUint32 perms;
+    rv = tmpFile->GetPermissions(&perms);
+    NS_ENSURE_SUCCESS(rv,rv);
+    if (perms != 0700) {
+      rv = tmpFile->SetPermissions(0700);
+      NS_ENSURE_SUCCESS(rv,rv);
+    }
+  } else {
+    NS_ENSURE_SUCCESS(rv,rv);
+  }
+
+  rv = tmpFile->AppendNative(nsDependentCString("media_cache"));
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0700);
+  NS_ENSURE_SUCCESS(rv,rv);
+
   rv = tmpFile->OpenNSPRFileDesc(PR_RDWR | nsILocalFile::DELETE_ON_CLOSE,
                                  PR_IRWXU, &mFD);
-  if (NS_FAILED(rv))
-    return rv;
+  NS_ENSURE_SUCCESS(rv,rv);
 
 #ifdef PR_LOGGING
   if (!gMediaCacheLog) {
     gMediaCacheLog = PR_NewLogModule("nsMediaCache");
   }
 #endif
 
   nsMediaCacheFlusher::Init();
@@ -611,17 +631,17 @@ nsMediaCache::FlushInternal()
     mFD = nsnull;
   }
   Init();
 }
 
 void
 nsMediaCache::MaybeShutdown()
 {
-  NS_ASSERTION(NS_IsMainThread(), 
+  NS_ASSERTION(NS_IsMainThread(),
                "nsMediaCache::MaybeShutdown called on non-main thread");
   if (!gMediaCache->mStreams.IsEmpty()) {
     // Don't shut down yet, streams are still alive
     return;
   }
 
   // Since we're on the main thread, no-one is going to add a new stream
   // while we shut down.
@@ -1479,17 +1499,17 @@ nsMediaCache::AllocateAndWriteBlock(nsMe
 
   // Extend the mBlocks array as necessary
 
   TimeStamp now = TimeStamp::Now();
   PRInt32 blockIndex = FindBlockForIncomingData(now, aStream);
   if (blockIndex >= 0) {
     FreeBlock(blockIndex);
 
-    Block* block = &mIndex[blockIndex];    
+    Block* block = &mIndex[blockIndex];
     LOG(PR_LOG_DEBUG, ("Allocated block %d to stream %p block %d(%lld)",
         blockIndex, aStream, streamBlockIndex, (long long)streamBlockIndex*BLOCK_SIZE));
 
     mFreeBlocks.RemoveBlock(blockIndex);
 
     // Tell each stream using this resource about the new block.
     ResourceStreamIterator iter(aStream->mResourceID);
     while (nsMediaCacheStream* stream = iter.Next()) {
@@ -1686,17 +1706,17 @@ nsMediaCacheStream::NotifyDataLength(PRI
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   nsAutoMonitor mon(gMediaCache->Monitor());
   mStreamLength = aLength;
 }
 
 void
-nsMediaCacheStream::NotifyDataStarted(PRInt64 aOffset) 
+nsMediaCacheStream::NotifyDataStarted(PRInt64 aOffset)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   nsAutoMonitor mon(gMediaCache->Monitor());
   NS_WARN_IF_FALSE(aOffset == mChannelOffset,
                    "Server is giving us unexpected offset");
   mChannelOffset = aOffset;
   if (mStreamLength >= 0) {
@@ -1806,17 +1826,17 @@ nsMediaCacheStream::NotifyDataReceived(P
 
   // Notify in case there's a waiting reader
   // XXX it would be fairly easy to optimize things a lot more to
   // avoid waking up reader threads unnecessarily
   mon.NotifyAll();
 }
 
 void
-nsMediaCacheStream::NotifyDataEnded(nsresult aStatus) 
+nsMediaCacheStream::NotifyDataEnded(nsresult aStatus)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   nsAutoMonitor mon(gMediaCache->Monitor());
 
   PRInt32 blockOffset = PRInt32(mChannelOffset%BLOCK_SIZE);
   if (blockOffset > 0) {
     // Write back the partial block
@@ -1970,17 +1990,17 @@ nsMediaCacheStream::GetCachedDataEndInte
 }
 
 PRInt64
 nsMediaCacheStream::GetNextCachedDataInternal(PRInt64 aOffset)
 {
   PR_ASSERT_CURRENT_THREAD_IN_MONITOR(gMediaCache->Monitor());
   if (aOffset == mStreamLength)
     return -1;
-  
+
   PRUint32 startBlockIndex = aOffset/BLOCK_SIZE;
   PRUint32 channelBlockIndex = mChannelOffset/BLOCK_SIZE;
 
   if (startBlockIndex == channelBlockIndex &&
       aOffset < mChannelOffset) {
     // The block containing mChannelOffset is partially read, but not
     // yet committed to the main cache. aOffset lies in the partially
     // read portion, thus it is effectively cached.
@@ -2211,17 +2231,17 @@ nsMediaCacheStream::ReadFromCache(char* 
       nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, size, &bytes);
       if (NS_FAILED(rv)) {
         return rv;
       }
     }
     streamOffset += bytes;
     count += bytes;
   }
-  
+
   return NS_OK;
 }
 
 nsresult