merge m-c to devtools
authorRob Campbell <rcampbell@mozilla.com>
Mon, 06 Jun 2011 16:42:23 -0300
changeset 70890 cce6acd42aea
parent 70889 b9ceaebb878f (current diff)
parent 70584 b69d30cc0b24 (diff)
child 70891 588eea08e466
push id20437
push userdcamp@campd.org
push date2011-06-10 22:40 +0000
treeherdermozilla-central@6da2c7c5c170 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge m-c to devtools
browser/base/content/test/Makefile.in
browser/themes/pinstripe/browser/Secure-background.gif
content/base/test/test_bug414796.html
dom/interfaces/core/nsIDOM3TypeInfo.idl
dom/interfaces/core/nsIDOMNotation.idl
layout/reftests/table-background/rainbowhb.gif
layout/reftests/table-background/rainbowvb.gif
mobile/chrome/content/bindings/setting.xml
mobile/chrome/content/checkerboard.png
services/sync/tests/unit/test_utils_queryAsync.js
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -70,46 +70,48 @@
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsPIDOMWindow.h"
 
 #include "nsIDocument.h"
 #include "nsIContent.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 
+#include "nsLayoutUtils.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIFrame.h"
 #include "nsIView.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIScrollableFrame.h"
 #include "nsFocusManager.h"
 
 #include "nsXPIDLString.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "prdtoa.h"
 #include "nsIAtom.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsIURI.h"
 #include "nsArrayUtils.h"
 #include "nsIMutableArray.h"
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsAttrName.h"
 #include "nsNetUtil.h"
 #include "nsEventStates.h"
 
 #ifdef NS_DEBUG
 #include "nsIDOMCharacterData.h"
 #endif
 
 #include "mozilla/unused.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible. nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsAccessible, nsAccessNode)
@@ -333,57 +335,49 @@ nsAccessible::Description(nsString& aDes
 #define NS_MODIFIER_ALT      4
 #define NS_MODIFIER_META     8
 
 // returns the accesskey modifier mask used in the given node's context
 // (i.e. chrome or content), or 0 if an error occurs
 static PRInt32
 GetAccessModifierMask(nsIContent* aContent)
 {
-  nsCOMPtr<nsIPrefBranch> prefBranch =
-    do_GetService(NS_PREFSERVICE_CONTRACTID);
-  if (!prefBranch)
-    return 0;
-
   // use ui.key.generalAccessKey (unless it is -1)
-  PRInt32 accessKey;
-  nsresult rv = prefBranch->GetIntPref("ui.key.generalAccessKey", &accessKey);
-  if (NS_SUCCEEDED(rv) && accessKey != -1) {
-    switch (accessKey) {
-      case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
-      case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
-      case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
-      case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
-      default:                             return 0;
-    }
+  switch (Preferences::GetInt("ui.key.generalAccessKey", -1)) {
+    case -1:                             break;
+    case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
+    case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
+    case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
+    case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
+    default:                             return 0;
   }
 
   // get the docShell to this DOMNode, return 0 on failure
   nsCOMPtr<nsIDocument> document = aContent->GetCurrentDoc();
   if (!document)
     return 0;
   nsCOMPtr<nsISupports> container = document->GetContainer();
   if (!container)
     return 0;
   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
   if (!treeItem)
     return 0;
 
   // determine the access modifier used in this context
+  nsresult rv = NS_ERROR_FAILURE;
   PRInt32 itemType, accessModifierMask = 0;
   treeItem->GetItemType(&itemType);
   switch (itemType) {
-
-  case nsIDocShellTreeItem::typeChrome:
-    rv = prefBranch->GetIntPref("ui.key.chromeAccess", &accessModifierMask);
-    break;
-
-  case nsIDocShellTreeItem::typeContent:
-    rv = prefBranch->GetIntPref("ui.key.contentAccess", &accessModifierMask);
-    break;
+    case nsIDocShellTreeItem::typeChrome:
+      rv = Preferences::GetInt("ui.key.chromeAccess", &accessModifierMask);
+      break;
+
+    case nsIDocShellTreeItem::typeContent:
+      rv = Preferences::GetInt("ui.key.contentAccess", &accessModifierMask);
+      break;
   }
 
   return NS_SUCCEEDED(rv) ? accessModifierMask : 0;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetKeyboardShortcut(nsAString& aAccessKey)
 {
@@ -677,49 +671,44 @@ nsAccessible::IsVisible(PRBool* aIsOffsc
     if (isEmpty && !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
       // Consider zero area objects hidden unless they are absolutely positioned
       // or floating and may have descendants that have a non-zero size
       return PR_FALSE;
     }
   }
 
   // The frame intersects the viewport, but we need to check the parent view chain :(
-  nsIDocument* doc = mContent->GetOwnerDoc();
-  if (!doc)  {
-    return PR_FALSE;
-  }
-
-  nsIFrame* frameWithView =
-    frame->HasView() ? frame : frame->GetAncestorWithViewExternal();
-  nsIView* view = frameWithView->GetViewExternal();
-  PRBool isVisible = CheckVisibilityInParentChain(doc, view);
+  bool isVisible = nsCoreUtils::CheckVisibilityInParentChain(frame);
   if (isVisible && rectVisibility == nsRectVisibility_kVisible) {
     *aIsOffscreen = PR_FALSE;
   }
   return isVisible;
 }
 
 PRUint64
 nsAccessible::NativeState()
 {
   PRUint64 state = 0;
-  nsEventStates intrinsicState = mContent->IntrinsicState();
-
-  if (intrinsicState.HasState(NS_EVENT_STATE_INVALID))
-    state |= states::INVALID;
-
-  if (intrinsicState.HasState(NS_EVENT_STATE_REQUIRED))
-    state |= states::REQUIRED;
-
-  PRBool disabled = mContent->IsHTML() ? 
-    (intrinsicState.HasState(NS_EVENT_STATE_DISABLED)) :
-    (mContent->AttrValueIs(kNameSpaceID_None,
-                           nsAccessibilityAtoms::disabled,
-                           nsAccessibilityAtoms::_true,
-                           eCaseMatters));
+  PRBool disabled = PR_FALSE;
+  if (mContent->IsElement()) {
+    nsEventStates elementState = mContent->AsElement()->State();
+
+    if (elementState.HasState(NS_EVENT_STATE_INVALID))
+      state |= states::INVALID;
+
+    if (elementState.HasState(NS_EVENT_STATE_REQUIRED))
+      state |= states::REQUIRED;
+
+    disabled = mContent->IsHTML() ? 
+      (elementState.HasState(NS_EVENT_STATE_DISABLED)) :
+      (mContent->AttrValueIs(kNameSpaceID_None,
+                             nsAccessibilityAtoms::disabled,
+                             nsAccessibilityAtoms::_true,
+                             eCaseMatters));
+  }
 
   // Set unavailable state based on disabled state, otherwise set focus states
   if (disabled) {
     state |= states::UNAVAILABLE;
   }
   else if (mContent->IsElement()) {
     nsIFrame *frame = GetFrame();
     if (frame && frame->IsFocusable()) {
@@ -3246,54 +3235,16 @@ nsAccessible::GetFirstAvailableAccessibl
       GetAccService()->GetAccessibleInWeakShell(node, mWeakShell);
     if (accessible)
       return accessible;
   }
 
   return nsnull;
 }
 
-PRBool nsAccessible::CheckVisibilityInParentChain(nsIDocument* aDocument, nsIView* aView)
-{
-  nsIDocument* document = aDocument;
-  nsIView* view = aView;
-  // both view chain and widget chain are broken between chrome and content
-  while (document != nsnull) {
-    while (view != nsnull) {
-      if (view->GetVisibility() == nsViewVisibility_kHide) {
-        return PR_FALSE;
-      }
-      view = view->GetParent();
-    }
-
-    nsIDocument* parentDoc = document->GetParentDocument();
-    if (parentDoc != nsnull) {
-      nsIContent* content = parentDoc->FindContentForSubDocument(document);
-      if (content != nsnull) {
-        nsIPresShell* shell = parentDoc->GetShell();
-        if (!shell) {
-          return PR_FALSE;
-        }
-        nsIFrame* frame = content->GetPrimaryFrame();
-        while (frame != nsnull && !frame->HasView()) {
-          frame = frame->GetParent();
-        }
-
-        if (frame != nsnull) {
-          view = frame->GetViewExternal();
-        }
-      }
-    }
-
-    document = parentDoc;
-  }
-
-  return PR_TRUE;
-}
-
 nsresult
 nsAccessible::GetAttrValue(nsIAtom *aProperty, double *aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;  // Node already shut down
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -513,17 +513,17 @@ protected:
     eMixedChildren = 1 << 0, // text leaf children are presented
     eEmbeddedChildren = 1 << 1 // all children are embedded objects
   };
 
   /**
    * Return true if the children flag is set.
    */
   inline bool IsChildrenFlag(ChildrenFlags aFlag) const
-    { return (mFlags & kChildrenFlagsMask) == aFlag; }
+    { return static_cast<ChildrenFlags> (mFlags & kChildrenFlagsMask) == aFlag; }
 
   /**
    * Set children flag.
    */
   inline void SetChildrenFlag(ChildrenFlags aFlag)
     { mFlags = (mFlags & ~kChildrenFlagsMask) | aFlag; }
 
   /**
@@ -601,19 +601,16 @@ protected:
   virtual void DispatchClickEvent(nsIContent *aContent, PRUint32 aActionIndex);
 
   NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessible, DispatchClickEvent,
                               nsCOMPtr<nsIContent>, PRUint32)
 
   //////////////////////////////////////////////////////////////////////////////
   // Helpers
 
-  // Check the visibility across both parent content and chrome
-  PRBool CheckVisibilityInParentChain(nsIDocument* aDocument, nsIView* aView);
-
   /**
    *  Get the container node for an atomic region, defined by aria-atomic="true"
    *  @return the container node
    */
   nsIDOMNode* GetAtomicRegion();
 
   /**
    * Get numeric value of the given ARIA attribute.
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -58,16 +58,17 @@
 #include "nsPresContext.h"
 #include "nsIScrollableFrame.h"
 #include "nsEventStateManager.h"
 #include "nsISelection2.h"
 #include "nsISelectionController.h"
 #include "nsPIDOMWindow.h"
 #include "nsGUIEvent.h"
 #include "nsIView.h"
+#include "nsLayoutUtils.h"
 
 #include "nsContentCID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -748,16 +749,40 @@ nsCoreUtils::IsColumnHidden(nsITreeColum
 {
   nsCOMPtr<nsIDOMElement> element;
   aColumn->GetElement(getter_AddRefs(element));
   nsCOMPtr<nsIContent> content = do_QueryInterface(element);
   return content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::hidden,
                               nsAccessibilityAtoms::_true, eCaseMatters);
 }
 
+bool
+nsCoreUtils::CheckVisibilityInParentChain(nsIFrame* aFrame)
+{
+  nsIView* view = aFrame->GetClosestView();
+  if (view && !view->IsEffectivelyVisible())
+    return false;
+
+  nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
+  while (presShell) {
+    if (!presShell->IsActive()) {
+      return false;
+    }
+
+    nsIFrame* rootFrame = presShell->GetRootFrame();
+    presShell = nsnull;
+    if (rootFrame) {
+      nsIFrame* frame = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
+      if (frame) {
+        presShell = frame->PresContext()->GetPresShell();
+      }
+    }
+  }
+  return true;
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibleDOMStringList
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS1(nsAccessibleDOMStringList, nsIDOMDOMStringList)
 
 NS_IMETHODIMP
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -362,16 +362,22 @@ public:
   /**
    * Return true if the given node is table header element.
    */
   static PRBool IsHTMLTableHeader(nsIContent *aContent)
   {
     return aContent->NodeInfo()->Equals(nsAccessibilityAtoms::th) ||
       aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::scope);
   }
+
+  /**
+   * Check the visibility across both parent content and chrome.
+   */
+  static bool CheckVisibilityInParentChain(nsIFrame* aFrame);
+
 };
 
 
 /**
  * nsIDOMDOMStringList implementation.
  */
 class nsAccessibleDOMStringList : public nsIDOMDOMStringList
 {
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -308,22 +308,17 @@ nsDocAccessible::NativeState()
   }
 
   // Expose state busy until the document is loaded or tree is constructed.
   if (!mIsLoaded || !mNotificationController->IsTreeConstructed()) {
     state |= states::BUSY | states::STALE;
   }
  
   nsIFrame* frame = GetFrame();
-  while (frame != nsnull && !frame->HasView()) {
-    frame = frame->GetParent();
-  }
- 
-  if (frame == nsnull ||
-      !CheckVisibilityInParentChain(mDocument, frame->GetViewExternal())) {
+  if (!frame || !nsCoreUtils::CheckVisibilityInParentChain(frame)) {
     state |= states::INVISIBLE | states::OFFSCREEN;
   }
 
   nsCOMPtr<nsIEditor> editor;
   GetAssociatedEditor(getter_AddRefs(editor));
   state |= editor ? states::EDITABLE : states::READONLY;
 
   return state;
--- a/accessible/src/html/nsHTMLLinkAccessible.cpp
+++ b/accessible/src/html/nsHTMLLinkAccessible.cpp
@@ -76,17 +76,17 @@ nsHTMLLinkAccessible::NativeState()
 
   if (mContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::name)) {
     // This is how we indicate it is a named anchor
     // In other words, this anchor can be selected as a location :)
     // There is no other better state to use to indicate this.
     states |= states::SELECTABLE;
   }
 
-  nsEventStates state = mContent->IntrinsicState();
+  nsEventStates state = mContent->AsElement()->State();
   if (state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED |
                                   NS_EVENT_STATE_UNVISITED)) {
     states |= states::LINKED;
 
     if (state.HasState(NS_EVENT_STATE_VISITED))
       states |= states::TRAVERSED;
 
     return states;
@@ -182,12 +182,12 @@ nsHTMLLinkAccessible::GetAnchorURI(PRUin
 // Protected members
 
 PRBool
 nsHTMLLinkAccessible::IsLinked()
 {
   if (IsDefunct())
     return PR_FALSE;
 
-  nsEventStates state = mContent->IntrinsicState();
+  nsEventStates state = mContent->AsElement()->State();
   return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED |
                                      NS_EVENT_STATE_UNVISITED);
 }
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -49,21 +49,23 @@
 #include "nsWinUtils.h"
 
 #include "nsAttrName.h"
 #include "nsIDocument.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsPIDOMWindow.h"
 #include "nsIServiceManager.h"
 
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
 /// the accessible library and cached methods
 HINSTANCE nsAccessNodeWrap::gmAccLib = nsnull;
 HINSTANCE nsAccessNodeWrap::gmUserLib = nsnull;
 LPFNACCESSIBLEOBJECTFROMWINDOW nsAccessNodeWrap::gmAccessibleObjectFromWindow = nsnull;
 LPFNLRESULTFROMOBJECT nsAccessNodeWrap::gmLresultFromObject = NULL;
 LPFNNOTIFYWINEVENT nsAccessNodeWrap::gmNotifyWinEvent = nsnull;
 LPFNGETGUITHREADINFO nsAccessNodeWrap::gmGetGUIThreadInfo = nsnull;
 
@@ -706,32 +708,26 @@ void nsAccessNodeWrap::TurnOffNewTabSwit
       // no screen reader we're interested in. Bail out.
       return;
     }
   }
 
   // Check to see if the pref for disallowing CtrlTab is already set.
   // If so, bail out.
   // If not, set it.
-  nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
-  if (prefs) {
-    PRBool hasDisallowNewCtrlTabPref = PR_FALSE;
-    nsresult rv = prefs->PrefHasUserValue(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF,
-             &hasDisallowNewCtrlTabPref);
-    if (NS_SUCCEEDED(rv) && hasDisallowNewCtrlTabPref) {
-      // This pref has been set before. There is no default for it.
-      // Do nothing further, respect the setting that's there.
-      // That way, if noone touches it, it'll stay on after toggled once.
-      // If someone decided to turn it off, we respect that, too.
-      return;
-    }
-    
-    // Value has never been set, set it.
-    prefs->SetBoolPref(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF, PR_TRUE);
+  if (Preferences::HasUserValue(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF)) {
+    // This pref has been set before. There is no default for it.
+    // Do nothing further, respect the setting that's there.
+    // That way, if noone touches it, it'll stay on after toggled once.
+    // If someone decided to turn it off, we respect that, too.
+    return;
   }
+  
+  // Value has never been set, set it.
+  Preferences::SetBool(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF, PR_TRUE);
 }
 
 void nsAccessNodeWrap::DoATSpecificProcessing()
 {
   if (IsOnlyMsaaCompatibleJawsPresent())
     // All versions below 8.0.2173 are not compatible
     gIsIA2Disabled  = PR_TRUE;
 
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -53,17 +53,16 @@
 #include "AccessibleStates.h"
 
 #include "nsIMutableArray.h"
 #include "nsIDOMDocument.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsINodeInfo.h"
-#include "nsIPrefService.h"
 #include "nsRootAccessible.h"
 #include "nsIServiceManager.h"
 #include "nsTextFormatter.h"
 #include "nsIView.h"
 #include "nsIViewManager.h"
 #include "nsRoleMap.h"
 #include "nsEventMap.h"
 #include "nsArrayUtils.h"
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -45,25 +45,27 @@
 
 #include "nsIDOMElement.h"
 #include "nsIDOMXULElement.h"
 #include "nsIMutableArray.h"
 #include "nsIDOMXULContainerElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMKeyEvent.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsIServiceManager.h"
 #include "nsIPresShell.h"
 #include "nsIContent.h"
 #include "nsGUIEvent.h"
 #include "nsILookAndFeel.h"
 #include "nsWidgetsCID.h"
 
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
 
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULSelectableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULSelectableAccessible::
@@ -405,20 +407,17 @@ nsXULMenuitemAccessible::GetKeyboardShor
 
   nsAccessible* parentAcc = GetParent();
   if (parentAcc) {
     if (parentAcc->NativeRole() == nsIAccessibleRole::ROLE_MENUBAR) {
       // If top level menu item, add Alt+ or whatever modifier text to string
       // No need to cache pref service, this happens rarely
       if (gMenuAccesskeyModifier == -1) {
         // Need to initialize cached global accesskey pref
-        gMenuAccesskeyModifier = 0;
-        nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
-        if (prefBranch)
-          prefBranch->GetIntPref("ui.key.menuAccessKey", &gMenuAccesskeyModifier);
+        gMenuAccesskeyModifier = Preferences::GetInt("ui.key.menuAccessKey", 0);
       }
 
       nsAutoString propertyKey;
       switch (gMenuAccesskeyModifier) {
         case nsIDOMKeyEvent::DOM_VK_CONTROL:
           propertyKey.AssignLiteral("VK_CONTROL");
           break;
         case nsIDOMKeyEvent::DOM_VK_ALT:
--- a/browser/base/content/aboutDialog.css
+++ b/browser/base/content/aboutDialog.css
@@ -67,38 +67,8 @@
   margin: 0 40px;
 }
 
 #currentChannel {
   margin: 0;
   padding: 0;
   font-weight: bold;
 }
-
-#channelSelector {
-  margin-top: 10px;
-}
-
-#channelSelectorStart {
-  -moz-margin-start: 0;
-}
-
-#channelMenulist {
-  margin: 0;
-}
-
-.channel-description {
-  margin: 10px 0;
-}
-
-#detailsBox,
-#channelSelector,
-.channel-description {
-  -moz-transition: opacity 250ms;
-}
-
-#contentDeck:not([selectedIndex="0"]) > #detailsBox,
-#contentDeck:not([selectedIndex="1"]) > #channelSelector,
-#channelDescriptionDeck:not([selectedIndex="0"]) > #releaseDescription,
-#channelDescriptionDeck:not([selectedIndex="1"]) > #betaDescription,
-#channelDescriptionDeck:not([selectedIndex="2"]) > #auroraDescription {
-  opacity: 0;
-}
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -83,17 +83,19 @@ function init(aEvent)
     document.getElementById("extra-trademark").hidden = true;
   }
 #endif
 
 #ifdef MOZ_UPDATER
   gAppUpdater = new appUpdater();
 #endif
 
-  gChannelSelector.init();
+  let defaults = Services.prefs.getDefaultBranch("");
+  let channelLabel = document.getElementById("currentChannel");
+  channelLabel.value = defaults.getCharPref("app.update.channel");
 
 #ifdef XP_MACOSX
   // it may not be sized at this point, and we need its width to calculate its position
   window.sizeToContent();
   window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5);
 #endif
 }
 
@@ -568,77 +570,8 @@ appUpdater.prototype =
     if (!aIID.equals(Components.interfaces.nsIProgressEventSink) &&
         !aIID.equals(Components.interfaces.nsIRequestObserver) &&
         !aIID.equals(Components.interfaces.nsISupports))
       throw Components.results.NS_ERROR_NO_INTERFACE;
     return this;
   }
 };
 #endif
-
-var gChannelSelector = {
-  validChannels: { release: 1, beta: 1, aurora: 1 },
-  
-  init: function() {
-    try {
-      this.channelValue = Services.prefs.getCharPref("app.update.desiredChannel");
-    } catch (e) {
-      let defaults = Services.prefs.getDefaultBranch("");
-      this.channelValue = defaults.getCharPref("app.update.channel");
-    }
-
-    // Only show channel selector UI on valid update channels.
-    if (this.channelValue in this.validChannels) {
-      document.getElementById("currentChannelText").hidden = false;
-      this.setChannelLabel(this.channelValue);
-      this.setChannelMenuitem(this.channelValue);
-    }
-  },
-
-  selectChannel: function(aSelectedItem) {
-    document.getElementById("channelDescriptionDeck").selectedPanel =
-      document.getElementById(aSelectedItem.value + "Description");
-    document.getElementById("channelMenulist").setAttribute("aria-describedby",
-      aSelectedItem.value + "Description");
-  },
-
-  cancel: function() {
-    this.setChannelMenuitem(this.channelValue);
-    this.hide();
-  },
-
-  apply: function() {
-    this.channelValue = document.getElementById("channelMenulist").selectedItem.value;
-    this.setChannelLabel(this.channelValue);
-
-    // Change app update channel.
-    Services.prefs.setCharPref("app.update.desiredChannel", this.channelValue);
-
-    // Stop any downloads in progress
-    gAppUpdater.aus.pauseDownload();
-    // App updater will look at app.update.desiredChannel for new channel value
-    // and will clear it when the update is complete.
-    gAppUpdater.isChecking = true;
-    gAppUpdater.checker.checkForUpdates(gAppUpdater.updateCheckListener, true);
-
-    this.hide();
-  },
-
-  show: function() {
-    document.getElementById("contentDeck").selectedPanel =
-      document.getElementById("channelSelector");
-  },
-
-  hide: function() {
-    document.getElementById("contentDeck").selectedPanel =
-      document.getElementById("detailsBox");  
-  },
-
-  setChannelLabel: function(aValue) {
-    let channelLabel = document.getElementById("currentChannel");
-    channelLabel.value = document.getElementById(aValue + "Menuitem").label;
-  },
-
-  setChannelMenuitem: function(aValue) {
-    document.getElementById("channelMenulist").selectedItem =
-      document.getElementById(aValue + "Menuitem");
-  }
-}
--- a/browser/base/content/aboutDialog.xul
+++ b/browser/base/content/aboutDialog.xul
@@ -75,95 +75,60 @@
   <vbox id="aboutDialogContainer">
     <hbox id="clientBox">
       <vbox id="leftBox" flex="1"/>
       <vbox id="rightBox" flex="1">
 #expand <label id="version" value="__MOZ_APP_VERSION__"/>
         <label id="distribution" class="text-blurb"/>
         <label id="distributionId" class="text-blurb"/>
 
-        <!-- Make sure the selectedIndex attribute is always set so that the CSS
-             selectors for transitions work -->        
-        <deck id="contentDeck" selectedIndex="0">
-          <vbox id="detailsBox" aria-describedby="communityDesc contributeDesc">
-            <vbox id="updateBox">
+        <vbox id="detailsBox" aria-describedby="communityDesc contributeDesc">
+          <vbox id="updateBox">
 #ifdef MOZ_UPDATER
-              <deck id="updateDeck" orient="vertical">
-                <hbox id="updateButtonBox" align="center">
-                  <button id="updateButton" align="start"
-                          oncommand="gAppUpdater.buttonOnCommand();"/>
-                  <spacer flex="1"/>
-                </hbox>
-                <hbox id="checkingForUpdates" align="center">
-                  <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
-                </hbox>
-                <hbox id="checkingAddonCompat" align="center">
-                  <image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
-                </hbox>
-                <hbox id="downloading" align="center">
-                  <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
-                </hbox>
-                <hbox id="downloadFailed" align="center">
-                  <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
-                </hbox>
-                <hbox id="adminDisabled" align="center">
-                  <label>&update.adminDisabled;</label>
-                </hbox>
-                <hbox id="noUpdatesFound" align="center">
-                  <label>&update.noUpdatesFound;</label>
-                </hbox>
-                <hbox id="manualUpdate" align="center">
-                  <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
-                </hbox>
-              </deck>
+            <deck id="updateDeck" orient="vertical">
+              <hbox id="updateButtonBox" align="center">
+                <button id="updateButton" align="start"
+                        oncommand="gAppUpdater.buttonOnCommand();"/>
+                <spacer flex="1"/>
+              </hbox>
+              <hbox id="checkingForUpdates" align="center">
+                <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
+              </hbox>
+              <hbox id="checkingAddonCompat" align="center">
+                <image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
+              </hbox>
+              <hbox id="downloading" align="center">
+                <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
+              </hbox>
+              <hbox id="downloadFailed" align="center">
+                <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
+              </hbox>
+              <hbox id="adminDisabled" align="center">
+                <label>&update.adminDisabled;</label>
+              </hbox>
+              <hbox id="noUpdatesFound" align="center">
+                <label>&update.noUpdatesFound;</label>
+              </hbox>
+              <hbox id="manualUpdate" align="center">
+                <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
+              </hbox>
+            </deck>
 #endif
-            </vbox>
-
-            <description class="text-blurb" id="currentChannelText" hidden="true">
-              &channel.description.start;<label id="currentChannel"/>&channel.description.end;<label id="channelChangeLink" class="text-link" onclick="gChannelSelector.show();">&channel.change;</label>
-            </description>
-            <description class="text-blurb" id="communityDesc">
-              &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
-            </description>
-            <description class="text-blurb" id="contributeDesc">
-              &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
-            </description>
           </vbox>
 
-          <vbox id="channelSelector">
-            <hbox pack="start" align="center">
-              <label id="channelSelectorStart">&channel.selector.start;</label>
-              <menulist id="channelMenulist" onselect="gChannelSelector.selectChannel(this.selectedItem);" aria-labelledby="channelSelectorStart channelMenulist channelSelectorEnd">
-                <menupopup>
-                  <menuitem id="releaseMenuitem" label="Release" value="release"/>
-                  <menuitem id="betaMenuitem" label="Beta" value="beta"/>
-                  <menuseparator/>
-                  <menuitem id="auroraMenuitem" label="Aurora" value="aurora"/>
-                </menupopup>
-              </menulist>
-              <label id="channelSelectorEnd">&channel.selector.end;</label>
-            </hbox>
-
-            <deck id="channelDescriptionDeck" selectedIndex="0">
-              <description id="releaseDescription" class="channel-description">&channel.release.description;</description>
-              <description id="betaDescription" class="channel-description">&channel.beta.description;</description>
-              <description id="auroraDescription" class="channel-description">&channel.aurora.description;</description>
-            </deck>
-
-            <hbox id="channelSelectorButtons" pack="end">
-#ifdef XP_UNIX
-              <button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
-              <button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
-#else
-              <button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
-              <button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
-#endif
-            </hbox>
-          </vbox>
-        </deck>
+          <description class="text-blurb" id="currentChannelText">
+            &channel.description.start;<label id="currentChannel"/>&channel.description.end;
+          </description>
+          <description class="text-blurb" id="communityDesc">
+            &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
+          </description>
+          <description class="text-blurb" id="contributeDesc">
+            &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
+          </description>
+        </vbox>
       </vbox>
     </hbox>
     <vbox id="bottomBox">
       <hbox pack="center">
         <label class="text-link bottom-link" href="about:license">&bottomLinks.license;</label>
         <label class="text-link bottom-link" href="about:rights">&bottomLinks.rights;</label>
         <label class="text-link bottom-link" href="http://www.mozilla.com/legal/privacy/">&bottomLinks.privacy;</label>
       </hbox>
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -323,17 +323,17 @@ let gSyncUI = {
     if (!lastSync || this._needsSetup()) {
       syncButton.removeAttribute("tooltiptext");
       return;
     }
 
     // Show the day-of-week and time (HH:MM) of last sync
     let lastSyncDate = new Date(lastSync).toLocaleFormat("%a %H:%M");
     let lastSyncLabel =
-      this._stringBundle.formatStringFromName("lastSync.label", [lastSyncDate], 1);
+      this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDate], 1);
 
     syncButton.setAttribute("tooltiptext", lastSyncLabel);
   },
 
   _onSyncEnd: function SUI__onSyncEnd(success) {
     let title = this._stringBundle.GetStringFromName("error.sync.title");
     if (!success) {
       if (Weave.Status.login != Weave.LOGIN_SUCCEEDED) {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2252,17 +2252,21 @@ function loadURI(uri, referrer, postData
     if (allowThirdPartyFixup) {
       flags = nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
     }
     gBrowser.loadURIWithFlags(uri, flags, referrer, null, postData);
   } catch (e) {
   }
 }
 
-function getShortcutOrURI(aURL, aPostDataRef) {
+function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) {
+  // Initialize outparam to false
+  if (aMayInheritPrincipal)
+    aMayInheritPrincipal.value = false;
+
   var shortcutURL = null;
   var keyword = aURL;
   var param = "";
 
   var offset = aURL.indexOf(" ");
   if (offset > 0) {
     keyword = aURL.substr(0, offset);
     param = aURL.substr(offset + 1);
@@ -2324,16 +2328,21 @@ function getShortcutOrURI(aURL, aPostDat
   else if (param) {
     // This keyword doesn't take a parameter, but one was provided. Just return
     // the original URL.
     aPostDataRef.value = null;
 
     return aURL;
   }
 
+  // This URL came from a bookmark, so it's safe to let it inherit the current
+  // document's principal.
+  if (aMayInheritPrincipal)
+    aMayInheritPrincipal.value = true;
+
   return shortcutURL;
 }
 
 function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType) {
   var dataStream = Cc["@mozilla.org/io/string-input-stream;1"].
                    createInstance(Ci.nsIStringInputStream);
   aStringData = aStringData.replace(/%s/g, aEncKeyword).replace(/%S/g, aKeyword);
   dataStream.data = aStringData;
@@ -2868,17 +2877,17 @@ var PrintPreviewListener = {
     gBrowser.selectedTab = this._tabBeforePrintPreview;
     this._tabBeforePrintPreview = null;
     gInPrintPreviewMode = false;
     this._toggleAffectedChrome();
     gBrowser.removeTab(this._printPreviewTab);
     this._printPreviewTab = null;
   },
   _toggleAffectedChrome: function () {
-    gNavToolbox.hidden = gInPrintPreviewMode;
+    gNavToolbox.collapsed = gInPrintPreviewMode;
 
     if (gInPrintPreviewMode)
       this._hideChrome();
     else
       this._showChrome();
 
     if (this._chromeState.sidebarOpen)
       toggleSidebar(this._sidebarCommand);
@@ -2959,16 +2968,17 @@ function FillInHTMLTooltip(tipElement)
     return retVal;
 
   const XLinkNS = "http://www.w3.org/1999/xlink";
 
 
   var titleText = null;
   var XLinkTitleText = null;
   var SVGTitleText = null;
+  var lookingForSVGTitle = true;
   var direction = tipElement.ownerDocument.dir;
 
   // If the element is invalid per HTML5 Forms specifications and has no title,
   // show the constraint validation error message.
   if ((tipElement instanceof HTMLInputElement ||
        tipElement instanceof HTMLTextAreaElement ||
        tipElement instanceof HTMLSelectElement ||
        tipElement instanceof HTMLButtonElement) &&
@@ -2983,20 +2993,23 @@ function FillInHTMLTooltip(tipElement)
     if (tipElement.nodeType == Node.ELEMENT_NODE) {
       titleText = tipElement.getAttribute("title");
       if ((tipElement instanceof HTMLAnchorElement && tipElement.href) ||
           (tipElement instanceof HTMLAreaElement && tipElement.href) ||
           (tipElement instanceof HTMLLinkElement && tipElement.href) ||
           (tipElement instanceof SVGAElement && tipElement.hasAttributeNS(XLinkNS, "href"))) {
         XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
       }
-      if (tipElement instanceof SVGElement &&
-          tipElement.parentNode instanceof SVGElement &&
-          !(tipElement.parentNode instanceof SVGForeignObjectElement)) {
-        // Looking for SVG title
+      if (lookingForSVGTitle &&
+          !(tipElement instanceof SVGElement &&
+            tipElement.parentNode instanceof SVGElement &&
+            !(tipElement.parentNode instanceof SVGForeignObjectElement))) {
+        lookingForSVGTitle = false;
+      }
+      if (lookingForSVGTitle) {
         let length = tipElement.childNodes.length;
         for (let i = 0; i < length; i++) {
           let childNode = tipElement.childNodes[i];
           if (childNode instanceof SVGTitleElement) {
             SVGTitleText = childNode.textContent;
             break;
           }
         }
--- a/browser/base/content/syncAddDevice.xul
+++ b/browser/base/content/syncAddDevice.xul
@@ -49,16 +49,17 @@
 %syncBrandDTD;
 %syncSetupDTD;
 ]>
 <wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         id="wizard"
         title="&addDevice.title.label;"
         windowtype="Sync:AddDevice"
+        persist="screenX screenY"
         onwizardnext="return gSyncAddDevice.onWizardAdvance();"
         onwizardback="return gSyncAddDevice.onWizardBack();"
         onwizardcancel="gSyncAddDevice.onWizardCancel();"
         onload="gSyncAddDevice.init();">
 
   <script type="application/javascript"
           src="chrome://browser/content/syncAddDevice.js"/>
   <script type="application/javascript"
--- a/browser/base/content/syncGenericChange.xul
+++ b/browser/base/content/syncGenericChange.xul
@@ -50,16 +50,17 @@
 %brandDTD;
 %syncBrandDTD;
 %syncSetupDTD;
 ]>
 <wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         id="change-dialog"
         windowtype="Weave:ChangeSomething"
+        persist="screenX screenY"
         onwizardnext="Change.onLoad()"
         onwizardfinish="return Change.onDialogAccept();">
 
   <script type="application/javascript"
           src="chrome://browser/content/syncGenericChange.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/syncUtils.js"/>
   <script type="application/javascript"
--- a/browser/base/content/syncKey.xhtml
+++ b/browser/base/content/syncKey.xhtml
@@ -46,16 +46,17 @@
   %syncKeyDTD;
   <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd" >
   %globalDTD;
 ]>
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <title>&syncKey.page.title;</title>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+  <meta name="robots" content="noindex"/>
   <style type="text/css">
     #synckey { font-size: 150% }
     footer { font-size: 70% }
 # Bug 575675: Need to have an a:visited rule in a chrome document.
     a:visited { color: purple; }
   </style>
 </head>
 
--- a/browser/base/content/syncQuota.xul
+++ b/browser/base/content/syncQuota.xul
@@ -45,16 +45,17 @@
 <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
 <!ENTITY % syncQuotaDTD SYSTEM "chrome://browser/locale/syncQuota.dtd">
 %brandDTD;
 %syncBrandDTD;
 %syncQuotaDTD;
 ]>
 <dialog id="quotaDialog"
         windowtype="Sync:ViewQuota"
+        persist="screenX screenY width height"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onload="gSyncQuota.init()"
         buttons="accept,cancel"
         title="&quota.dialogTitle.label;"
         ondialogcancel="return true;"
         ondialogaccept="return gSyncQuota.onAccept();">
 
--- a/browser/base/content/syncSetup.xul
+++ b/browser/base/content/syncSetup.xul
@@ -49,16 +49,17 @@
 <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
 <!ENTITY % syncSetupDTD SYSTEM "chrome://browser/locale/syncSetup.dtd">
 %brandDTD;
 %syncBrandDTD;
 %syncSetupDTD;
 ]>
 <wizard id="accountSetup" title="&accountSetupTitle.label;"
         windowtype="Weave:AccountSetup"
+        persist="screenX screenY"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onwizardnext="return gSyncSetup.onWizardAdvance()"
         onwizardback="return gSyncSetup.onWizardBack()"
         onwizardfinish="gSyncSetup.onWizardFinish()"
         onwizardcancel="gSyncSetup.onWizardCancel()"
         onload="gSyncSetup.init()">
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1329,19 +1329,19 @@
 
               let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
               if (aAllowThirdPartyFixup)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
               if (aFromExternal)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
               try {
                 b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
-
+              } catch (ex) {
+                Cu.reportError(ex);
               }
-              catch (ex) { }
             }
 
             // We start our browsers out as inactive, and then maintain
             // activeness in the tab switcher.
             b.docShell.isActive = false;
 
             // Check if we're opening a tab related to the current tab and
             // move it to after the current tab.
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -2027,17 +2027,17 @@ let GroupItems = {
   // Function: getAppTabFavIconUrl
   // Gets the fav icon url for app tab.
   getAppTabFavIconUrl: function GroupItems__getAppTabFavIconUrl(xulTab) {
     let iconUrl;
 
     if (UI.shouldLoadFavIcon(xulTab.linkedBrowser))
       iconUrl = UI.getFavIconUrlForTab(xulTab);
     else
-      iconUrl = Utils.defaultFaviconURL;
+      iconUrl = gFavIconService.defaultFavicon.spec;
 
     return iconUrl;
   },
 
   // ----------
   // Function: addAppTab
   // Adds the given xul:tab to the app tab tray in all groups
   addAppTab: function GroupItems_addAppTab(xulTab) {
--- a/browser/base/content/tabview/iq.js
+++ b/browser/base/content/tabview/iq.js
@@ -603,17 +603,17 @@ iQClass.prototype = {
       let cStyle = window.getComputedStyle(elem, null);
       for (let prop in css) {
         prop = prop.replace(rupper, "-$1").toLowerCase();
         iQ(elem).css(prop, cStyle.getPropertyValue(prop));
       }
     });
 
     this.css({
-      '-moz-transition-property': 'all', // TODO: just animate the properties we're changing
+      '-moz-transition-property': Object.keys(css).join(", "),
       '-moz-transition-duration': (duration / 1000) + 's',
       '-moz-transition-timing-function': easing
     });
 
     this.css(css);
 
     let self = this;
     setTimeout(function() {
--- a/browser/base/content/tabview/modules/AllTabs.jsm
+++ b/browser/base/content/tabview/modules/AllTabs.jsm
@@ -52,20 +52,17 @@ let AllTabs = {
    * Get an array of all tabs from all tabbrowser windows.
    *
    * @usage let numAllTabs = AllTabs.tabs.length;
    *        AllTabs.tabs.forEach(handleAllTabs);
    */
   get tabs() {
     // Get tabs from each browser window and flatten them into one array
     return Array.concat.apply(null, browserWindows.map(function(browserWindow) {
-      let removingTabs = browserWindow.gBrowser._removingTabs;
-      return Array.filter(browserWindow.gBrowser.tabs, function (tab) {
-        return removingTabs.indexOf(tab) == -1;
-      });
+      return Array.filter(browserWindow.gBrowser.tabs, function (tab) !tab.closing);
     }));
   },
 
   /**
    * Attach a callback for a given tab event.
    *
    * @param eventName
    *        Name of the corresponding Tab* Event; one of "attrModified",
--- a/browser/base/content/tabview/modules/utils.jsm
+++ b/browser/base/content/tabview/modules/utils.jsm
@@ -485,18 +485,16 @@ Subscribable.prototype = {
     }, this);
   }
 };
 
 // ##########
 // Class: Utils
 // Singelton with common utility functions.
 let Utils = {
-  defaultFaviconURL: "chrome://mozapps/skin/places/defaultFavicon.png",
-
   // ----------
   // Function: toString
   // Prints [Utils] for debug use
   toString: function Utils_toString() {
     return "[Utils]";
   },
 
   // ___ Logging
--- a/browser/base/content/tabview/storage.js
+++ b/browser/base/content/tabview/storage.js
@@ -42,55 +42,37 @@
 // ##########
 // Class: Storage
 // Singleton for permanent storage of TabView data.
 let Storage = {
   GROUP_DATA_IDENTIFIER: "tabview-group",
   GROUPS_DATA_IDENTIFIER: "tabview-groups",
   TAB_DATA_IDENTIFIER: "tabview-tab",
   UI_DATA_IDENTIFIER: "tabview-ui",
-  CACHE_CLIENT_IDENTIFIER: "tabview-cache",
-  CACHE_PREFIX: "moz-panorama:",
 
   // ----------
   // Function: toString
   // Prints [Storage] for debug use
   toString: function Storage_toString() {
     return "[Storage]";
   },
 
   // ----------
   // Function: init
   // Sets up the object.
   init: function Storage_init() {
     this._sessionStore =
       Cc["@mozilla.org/browser/sessionstore;1"].
         getService(Ci.nsISessionStore);
-    
-    // Create stream-based cache session for tabview
-    let cacheService = 
-      Cc["@mozilla.org/network/cache-service;1"].
-        getService(Ci.nsICacheService);
-    this._cacheSession = cacheService.createSession(
-      this.CACHE_CLIENT_IDENTIFIER, Ci.nsICache.STORE_ON_DISK, true);
-    this.StringInputStream = Components.Constructor(
-      "@mozilla.org/io/string-input-stream;1", "nsIStringInputStream",
-      "setData");
-    this.StorageStream = Components.Constructor(
-      "@mozilla.org/storagestream;1", "nsIStorageStream", 
-      "init");
   },
 
   // ----------
   // Function: uninit
   uninit: function Storage_uninit () {
     this._sessionStore = null;
-    this._cacheSession = null;
-    this.StringInputStream = null;
-    this.StorageStream = null;
   },
 
   // ----------
   // Function: wipe
   // Cleans out all the stored data, leaving empty objects.
   wipe: function Storage_wipe() {
     try {
       var self = this;
@@ -110,166 +92,28 @@ let Storage = {
       this._sessionStore.setWindowValue(gWindow, this.GROUP_DATA_IDENTIFIER,
         JSON.stringify({}));
     } catch (e) {
       Utils.log("Error in wipe: "+e);
     }
   },
 
   // ----------
-  // Function: _openCacheEntry
-  // Opens a cache entry for the given <url> and requests access <access>.
-  // Calls <successCallback>(entry) when the entry was successfully opened with
-  // requested access rights. Otherwise calls <errorCallback>().
-  _openCacheEntry: function Storage__openCacheEntry(url, access, successCallback, errorCallback) {
-    let onCacheEntryAvailable = function (entry, accessGranted, status) {
-      if (entry && access == accessGranted && Components.isSuccessCode(status)) {
-        successCallback(entry);
-      } else {
-        entry && entry.close();
-        errorCallback();
-      }
-    }
-
-    let key = this.CACHE_PREFIX + url;
-
-    // switch to synchronous mode if parent window is about to close
-    if (UI.isDOMWindowClosing) {
-      let entry = this._cacheSession.openCacheEntry(key, access, true);
-      let status = Components.results.NS_OK;
-      onCacheEntryAvailable(entry, entry.accessGranted, status);
-    } else {
-      let listener = new CacheListener(onCacheEntryAvailable);
-      this._cacheSession.asyncOpenCacheEntry(key, access, listener);
-    }
-  },
-
-  // ----------
-  // Function: saveThumbnail
-  // Saves the <imageData> to the cache using the given <url> as key.
-  // Calls <callback>(status) when finished (passing true or false indicating
-  // whether the operation succeeded).
-  saveThumbnail: function Storage_saveThumbnail(url, imageData, callback) {
-    Utils.assert(url, "url");
-    Utils.assert(imageData, "imageData");
-    Utils.assert(typeof callback == "function", "callback arg must be a function");
-
-    let self = this;
-    let StringInputStream = this.StringInputStream;
-
-    let onCacheEntryAvailable = function (entry) {
-      let outputStream = entry.openOutputStream(0);
-
-      let cleanup = function () {
-        outputStream.close();
-        entry.close();
-      }
-
-      // switch to synchronous mode if parent window is about to close
-      if (UI.isDOMWindowClosing) {
-        outputStream.write(imageData, imageData.length);
-        cleanup();
-        callback(true);
-        return;
-      }
-
-      // asynchronous mode
-      let inputStream = new StringInputStream(imageData, imageData.length);
-      gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
-        cleanup();
-        inputStream.close();
-        callback(Components.isSuccessCode(result));
-      });
-    }
-
-    let onCacheEntryUnavailable = function () {
-      callback(false);
-    }
-
-    this._openCacheEntry(url, Ci.nsICache.ACCESS_WRITE,
-        onCacheEntryAvailable, onCacheEntryUnavailable);
-  },
-
-  // ----------
-  // Function: loadThumbnail
-  // Asynchrously loads image data from the cache using the given <url> as key.
-  // Calls <callback>(status, data) when finished, passing true or false
-  // (indicating whether the operation succeeded) and the retrieved image data.
-  loadThumbnail: function Storage_loadThumbnail(url, callback) {
-    Utils.assert(url, "url");
-    Utils.assert(typeof callback == "function", "callback arg must be a function");
-
-    let self = this;
-
-    let onCacheEntryAvailable = function (entry) {
-      let imageChunks = [];
-      let nativeInputStream = entry.openInputStream(0);
-
-      const CHUNK_SIZE = 0x10000; // 65k
-      const PR_UINT32_MAX = 0xFFFFFFFF;
-      let storageStream = new self.StorageStream(CHUNK_SIZE, PR_UINT32_MAX, null);
-      let storageOutStream = storageStream.getOutputStream(0);
-
-      let cleanup = function () {
-        nativeInputStream.close();
-        storageStream.close();
-        storageOutStream.close();
-        entry.close();
-      }
-
-      gNetUtil.asyncCopy(nativeInputStream, storageOutStream, function (result) {
-        // cancel if parent window has already been closed
-        if (typeof UI == "undefined") {
-          cleanup();
-          return;
-        }
-
-        let imageData = null;
-        let isSuccess = Components.isSuccessCode(result);
-
-        if (isSuccess) {
-          let storageInStream = storageStream.newInputStream(0);
-          imageData = gNetUtil.readInputStreamToString(storageInStream,
-            storageInStream.available());
-          storageInStream.close();
-        }
-
-        cleanup();
-        callback(isSuccess, imageData);
-      });
-    }
-
-    let onCacheEntryUnavailable = function () {
-      callback(false);
-    }
-
-    this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
-        onCacheEntryAvailable, onCacheEntryUnavailable);
-  },
-
-  // ----------
   // Function: saveTab
   // Saves the data for a single tab.
   saveTab: function Storage_saveTab(tab, data) {
     Utils.assert(tab, "tab");
 
     if (data != null) {
       let imageData = data.imageData;
       // Remove imageData from payload
       delete data.imageData;
-      if (imageData != null) {
-        this.saveThumbnail(data.url, imageData, function (status) {
-          if (status) {
-            // Notify subscribers
-            tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
-          } else {
-            Utils.log("Error while saving thumbnail: " + e);
-          }
-        });
-      }
+
+      if (imageData != null)
+        ThumbnailStorage.saveThumbnail(tab, imageData);
     }
 
     this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
       JSON.stringify(data));
   },
 
   // ----------
   // Function: getTabData
@@ -287,28 +131,23 @@ let Storage = {
         existingData = JSON.parse(tabData);
       }
     } catch (e) {
       // getTabValue will fail if the property doesn't exist.
       Utils.log(e);
     }
 
     if (existingData) {
-      this.loadThumbnail(existingData.url, function (status, imageData) {
-        if (status) {
+      ThumbnailStorage.loadThumbnail(
+        tab, existingData.url,
+        function(status, imageData) { 
           callback(imageData);
-
-          // Notify subscribers
-          tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
-        } else {
-          Utils.log("Error while loading thumbnail");
         }
-      });
+      );
     }
-
     return existingData;
   },
 
   // ----------
   // Function: saveGroupItem
   // Saves the data for a single groupItem, associated with a specific window.
   saveGroupItem: function Storage_saveGroupItem(win, data) {
     var id = data.id;
@@ -404,31 +243,8 @@ let Storage = {
     } catch (e) {
       Utils.log("Error in readData: "+e);
     }
 
     return existingData;
   }
 };
 
-// ##########
-// Class: CacheListener
-// Generic CacheListener for feeding to asynchronous cache calls.
-// Calls <callback>(entry, access, status) when the requested cache entry
-// is available.
-function CacheListener(callback) {
-  Utils.assert(typeof callback == "function", "callback arg must be a function");
-  this.callback = callback;
-};
-
-CacheListener.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [CacheListener] for debug use
-  toString: function CacheListener_toString() {
-    return "[CacheListener]";
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener]),
-  onCacheEntryAvailable: function (entry, access, status) {
-    this.callback(entry, access, status);
-  }
-};
--- a/browser/base/content/tabview/tabview.js
+++ b/browser/base/content/tabview/tabview.js
@@ -1,11 +1,12 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
+const Cr = Components.results;
 
 Cu.import("resource:///modules/tabview/AllTabs.jsm");
 Cu.import("resource:///modules/tabview/utils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
   return Services.strings.
@@ -45,10 +46,11 @@ var gTabViewFrame = gWindow.document.get
 
 #include iq.js
 #include storage.js
 #include items.js
 #include groupitems.js
 #include tabitems.js
 #include drag.js
 #include trench.js
+#include thumbnailStorage.js
 #include ui.js
 #include search.js
new file mode 100644
--- /dev/null
+++ b/browser/base/content/tabview/thumbnailStorage.js
@@ -0,0 +1,373 @@
+/* ***** 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 thumbnailStorage.js.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * 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 ***** */
+
+// **********
+// Title: thumbnailStorage.js
+
+// ##########
+// Class: ThumbnailStorage
+// Singleton for persistent storage of thumbnail data.
+let ThumbnailStorage = {
+  CACHE_CLIENT_IDENTIFIER: "tabview-cache",
+  CACHE_PREFIX: "moz-panorama:",
+  PREF_DISK_CACHE_SSL: "browser.cache.disk_cache_ssl",
+
+  // Holds the cache session reference
+  _cacheSession: null,
+
+  // Holds the string input stream reference
+  _stringInputStream: null,
+
+  // Holds the storage stream reference
+  _storageStream: null,
+
+  // Holds the progress listener reference
+  _progressListener: null,
+
+  // Used to keep track of disk_cache_ssl preference
+  enablePersistentHttpsCaching: null,
+
+  // Used to keep track of browsers whose thumbs we shouldn't save
+  excludedBrowsers: [],
+
+  // ----------
+  // Function: toString
+  // Prints [ThumbnailStorage] for debug use.
+  toString: function ThumbnailStorage_toString() {
+    return "[ThumbnailStorage]";
+  },
+
+  // ----------
+  // Function: init
+  // Should be called when UI is initialized.
+  init: function ThumbnailStorage_init() {
+    // Create stream-based cache session for tabview
+    let cacheService = 
+      Cc["@mozilla.org/network/cache-service;1"].
+        getService(Ci.nsICacheService);
+    this._cacheSession = cacheService.createSession(
+      this.CACHE_CLIENT_IDENTIFIER, Ci.nsICache.STORE_ON_DISK, true);
+    this._stringInputStream = Components.Constructor(
+      "@mozilla.org/io/string-input-stream;1", "nsIStringInputStream",
+      "setData");
+    this._storageStream = Components.Constructor(
+      "@mozilla.org/storagestream;1", "nsIStorageStream", 
+      "init");
+
+    // store the preference value
+    this.enablePersistentHttpsCaching =
+      Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
+
+    Services.prefs.addObserver(this.PREF_DISK_CACHE_SSL, this, false);
+
+    let self = this;
+    // tabs are already loaded before UI is initialized so cache-control
+    // values are unknown.  We add browsers with https to the list for now.
+    gBrowser.browsers.forEach(function(browser) {
+      let checkAndAddToList = function(browserObj) {
+        if (!self.enablePersistentHttpsCaching &&
+            browserObj.currentURI.schemeIs("https"))
+          self.excludedBrowsers.push(browserObj);
+      };
+      if (browser.contentDocument.readyState != "complete" ||
+          browser.webProgress.isLoadingDocument) {
+        browser.addEventListener("load", function() {
+          browser.removeEventListener("load", arguments.callee, true);
+          checkAndAddToList(browser);
+        }, true);
+      } else {
+        checkAndAddToList(browser);
+      }
+    });
+    gBrowser.addTabsProgressListener(this);
+  },
+
+  // Function: uninit
+  // Should be called when window is unloaded.
+  uninit: function ThumbnailStorage_uninit() {
+    gBrowser.removeTabsProgressListener(this);
+    Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
+  },
+
+  // ----------
+  // Function: _openCacheEntry
+  // Opens a cache entry for the given <url> and requests access <access>.
+  // Calls <successCallback>(entry) when the entry was successfully opened with
+  // requested access rights. Otherwise calls <errorCallback>().
+  _openCacheEntry: function ThumbnailStorage__openCacheEntry(url, access, successCallback, errorCallback) {
+    let onCacheEntryAvailable = function(entry, accessGranted, status) {
+      if (entry && access == accessGranted && Components.isSuccessCode(status)) {
+        successCallback(entry);
+      } else {
+        entry && entry.close();
+        errorCallback();
+      }
+    }
+
+    let key = this.CACHE_PREFIX + url;
+
+    // switch to synchronous mode if parent window is about to close
+    if (UI.isDOMWindowClosing) {
+      let entry = this._cacheSession.openCacheEntry(key, access, true);
+      let status = Cr.NS_OK;
+      onCacheEntryAvailable(entry, entry.accessGranted, status);
+    } else {
+      let listener = new CacheListener(onCacheEntryAvailable);
+      this._cacheSession.asyncOpenCacheEntry(key, access, listener);
+    }
+  },
+
+  // Function: _shouldSaveThumbnail
+  // Checks whether to save tab's thumbnail or not.
+  _shouldSaveThumbnail : function ThumbnailStorage__shouldSaveThumbnail(tab) {
+    return (this.excludedBrowsers.indexOf(tab.linkedBrowser) == -1);
+  },
+
+  // ----------
+  // Function: saveThumbnail
+  // Saves the <imageData> to the cache using the given <url> as key.
+  // Calls <callback>(status, data) when finished, passing true or false
+  // (indicating whether the operation succeeded).
+  saveThumbnail: function ThumbnailStorage_saveThumbnail(tab, imageData, callback) {
+    Utils.assert(tab, "tab");
+    Utils.assert(imageData, "imageData");
+    
+    if (!this._shouldSaveThumbnail(tab)) {
+      tab._tabViewTabItem._sendToSubscribers("deniedToCacheImageData");
+      if (callback)
+        callback(false);
+      return;
+    }
+
+    let self = this;
+
+    let completed = function(status) {
+      if (callback)
+        callback(status);
+
+      if (status) {
+        // Notify subscribers
+        tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
+      } else {
+        Utils.log("Error while saving thumbnail: " + e);
+      }
+    };
+
+    let onCacheEntryAvailable = function(entry) {
+      let outputStream = entry.openOutputStream(0);
+
+      let cleanup = function() {
+        outputStream.close();
+        entry.close();
+      }
+
+      // switch to synchronous mode if parent window is about to close
+      if (UI.isDOMWindowClosing) {
+        outputStream.write(imageData, imageData.length);
+        cleanup();
+        completed(true);
+        return;
+      }
+
+      // asynchronous mode
+      let inputStream = new self._stringInputStream(imageData, imageData.length);
+      gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
+        cleanup();
+        inputStream.close();
+        completed(Components.isSuccessCode(result));
+      });
+    }
+
+    let onCacheEntryUnavailable = function() {
+      completed(false);
+    }
+
+    this._openCacheEntry(tab.linkedBrowser.currentURI.spec, 
+        Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable, 
+        onCacheEntryUnavailable);
+  },
+
+  // ----------
+  // Function: loadThumbnail
+  // Asynchrously loads image data from the cache using the given <url> as key.
+  // Calls <callback>(status, data) when finished, passing true or false
+  // (indicating whether the operation succeeded) and the retrieved image data.
+  loadThumbnail: function ThumbnailStorage_loadThumbnail(tab, url, callback) {
+    Utils.assert(tab, "tab");
+    Utils.assert(url, "url");
+    Utils.assert(typeof callback == "function", "callback arg must be a function");
+
+    let self = this;
+
+    let completed = function(status, imageData) {
+      callback(status, imageData);
+
+      if (status) {
+        // Notify subscribers
+        tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
+      } else {
+        Utils.log("Error while loading thumbnail");
+      }
+    }
+
+    let onCacheEntryAvailable = function(entry) {
+      let imageChunks = [];
+      let nativeInputStream = entry.openInputStream(0);
+
+      const CHUNK_SIZE = 0x10000; // 65k
+      const PR_UINT32_MAX = 0xFFFFFFFF;
+      let storageStream = new self._storageStream(CHUNK_SIZE, PR_UINT32_MAX, null);
+      let storageOutStream = storageStream.getOutputStream(0);
+
+      let cleanup = function () {
+        nativeInputStream.close();
+        storageStream.close();
+        storageOutStream.close();
+        entry.close();
+      }
+
+      gNetUtil.asyncCopy(nativeInputStream, storageOutStream, function (result) {
+        // cancel if parent window has already been closed
+        if (typeof UI == "undefined") {
+          cleanup();
+          return;
+        }
+
+        let imageData = null;
+        let isSuccess = Components.isSuccessCode(result);
+
+        if (isSuccess) {
+          let storageInStream = storageStream.newInputStream(0);
+          imageData = gNetUtil.readInputStreamToString(storageInStream,
+            storageInStream.available());
+          storageInStream.close();
+        }
+
+        cleanup();
+        completed(isSuccess, imageData);
+      });
+    }
+
+    let onCacheEntryUnavailable = function() {
+      completed(false);
+    }
+
+    this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
+        onCacheEntryAvailable, onCacheEntryUnavailable);
+  },
+
+  // ----------
+  // Function: observe
+  // Implements the observer interface.
+  observe: function ThumbnailStorage_observe(subject, topic, data) {
+    this.enablePersistentHttpsCaching =
+      Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
+  },
+
+  // ----------
+  // Implements progress listener interface.
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                         Ci.nsISupportsWeakReference,
+                                         Ci.nsISupports]),
+
+  onStateChange: function ThumbnailStorage_onStateChange(
+    browser, webProgress, request, flag, status) {
+    if (flag & Ci.nsIWebProgressListener.STATE_START &&
+        flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
+      // ensure the dom window is the top one
+      if (webProgress.DOMWindow.parent == webProgress.DOMWindow) {
+        let index = this.excludedBrowsers.indexOf(browser);
+        if (index != -1)
+          this.excludedBrowsers.splice(index, 1);
+      }
+    }
+    if (flag & Ci.nsIWebProgressListener.STATE_STOP &&
+        flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
+      // ensure the dom window is the top one
+      if (webProgress.DOMWindow.parent == webProgress.DOMWindow &&
+          request && request instanceof Ci.nsIHttpChannel) {
+        request.QueryInterface(Ci.nsIHttpChannel);
+
+        let inhibitPersistentThumb = false;
+        if (request.isNoStoreResponse()) {
+           inhibitPersistentThumb = true;
+        } else if (!this.enablePersistentHttpsCaching &&
+                   request.URI.schemeIs("https")) {
+          let cacheControlHeader;
+          try {
+            cacheControlHeader = request.getResponseHeader("Cache-Control");
+          } catch(e) {
+            // this error would occur when "Cache-Control" doesn't exist in
+            // the eaders
+          }
+          if (cacheControlHeader && !(/public/i).test(cacheControlHeader))
+            inhibitPersistentThumb = true;
+        }
+
+        if (inhibitPersistentThumb &&
+            this.excludedBrowsers.indexOf(browser) == -1)
+          this.excludedBrowsers.push(browser);
+      }
+    }
+  }
+}
+
+// ##########
+// Class: CacheListener
+// Generic CacheListener for feeding to asynchronous cache calls.
+// Calls <callback>(entry, access, status) when the requested cache entry
+// is available.
+function CacheListener(callback) {
+  Utils.assert(typeof callback == "function", "callback arg must be a function");
+  this.callback = callback;
+};
+
+CacheListener.prototype = {
+  // ----------
+  // Function: toString
+  // Prints [CacheListener] for debug use
+  toString: function CacheListener_toString() {
+    return "[CacheListener]";
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener]),
+  onCacheEntryAvailable: function CacheListener_onCacheEntryAvailable(
+    entry, access, status) {
+    this.callback(entry, access, status);
+  }
+};
+
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -152,16 +152,19 @@ let UI = {
   // Must be called after the object is created.
   init: function UI_init() {
     try {
       let self = this;
 
       // initialize the direction of the page
       this._initPageDirection();
 
+      // ___ thumbnail storage
+      ThumbnailStorage.init();
+
       // ___ storage
       Storage.init();
       let data = Storage.readUIData(gWindow);
       this._storageSanity(data);
       this._pageBounds = data.pageBounds;
 
       // ___ currentTab
       this._currentTab = gBrowser.selectedTab;
@@ -273,35 +276,38 @@ let UI = {
       // ___ Done
       this._frameInitialized = true;
       this._save();
 
       // fire an iframe initialized event so everyone knows tab view is 
       // initialized.
       let event = document.createEvent("Events");
       event.initEvent("tabviewframeinitialized", true, false);
-      dispatchEvent(event);      
+      dispatchEvent(event);
     } catch(e) {
       Utils.log(e);
     } finally {
       GroupItems.resumeArrange();
     }
   },
 
+  // Function: uninit
+  // Should be called when window is unloaded.
   uninit: function UI_uninit() {
     // call our cleanup functions
     this._cleanupFunctions.forEach(function(func) {
       func();
     });
     this._cleanupFunctions = [];
 
     // additional clean up
     TabItems.uninit();
     GroupItems.uninit();
     Storage.uninit();
+    ThumbnailStorage.uninit();
 
     this._removeTabActionHandlers();
     this._currentTab = null;
     this._pageBounds = null;
     this._reorderTabItemsOnShow = null;
     this._reorderTabsOnHide = null;
     this._frameInitialized = false;
   },
@@ -675,32 +681,32 @@ let UI = {
     });
 
     // Private Browsing:
     // When transitioning to PB, we exit Panorama if necessary (making note of the
     // fact that we were there so we can return after PB) and make sure we
     // don't reenter Panorama due to all of the session restore tab
     // manipulation (which otherwise we might). When transitioning away from
     // PB, we reenter Panorama if we had been there directly before PB.
-    function pbObserver(aSubject, aTopic, aData) {
-      if (aTopic == "private-browsing") {
+    function pbObserver(subject, topic, data) {
+      if (topic == "private-browsing") {
         // We could probably do this in private-browsing-change-granted, but
         // this seems like a nicer spot, right in the middle of the process.
-        if (aData == "enter") {
+        if (data == "enter") {
           // If we are in Tab View, exit. 
           self._privateBrowsing.wasInTabView = self.isTabViewVisible();
           if (self.isTabViewVisible())
             self.goToTab(gBrowser.selectedTab);
         }
-      } else if (aTopic == "private-browsing-change-granted") {
-        if (aData == "enter" || aData == "exit") {
-          self._privateBrowsing.transitionMode = aData;
+      } else if (topic == "private-browsing-change-granted") {
+        if (data == "enter" || data == "exit") {
+          self._privateBrowsing.transitionMode = data;
           self.storageBusy();
         }
-      } else if (aTopic == "private-browsing-transition-complete") {
+      } else if (topic == "private-browsing-transition-complete") {
         // We use .transitionMode here, as aData is empty.
         if (self._privateBrowsing.transitionMode == "exit" &&
             self._privateBrowsing.wasInTabView)
           self.showTabView(false);
 
         self._privateBrowsing.transitionMode = "";
         self.storageReady();
       }
@@ -744,18 +750,17 @@ let UI = {
         // we don't want to go to the Tab View UI. 
         if (self._storageBusyCount)
           return;
 
         // if not closing the last tab
         if (gBrowser.tabs.length > 1) {
           // Don't return to TabView if there are any app tabs
           for (let a = 0; a < gBrowser._numPinnedTabs; a++) {
-            let theTab = gBrowser.tabs[a]; 
-            if (gBrowser._removingTabs.indexOf(theTab) == -1) 
+            if (!gBrowser.tabs[a].closing)
               return;
           }
 
           var groupItem = GroupItems.getActiveGroupItem();
 
           // 1) Only go back to the TabView tab when there you close the last
           // tab of a groupItem.
           let closingLastOfGroup = (groupItem && 
@@ -985,31 +990,38 @@ let UI = {
   // Function: _setupBrowserKeys
   // Sets up the allowed browser keys using key elements.
   _setupBrowserKeys: function UI__setupKeyWhiteList() {
     let keys = {};
 
     [
 #ifdef XP_UNIX
       "quitApplication",
+#else
+      "redo",
 #endif
 #ifdef XP_MACOSX
-      "preferencesCmdMac", "minimizeWindow",
+      "preferencesCmdMac", "minimizeWindow", "hideThisAppCmdMac",
 #endif
       "newNavigator", "newNavigatorTab", "undo", "cut", "copy", "paste", 
       "selectAll", "find"
-     ].forEach(function(key) {
+    ].forEach(function(key) {
       let element = gWindow.document.getElementById("key_" + key);
       keys[key] = element.getAttribute("key").toLocaleLowerCase().charCodeAt(0);
     });
 
     // for key combinations with shift key, the charCode of upper case letters 
     // are different to the lower case ones so need to handle them differently.
-    ["closeWindow", "tabview", "undoCloseTab", "undoCloseWindow",
-     "privatebrowsing", "redo"].forEach(function(key) {
+    [
+#ifdef XP_UNIX
+      "redo",
+#endif
+      "closeWindow", "tabview", "undoCloseTab", "undoCloseWindow",
+      "privatebrowsing"
+    ].forEach(function(key) {
       let element = gWindow.document.getElementById("key_" + key);
       keys[key] = element.getAttribute("key").toLocaleUpperCase().charCodeAt(0);
     });
 
     delete this._browserKeys;
     this._browserKeys = keys;
   },
 
@@ -1026,60 +1038,65 @@ let UI = {
         Keys.meta = false;
     });
 
     iQ(window).keypress(function(event) {
       if (event.metaKey)
         Keys.meta = true;
 
       function processBrowserKeys(evt) {
+        // let any keys with alt to pass through
+        if (evt.altKey)
+          return;
+
 #ifdef XP_MACOSX
         if (evt.metaKey) {
 #else
         if (evt.ctrlKey) {
 #endif
           let preventDefault = true;
           if (evt.shiftKey) {
             switch (evt.charCode) {
-              case self._browserKeys.privatebrowsing:
+              case self._browserKeys.tabview:
+                self.exit();
+                break;
+#ifdef XP_UNIX
+              case self._browserKeys.redo:
+#endif
+              case self._browserKeys.closeWindow:
               case self._browserKeys.undoCloseTab:
               case self._browserKeys.undoCloseWindow:
-              case self._browserKeys.closeWindow:
-              case self._browserKeys.redo:
+              case self._browserKeys.privatebrowsing:
                 preventDefault = false;
                 break;
-              case self._browserKeys.tabview:
-                self.exit();
-                break;
             }
           } else {
             switch (evt.charCode) {
               case self._browserKeys.find:
                 self.enableSearch();
                 break;
+#ifdef XP_UNIX
+              case self._browserKeys.quitApplication:
+#else
+              case self._browserKeys.redo:
+#endif
+#ifdef XP_MACOSX
+              case self._browserKeys.preferencesCmdMac:
+              case self._browserKeys.minimizeWindow:
+              case self._browserKeys.hideThisAppCmdMac:
+#endif
               case self._browserKeys.newNavigator:
               case self._browserKeys.newNavigatorTab:
               case self._browserKeys.undo:
               case self._browserKeys.cut:
               case self._browserKeys.copy:
               case self._browserKeys.paste:
               case self._browserKeys.selectAll:
                 preventDefault = false;
                 break;
-#ifdef XP_UNIX
-              case self._browserKeys.quitApplication:
-                preventDefault = false;
-                break;
-#endif
-#ifdef XP_MACOSX
-              case self._browserKeys.preferencesCmdMac:
-              case self._browserKeys.minimizeWindow:
-                preventDefault = false;
-                break;
-#endif
             }
           }
           if (preventDefault) {
             evt.stopPropagation();
             evt.preventDefault();
           }
         }
       }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -168,16 +168,17 @@ endif
                  browser_bug599325.js \
                  browser_bug609700.js \
                  browser_bug616836.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_findbarClose.js \
+                 browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
                  browser_disablechrome.js \
                  browser_discovery.js \
                  browser_duplicateIDs.js \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
--- a/browser/base/content/test/browser_bug581242.js
+++ b/browser/base/content/test/browser_bug581242.js
@@ -39,14 +39,15 @@ function test() {
   let blanktab = gBrowser.addTab();
   gBrowser.selectedTab = blanktab;
   BrowserOpenAddonsMgr();
 
   is(blanktab, gBrowser.selectedTab, "Current tab should be blank tab");
   // Verify that about:addons loads
   waitForExplicitFinish();
   gBrowser.selectedBrowser.addEventListener("load", function() {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     let browser = blanktab.linkedBrowser;
     is(browser.currentURI.spec, "about:addons", "about:addons should load into blank tab.");
     gBrowser.removeTab(blanktab);
     finish();
   }, true);
 }
--- a/browser/base/content/test/browser_getshortcutoruri.js
+++ b/browser/base/content/test/browser_getshortcutoruri.js
@@ -6,19 +6,20 @@ function getPostDataString(aIS) {
             createInstance(Ci.nsIScriptableInputStream);
   sis.init(aIS);
   var dataLines = sis.read(aIS.available()).split("\n");
 
   // only want the last line
   return dataLines[dataLines.length-1];
 }
 
-function keywordResult(aURL, aPostData) {
+function keywordResult(aURL, aPostData, aIsUnsafe) {
   this.url = aURL;
   this.postData = aPostData;
+  this.isUnsafe = aIsUnsafe;
 }
 
 function keyWordData() {}
 keyWordData.prototype = {
   init: function(aKeyWord, aURL, aPostData, aSearchWord) {
     this.keyword = aKeyWord;
     this.uri = makeURI(aURL);
     this.postData = aPostData;
@@ -47,64 +48,72 @@ var testData = [
 
   [new bmKeywordData("bmpostget", "http://bmpostget/search1=%s", "search2=%s", "foo3"),
    new keywordResult("http://bmpostget/search1=foo3", "search2=foo3")],
 
   [new bmKeywordData("bmget-nosearch", "http://bmget-nosearch/", null, ""),
    new keywordResult("http://bmget-nosearch/", null)],
 
   [new searchKeywordData("searchget", "http://searchget/?search={searchTerms}", null, "foo4"),
-   new keywordResult("http://searchget/?search=foo4", null)],
+   new keywordResult("http://searchget/?search=foo4", null, true)],
 
   [new searchKeywordData("searchpost", "http://searchpost/", "search={searchTerms}", "foo5"),
-   new keywordResult("http://searchpost/", "search=foo5")],
+   new keywordResult("http://searchpost/", "search=foo5", true)],
 
   [new searchKeywordData("searchpostget", "http://searchpostget/?search1={searchTerms}", "search2={searchTerms}", "foo6"),
-   new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6")],
+   new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6", true)],
 
   // Bookmark keywords that don't take parameters should not be activated if a
   // parameter is passed (bug 420328).
   [new bmKeywordData("bmget-noparam", "http://bmget-noparam/", null, "foo7"),
-   new keywordResult(null, null)],
+   new keywordResult(null, null, true)],
   [new bmKeywordData("bmpost-noparam", "http://bmpost-noparam/", "not_a=param", "foo8"),
-   new keywordResult(null, null)],
+   new keywordResult(null, null, true)],
 
   // Test escaping (%s = escaped, %S = raw)
   // UTF-8 default
   [new bmKeywordData("bmget-escaping", "http://bmget/?esc=%s&raw=%S", null, "foé"),
    new keywordResult("http://bmget/?esc=fo%C3%A9&raw=foé", null)],
   // Explicitly-defined ISO-8859-1
   [new bmKeywordData("bmget-escaping2", "http://bmget/?esc=%s&raw=%S&mozcharset=ISO-8859-1", null, "foé"),
    new keywordResult("http://bmget/?esc=fo%E9&raw=foé", null)],
 
   // Bug 359809: Test escaping +, /, and @
   // UTF-8 default
   [new bmKeywordData("bmget-escaping", "http://bmget/?esc=%s&raw=%S", null, "+/@"),
    new keywordResult("http://bmget/?esc=%2B%2F%40&raw=+/@", null)],
   // Explicitly-defined ISO-8859-1
   [new bmKeywordData("bmget-escaping2", "http://bmget/?esc=%s&raw=%S&mozcharset=ISO-8859-1", null, "+/@"),
    new keywordResult("http://bmget/?esc=%2B%2F%40&raw=+/@", null)],
+
+  // Test using a non-bmKeywordData object, to test the behavior of
+  // getShortcutOrURI for non-keywords (setupKeywords only adds keywords for
+  // bmKeywordData objects)
+  [{keyword: "http://gavinsharp.com"},
+   new keywordResult(null, null, true)]
 ];
 
 function test() {
   setupKeywords();
 
   for each (var item in testData) {
     var [data, result] = item;
 
     var postData = {};
     var query = data.keyword;
     if (data.searchWord)
       query += " " + data.searchWord;
-    var url = getShortcutOrURI(query, postData);
+    var mayInheritPrincipal = {};
+    var url = getShortcutOrURI(query, postData, mayInheritPrincipal);
 
     // null result.url means we should expect the same query we sent in
     var expected = result.url || query;
     is(url, expected, "got correct URL for " + data.keyword);
     is(getPostDataString(postData.value), result.postData, "got correct postData for " + data.keyword);
+    is(mayInheritPrincipal.value, !result.isUnsafe, "got correct mayInheritPrincipal for " + data.keyword);
   }
 
   cleanupKeywords();
 }
 
 var gBMFolder = null;
 var gAddedEngines = [];
 function setupKeywords() {
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_keywordBookmarklets.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  let bmFolder = Application.bookmarks.menu.addFolder("keyword-test");
+  let tab = gBrowser.selectedTab = gBrowser.addTab();
+
+  registerCleanupFunction (function () {
+    bmFolder.remove();
+    gBrowser.removeTab(tab);
+  });
+
+  let bm = bmFolder.addBookmark("bookmarklet", makeURI("javascript:1;"));
+  bm.keyword = "bm";
+
+  addPageShowListener(function () {
+    let originalPrincipal = gBrowser.contentPrincipal;
+
+    // Enter bookmarklet keyword in the URL bar
+    gURLBar.value = "bm";
+    gURLBar.focus();
+    EventUtils.synthesizeKey("VK_RETURN", {});
+
+    addPageShowListener(function () {
+      ok(gBrowser.contentPrincipal.equals(originalPrincipal), "javascript bookmarklet should inherit principal");
+      finish();
+    });
+  });
+}
+
+function addPageShowListener(func) {
+  gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
+    gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
+    func();
+  });
+}
--- a/browser/base/content/test/browser_zbug569342.js
+++ b/browser/base/content/test/browser_zbug569342.js
@@ -13,51 +13,51 @@ function load(url, cb) {
     cb();
   }, true);
 }
 
 function test() {
   waitForExplicitFinish();
 
   ok(gFindBar.hidden, "Find bar should not be visible");
-
-  run_test_1();
+  nextTest();
 }
 
-function run_test_1() {
-  load("about:config", function() {
+let urls = [
+  "about:config",
+  "about:addons",
+  "about:permissions"
+];
+
+function nextTest() {
+  let url = urls.shift();
+  if (url) {
+    testFindDisabled(url, nextTest);
+  } else {
+    // Make sure the find bar is re-enabled after disabled page is closed.
+    testFindEnabled("about:blank", finish);
+  }
+}
+
+function testFindDisabled(url, cb) {
+  load(url, function() {
     ok(gFindBar.hidden, "Find bar should not be visible");
     EventUtils.synthesizeKey("/", {}, gTab.linkedBrowser.contentWindow);
     ok(gFindBar.hidden, "Find bar should not be visible");
     EventUtils.synthesizeKey("f", { accelKey: true });
     ok(gFindBar.hidden, "Find bar should not be visible");
     ok(document.getElementById("cmd_find").getAttribute("disabled"),
        "Find command should be disabled");
 
     gBrowser.removeTab(gTab);
-    run_test_2();
+    cb();
   });
 }
 
-function run_test_2() {
-  load("about:addons", function() {
-    ok(gFindBar.hidden, "Find bar should not be visible");
-    EventUtils.synthesizeKey("/", {}, gTab.linkedBrowser.contentWindow);
-    ok(gFindBar.hidden, "Find bar should not be visible");
-    EventUtils.synthesizeKey("f", { accelKey: true });
-    ok(gFindBar.hidden, "Find bar should not be visible");
-    ok(document.getElementById("cmd_find").getAttribute("disabled"),
-       "Find command should be disabled");
-
-    gBrowser.removeTab(gTab);
-    run_test_3();
-  });
-}
-
-function run_test_3() {
-  load("about:blank", function() {
+function testFindEnabled(url, cb) {
+  load(url, function() {
     ok(!document.getElementById("cmd_find").getAttribute("disabled"),
        "Find command should not be disabled");
 
     gBrowser.removeTab(gTab);
-    finish();
+    cb();
   });
-}
\ No newline at end of file
+}
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -108,16 +108,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug624953.js \
                  browser_tabview_bug625195.js \
                  browser_tabview_bug625269.js \
                  browser_tabview_bug625424.js \
                  browser_tabview_bug625666.js \
                  browser_tabview_bug626368.js \
                  browser_tabview_bug626525.js \
                  browser_tabview_bug626791.js \
+                 browser_tabview_bug627239.js \
                  browser_tabview_bug627288.js \
                  browser_tabview_bug627736.js \
                  browser_tabview_bug628061.js \
                  browser_tabview_bug628165.js \
                  browser_tabview_bug628270.js \
                  browser_tabview_bug629189.js \
                  browser_tabview_bug629195.js \
                  browser_tabview_bug630102.js \
--- a/browser/base/content/test/tabview/browser_tabview_bug600645.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug600645.js
@@ -1,11 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+const fi = Cc["@mozilla.org/browser/favicon-service;1"].
+           getService(Ci.nsIFaviconService);
+
 let newTab;
 
 function test() {
   waitForExplicitFinish();
 
   newTab = gBrowser.addTab();
   gBrowser.pinTab(newTab);
 
@@ -22,27 +25,27 @@ function onTabViewWindowLoaded() {
 
   let groupItem = contentWindow.GroupItems.groupItems[0];
   let icon = contentWindow.iQ(".appTabIcon", groupItem.$appTabTray)[0];
   let $icon = contentWindow.iQ(icon);
 
   is($icon.data("xulTab"), newTab, 
      "The app tab icon has the right tab reference")
   // check to see whether it's showing the default one or not.
-  is($icon.attr("src"), contentWindow.Utils.defaultFaviconURL, 
+  is($icon.attr("src"), fi.defaultFavicon.spec,
      "The icon is showing the default fav icon for blank tab");
 
   let errorHandler = function(event) {
     newTab.removeEventListener("error", errorHandler, false);
 
     // since the browser code and test code are invoked when an error event is 
     // fired, a delay is used here to avoid the test code run before the browser 
     // code.
     executeSoon(function() {
-      is($icon.attr("src"), contentWindow.Utils.defaultFaviconURL, 
+      is($icon.attr("src"), fi.defaultFavicon.spec,
          "The icon is showing the default fav icon");
 
       // clean up
       gBrowser.removeTab(newTab);
       let endGame = function() {
         window.removeEventListener("tabviewhidden", endGame, false);
 
         ok(!TabView.isVisible(), "Tab View is hidden");
--- a/browser/base/content/test/tabview/browser_tabview_bug604699.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug604699.js
@@ -1,61 +1,62 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
-  let url = "http://non.existant/url";
+  let url = "http://www.example.com/";
   let cw;
+  let tab = gBrowser.tabs[0];
 
   let finishTest = function () {
     is(1, gBrowser.tabs.length, "there is one tab, only");
     ok(!TabView.isVisible(), "tabview is not visible");
     finish();
   }
 
   waitForExplicitFinish();
 
   let testErroneousLoading = function () {
-    cw.Storage.loadThumbnail(url, function (status, data) {
+    cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, data) {
       ok(!status, "thumbnail entry failed to load");
       is(null, data, "no thumbnail data received");
       next();
     });
   }
 
   let testAsynchronousSaving = function () {
     let saved = false;
     let data = "thumbnail-data-asynchronous";
 
-    cw.Storage.saveThumbnail(url, data, function (status) {
+    cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
       ok(status, "thumbnail entry was saved");
       ok(saved, "thumbnail was saved asynchronously");
 
-      cw.Storage.loadThumbnail(url, function (status, imageData) {
+      cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
         ok(status, "thumbnail entry was loaded");
         is(imageData, data, "valid thumbnail data received");
         next();
       });
     });
 
     saved = true;
   }
 
   let testSynchronousSaving = function () {
     let saved = false;
     let data = "thumbnail-data-synchronous";
 
     cw.UI.isDOMWindowClosing = true;
     registerCleanupFunction(function () cw.UI.isDOMWindowClosing = false);
 
-    cw.Storage.saveThumbnail(url, data, function (status) {
+    cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
       ok(status, "thumbnail entry was saved");
       ok(!saved, "thumbnail was saved synchronously");
 
-      cw.Storage.loadThumbnail(url, function (status, imageData) {
+      cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
         ok(status, "thumbnail entry was loaded");
         is(imageData, data, "valid thumbnail data received");
 
         cw.UI.isDOMWindowClosing = false;
         next();
       });
     });
 
@@ -67,15 +68,18 @@ function test() {
   let next = function () {
     let test = tests.shift();
     if (test)
       test();
     else
       hideTabView(finishTest);
   }
 
-  showTabView(function () {
-    registerCleanupFunction(function () TabView.hide());
-    cw = TabView.getContentWindow();
+  tab.linkedBrowser.loadURI(url);
+  afterAllTabsLoaded(function() {
+    showTabView(function () {
+      registerCleanupFunction(function () TabView.hide());
+      cw = TabView.getContentWindow();
 
-    next();
+      next();
+    });
   });
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug627239.js
@@ -0,0 +1,156 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+let contentWindow;
+let enablePersistentHttpsCaching;
+let newTab;
+
+function test() {
+  waitForExplicitFinish();
+
+  newTab = gBrowser.addTab();
+
+  HttpRequestObserver.register();
+
+  registerCleanupFunction(function () {
+    HttpRequestObserver.unregister();
+    if (gBrowser.tabs[1])
+      gBrowser.removeTab(gBrowser.tabs[1]);
+    hideTabView(function () {});
+
+    contentWindow.ThumbnailStorage.enablePersistentHttpsCaching =
+        enablePersistentHttpsCaching;
+  });
+
+  showTabView(function() {
+    contentWindow = TabView.getContentWindow();
+    test1();
+  });
+}
+
+
+function test1() {
+  // page with cache-control: no-store, should not save thumbnail
+  HttpRequestObserver.cacheControlValue = "no-store";
+  newTab.linkedBrowser.loadURI("http://www.example.com/browser/browser/base/content/test/tabview/dummy_page.html");
+
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(!contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab), 
+       "Should not save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "deniedToCacheImageData", function() {
+      tabItem.removeSubscriber(tabItem, "deniedToCacheImageData");
+      test2();
+    });
+    tabItem.save(true);
+    HttpRequestObserver.cacheControlValue = null;
+  });
+}
+
+function test2() {
+  // page with cache-control: private, should save thumbnail
+  HttpRequestObserver.cacheControlValue = "private";
+
+  newTab.linkedBrowser.loadURI("http://www.example.com/");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab), 
+       "Should save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
+      tabItem.removeSubscriber(tabItem, "savedCachedImageData");
+      test3();
+    });
+    tabItem.save(true);
+  });
+}
+
+function test3() {
+  // page with cache-control: private with https caching enabled, should save thumbnail
+  HttpRequestObserver.cacheControlValue = "private";
+
+  enablePersistentHttpsCaching =
+    contentWindow.ThumbnailStorage.enablePersistentHttpsCaching;
+  contentWindow.ThumbnailStorage.enablePersistentHttpsCaching = true;
+
+  newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/dummy_page.html");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
+       "Should save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
+      tabItem.removeSubscriber(tabItem, "savedCachedImageData");
+
+      test4();
+    });
+    tabItem.save(true);
+  });
+}
+
+function test4() {
+  // page with cache-control: public with https caching disabled, should save thumbnail
+  HttpRequestObserver.cacheControlValue = "public";
+
+  contentWindow.ThumbnailStorage.enablePersistentHttpsCaching = false;
+
+  newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
+       "Should save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
+      tabItem.removeSubscriber(tabItem, "savedCachedImageData");
+
+      test5();
+    });
+    tabItem.save(true);
+  });
+}
+
+function test5() {
+  // page with cache-control: private with https caching disabled, should not save thumbnail
+  HttpRequestObserver.cacheControlValue = "private";
+ 
+  newTab.linkedBrowser.loadURI("https://example.com/");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(!contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
+       "Should not the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "deniedToCacheImageData", function() {
+      tabItem.removeSubscriber(tabItem, "deniedToCacheImageData");
+
+      hideTabView(function () {
+        gBrowser.removeTab(gBrowser.tabs[1]);
+        finish();
+      });
+    });
+    tabItem.save(true);
+  });
+}
+
+let HttpRequestObserver = {
+  cacheControlValue: null,
+
+  observe: function(subject, topic, data) {
+    if (topic == "http-on-examine-response" && this.cacheControlValue) {
+      let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
+      httpChannel.setResponseHeader("Cache-Control", this.cacheControlValue, false);
+    }
+  },
+
+  register: function() {
+    Services.obs.addObserver(this, "http-on-examine-response", false);
+  },
+
+  unregister: function() {
+    Services.obs.removeObserver(this, "http-on-examine-response");
+  }
+};
--- a/browser/base/content/test/tabview/browser_tabview_startup_transitions.js
+++ b/browser/base/content/test/tabview/browser_tabview_startup_transitions.js
@@ -2,55 +2,53 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 var prefsBranch = Cc["@mozilla.org/preferences-service;1"].
                   getService(Ci.nsIPrefService).
                   getBranch("browser.panorama.");
 
 function animateZoom() prefsBranch.getBoolPref("animate_zoom");
 
-function registerCleanupFunction() {
-  prefsBranch.setUserPref("animate_zoom", true);
-}
-
 function test() {
   waitForExplicitFinish();
   
   let charsetArg = "charset=" + window.content.document.characterSet;
   let win = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
                               "about:blank", charsetArg, null, null, true);
-  
+
+  registerCleanupFunction(function() {
+    prefsBranch.setBoolPref("animate_zoom", true);
+    win.close();
+  });
+
   ok(animateZoom(), "By default, we animate on zoom.");
   prefsBranch.setBoolPref("animate_zoom", false);
   ok(!animateZoom(), "animate_zoom = false");
   
   let onLoad = function() {
     win.removeEventListener("load", onLoad, false);
 
     // a few shared references
     let tabViewWindow = null;
     let transitioned = 0;
 
-    let onShown = function() {
-      win.removeEventListener("tabviewshown", onShown, false);
-
-      ok(!transitioned, "There should be no transitions");
-      win.close();
-
-      finish();
-    };
-
     let initCallback = function() {
       tabViewWindow = win.TabView._window;
       function onTransitionEnd(event) {
         transitioned++;
-        tabViewWindow.Utils.log(transitioned);
+        info(transitioned);
       }
       tabViewWindow.document.addEventListener("transitionend", onTransitionEnd, false);
 
-      win.TabView.show();
+      showTabView(function() {
+        ok(!transitioned, "There should be no transitions");
+
+        tabViewWindow.document.removeEventListener(
+          "transitionend", onTransitionEnd, false);
+
+        finish();
+      }, win);
     };
 
-    win.addEventListener("tabviewshown", onShown, false);
     win.TabView._initFrame(initCallback);
   }
   win.addEventListener("load", onLoad, false);
 }
--- a/browser/base/content/test/tabview/browser_tabview_undo_group.js
+++ b/browser/base/content/test/tabview/browser_tabview_undo_group.js
@@ -26,17 +26,19 @@ function onTabViewWindowLoaded() {
     // show tab view
     TabView.toggle();
   };
   let onTabViewShown = function() {
     window.removeEventListener("tabviewshown", onTabViewShown, false);
 
     is(groupItem.getChildren().length, 1, "The new group has a tab item");
     // start the tests
-    testUndoGroup(contentWindow, groupItem);
+    waitForFocus(function() {
+      testUndoGroup(contentWindow, groupItem);
+    }, contentWindow);
   };
   window.addEventListener("tabviewhidden", onTabViewHidden, false);
   window.addEventListener("tabviewshown", onTabViewShown, false);
 
   // click on the + button
   let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
   ok(newTabButton[0], "New tab button exists");
 
@@ -75,17 +77,17 @@ function testUndoGroup(contentWindow, gr
     is(theGroupItem.container.style.display, "", "The group element is visible");
     ok(!theGroupItem.$undoContainer, "Undo container is not avaliable");
     
     // start the next test
     testCloseUndoGroup(contentWindow, groupItem);
   });
 
   let closeButton = groupItem.container.getElementsByClassName("close");
-  ok(closeButton, "Group item close button exists");
+  ok(closeButton[0], "Group item close button exists");
   EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
 }
 
 function testCloseUndoGroup(contentWindow, groupItem) {
   groupItem.addSubscriber(groupItem, "groupHidden", function() {
     groupItem.removeSubscriber(groupItem, "groupHidden");
 
     // check the data of the group
@@ -124,11 +126,11 @@ function testCloseUndoGroup(contentWindo
     let tabItems = contentWindow.TabItems.getItems();
     ok(tabItems[0], "A tab item exists");
     contentWindow.UI.setActive(tabItems[0]);
 
     TabView.toggle();
   });
 
   let closeButton = groupItem.container.getElementsByClassName("close");
-  ok(closeButton, "Group item close button exists");
+  ok(closeButton[0], "Group item close button exists");
   EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
 }
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -255,16 +255,17 @@
 
       <method name="handleCommand">
         <parameter name="aTriggeringEvent"/>
         <body><![CDATA[
           if (aTriggeringEvent instanceof MouseEvent && aTriggeringEvent.button == 2)
             return; // Do nothing for right clicks
 
           var url = this.value;
+          var mayInheritPrincipal = false;
           var postData = null;
 
           var action = this._parseActionUrl(url);
           if (action) {
             url = action.param;
             if (this.hasAttribute("actiontype")) {
               if (action.type == "switchtab") {
                 this.handleRevert();
@@ -272,36 +273,39 @@
                 if (switchToTabHavingURI(url) &&
                     isTabEmpty(prevTab))
                   gBrowser.removeTab(prevTab);
               }
               return;
             }
           }
           else {
-            [url, postData] = this._canonizeURL(aTriggeringEvent);
+            [url, postData, mayInheritPrincipal] = this._canonizeURL(aTriggeringEvent);
             if (!url)
               return;
           }
 
           this.value = url;
           gBrowser.userTypedValue = url;
           try {
             addToUrlbarHistory(url);
           } catch (ex) {
             // 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);
           }
 
           function loadCurrent() {
+            let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
             // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
-            // inheriting the currently loaded document's principal.
-            let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
-                        Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+            // inheriting the currently loaded document's principal, unless this
+            // URL is marked as safe to inherit (e.g. came from a bookmark
+            // keyword).
+            if (!mayInheritPrincipal)
+              flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
             gBrowser.loadURIWithFlags(url, flags, null, null, postData);
           }
 
           if (aTriggeringEvent instanceof MouseEvent) {
             // We have a mouse event (from the go button), so use the standard
             // UI link behaviors
             let where = whereToOpenLink(aTriggeringEvent, false, false);
             if (where == "current") {
@@ -334,17 +338,17 @@
         ]]></body>
       </method>
 
       <method name="_canonizeURL">
         <parameter name="aTriggeringEvent"/>
         <body><![CDATA[
           var url = this.value;
           if (!url)
-            return ["", null];
+            return ["", null, false];
 
           // Only add the suffix when the URL bar value isn't already "URL-like",
           // and only if we get a keyboard event, to match user expectations.
           if (!/^\s*(www|https?)\b|\/\s*$/i.test(url) &&
               (aTriggeringEvent instanceof KeyEvent)) {
 #ifdef XP_MACOSX
             let accel = aTriggeringEvent.metaKey;
 #else
@@ -397,19 +401,20 @@
               } else
                 url = url + (existingSuffix == -1 ? suffix : "/");
 
               url = "http://www." + url;
             }
           }
 
           var postData = {};
-          url = getShortcutOrURI(url, postData);
+          var mayInheritPrincipal = { value: false };
+          url = getShortcutOrURI(url, postData, mayInheritPrincipal);
 
-          return [url, postData.value];
+          return [url, postData.value, mayInheritPrincipal.value];
         ]]></body>
       </method>
 
       <field name="_contentIsCropped">false</field>
 
       <method name="_initURLTooltip">
         <body><![CDATA[
           if (this.focused || !this._contentIsCropped)
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -413,20 +413,22 @@ function openAboutDialog() {
   var enumerator = Services.wm.getEnumerator("Browser:About");
   while (enumerator.hasMoreElements()) {
     // Only open one about window (Bug 599573)
     let win = enumerator.getNext();
     win.focus();
     return;
   }
 
-#ifdef XP_MACOSX
+#ifdef XP_WIN
+  var features = "chrome,centerscreen,dependent";
+#elifdef XP_MACOSX
   var features = "chrome,resizable=no,minimizable=no";
 #else
-  var features = "chrome,centerscreen,dependent";
+  var features = "chrome,centerscreen,dependent,dialog=no";
 #endif
   window.openDialog("chrome://browser/content/aboutDialog.xul", "", features);
 }
 
 function openPreferences(paneID, extraArgs)
 {
   var instantApply = getBoolPref("browser.preferences.instantApply", false);
   var features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
--- a/browser/branding/aurora/content/jar.mn
+++ b/browser/branding/aurora/content/jar.mn
@@ -1,11 +1,10 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-background.png          (about-background.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/branding/nightly/content/jar.mn
+++ b/browser/branding/nightly/content/jar.mn
@@ -1,11 +1,10 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-background.png          (about-background.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/branding/official/content/jar.mn
+++ b/browser/branding/official/content/jar.mn
@@ -1,10 +1,9 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/branding/unofficial/content/jar.mn
+++ b/browser/branding/unofficial/content/jar.mn
@@ -1,11 +1,10 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-background.png          (about-background.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/components/preferences/aboutPermissions.js
+++ b/browser/components/preferences/aboutPermissions.js
@@ -140,16 +140,25 @@ Site.prototype = {
    *        The permission type string stored in permission manager.
    *        e.g. "cookie", "geo", "indexedDB", "popup", "image"
    * @param aResultObj
    *        An object that stores the permission value set for aType.
    *
    * @return A boolean indicating whether or not a permission is set.
    */
   getPermission: function Site_getPermission(aType, aResultObj) {
+    // Password saving isn't a nsIPermissionManager permission type, so handle
+    // it seperately.
+    if (aType == "password") {
+      aResultObj.value =  this.loginSavingEnabled ?
+                          Ci.nsIPermissionManager.ALLOW_ACTION :
+                          Ci.nsIPermissionManager.DENY_ACTION;
+      return true;
+    }
+
     let permissionValue;
     if (TEST_EXACT_PERM_TYPES.indexOf(aType) == -1) {
       permissionValue = Services.perms.testPermission(this.httpURI, aType);
     } else {
       permissionValue = Services.perms.testExactPermission(this.httpURI, aType);
     }
     aResultObj.value = permissionValue;
 
@@ -162,16 +171,23 @@ Site.prototype = {
    * @param aType
    *        The permission type string stored in permission manager.
    *        e.g. "cookie", "geo", "indexedDB", "popup", "image"
    * @param aPerm
    *        The permission value to set for the permission type. This should
    *        be one of the constants defined in nsIPermissionManager.
    */
   setPermission: function Site_setPermission(aType, aPerm) {
+    // Password saving isn't a nsIPermissionManager permission type, so handle
+    // it seperately.
+    if (aType == "password") {
+      this.loginSavingEnabled = aPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
+      return;
+    }
+
     // Using httpURI is kind of bogus, but the permission manager stores the
     // permission for the host, so the right thing happens in the end.
     Services.perms.add(this.httpURI, aType, aPerm);
   },
 
   /**
    * Clears a user-set permission value for the site given a permission type.
    *
@@ -458,37 +474,41 @@ let AboutPermissions = {
   /**
    * Creates Site objects for the top-frecency sites in the places database and stores
    * them in _sites. The number of sites created is controlled by PLACES_SITES_LIMIT.
    */
   getSitesFromPlaces: function() {
     gSitesStmt.params.limit = this.PLACES_SITES_LIMIT;
     gSitesStmt.executeAsync({
       handleResult: function(aResults) {
+        AboutPermissions.startSitesListBatch();
         let row;
         while (row = aResults.getNextRow()) {
           let host = row.getResultByName("host");
           AboutPermissions.addHost(host);
         }
+        AboutPermissions.endSitesListBatch();
       },
       handleError: function(aError) {
         Cu.reportError("AboutPermissions: " + aError);
       },
       handleCompletion: function(aReason) {
         // Notify oberservers for testing purposes.
         Services.obs.notifyObservers(null, "browser-permissions-initialized", null);
       }
     });
   },
 
   /**
    * Finds sites that have non-default permissions and creates Site objects for
    * them if they are not already stored in _sites.
    */
   enumerateServices: function() {
+    this.startSitesListBatch();
+
     let logins = Services.logins.getAllLogins();
     logins.forEach(function(aLogin) {
       try {
         // aLogin.hostname is a string in origin URL format (e.g. "http://foo.com")
         let uri = NetUtil.newURI(aLogin.hostname);
         this.addHost(uri.host);
       } catch (e) {
         // newURI will throw for add-ons logins stored in chrome:// URIs 
@@ -510,16 +530,18 @@ let AboutPermissions = {
       while (enumerator.hasMoreElements()) {
         let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission);
         // Only include sites with exceptions set for supported permission types.
         if (this._supportedPermissions.indexOf(permission.type) != -1) {
           this.addHost(permission.host);
         }
       }
     }
+
+    this.endSitesListBatch();
   },
 
   /**
    * Creates a new Site and adds it to _sites if it's not already there.
    *
    * @param aHost
    *        A host string.
    */
@@ -543,17 +565,29 @@ let AboutPermissions = {
     item.setAttribute("class", "site");
     item.setAttribute("value", aSite.host);
 
     aSite.getFavicon(function(aURL) {
       item.setAttribute("favicon", aURL);
     });
     aSite.listitem = item;
 
-    this.sitesList.appendChild(item);    
+    (this._listFragment || this.sitesList).appendChild(item);
+  },
+
+  startSitesListBatch: function () {
+    if (!this._listFragment)
+      this._listFragment = document.createDocumentFragment();
+  },
+
+  endSitesListBatch: function () {
+    if (this._listFragment) {
+      this.sitesList.appendChild(this._listFragment);
+      this._listFragment = null;
+    }
   },
 
   /**
    * Hides sites in richlistbox based on search text in sites-filter textbox.
    */
   filterSitesList: function() {
     let siteItems = this.sitesList.children;
     let filterValue = document.getElementById("sites-filter").value.toLowerCase();
@@ -651,54 +685,40 @@ let AboutPermissions = {
    * stored permission.
    *
    * @param aType
    *        The permission type string stored in permission manager.
    *        e.g. "cookie", "geo", "indexedDB", "popup", "image"
    */
   updatePermission: function(aType) {
     let allowItem = document.getElementById(aType + "-" + PermissionDefaults.ALLOW);
-    if (!this._selectedSite &&
-        this._noGlobalAllow.indexOf(aType) != -1) {
-      allowItem.hidden = true;
-      return;
-    }
-
-    allowItem.hidden = false;
+    allowItem.hidden = !this._selectedSite &&
+                       this._noGlobalAllow.indexOf(aType) != -1;
 
     let permissionMenulist = document.getElementById(aType + "-menulist");
     let permissionValue;    
     if (!this._selectedSite) {
-
       // If there is no selected site, we are updating the default permissions interface.
       permissionValue = PermissionDefaults[aType];
-    } else if (aType == "password") {
-      // Services.logins.getLoginSavingEnabled already looks at the default
-      // permission, so we don't need to.
-      permissionValue = this._selectedSite.loginSavingEnabled ?
-                        PermissionDefaults.ALLOW : PermissionDefaults.DENY;
     } else {
       let result = {};
       permissionValue = this._selectedSite.getPermission(aType, result) ?
                         result.value : PermissionDefaults[aType];
     }
 
     permissionMenulist.selectedItem = document.getElementById(aType + "-" + permissionValue);
   },
 
   onPermissionCommand: function(event) {
     let permissionType = event.currentTarget.getAttribute("type");
     let permissionValue = event.target.value;
 
     if (!this._selectedSite) {
       // If there is no selected site, we are setting the default permission.
       PermissionDefaults[permissionType] = permissionValue;
-    } else if (permissionType == "password") {
-      let isEnabled = permissionValue == PermissionDefaults.ALLOW;
-      this._selectedSite.loginSavingEnabled = isEnabled;
     } else {
       this._selectedSite.setPermission(permissionType, permissionValue);
     }
   },
 
   updateVisitCount: function() {
     this._selectedSite.getVisitCount(function(aCount) {
       let visitForm = AboutPermissions._stringBundle.GetStringFromName("visitCount");
--- a/browser/components/preferences/aboutPermissions.xml
+++ b/browser/components/preferences/aboutPermissions.xml
@@ -37,15 +37,15 @@
    - ***** END LICENSE BLOCK ***** -->
 
 <!DOCTYPE bindings>
 <bindings xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
   <binding id="site" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
     <content>
-      <xul:hbox class="site-container" align="center">
+      <xul:hbox class="site-container" align="center" flex="1">
         <xul:image xbl:inherits="src=favicon" class="site-favicon"/>
-        <xul:label xbl:inherits="value,selected" class="site-domain" crop="end"/>
+        <xul:label xbl:inherits="value,selected" class="site-domain" crop="end" flex="1"/>
       </xul:hbox>
     </content>
   </binding>
 </bindings>
--- a/browser/components/preferences/aboutPermissions.xul
+++ b/browser/components/preferences/aboutPermissions.xul
@@ -47,16 +47,17 @@
 %aboutPermissionsDTD;
 ]>
 
 <page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
       xmlns:xhtml="http://www.w3.org/1999/xhtml"
       id="permissions-page" title="&permissionsManager.title;"
       onload="AboutPermissions.init();"
       onunload="AboutPermissions.cleanUp();"
+      disablefastfind="true"
       role="application">
 
   <script type="application/javascript"
           src="chrome://browser/content/preferences/aboutPermissions.js"/>
 
   <hbox flex="1" id="permissions-content">
 
     <vbox id="sites-box">
@@ -158,26 +159,26 @@
                       oncommand="AboutPermissions.onPermissionCommand(event);">
               <menupopup>
                 <menuitem id="cookie-1" value="1" label="&permission.allow;"/>
                 <menuitem id="cookie-8" value="8" label="&permission.allowForSession;"/>
                 <menuitem id="cookie-2" value="2" label="&permission.block;"/>
               </menupopup>
             </menulist>
             <button id="cookies-clear-all-button"
-                    label="&cookie.clearAll;"
+                    label="&cookie.removeAll;"
                     oncommand="Services.cookies.removeAll();"/>
             <button id="cookies-manage-all-button"
                     label="&cookie.manage;"
                     oncommand="AboutPermissions.manageCookies();"/>
           </hbox>
           <hbox id="cookies-count" align="center">
             <label id="cookies-label"/>
             <button id="cookies-clear-button"
-                    label="&cookie.clear;"
+                    label="&cookie.remove;"
                     oncommand="AboutPermissions.clearCookies();"/>
             <button id="cookies-manage-button"
                     label="&cookie.manage;"
                     oncommand="AboutPermissions.manageCookies();"/>
           </hbox>
         </vbox>
       </hbox>
 
--- a/browser/components/preferences/privacy.xul
+++ b/browser/components/preferences/privacy.xul
@@ -182,18 +182,18 @@
               >&dontrememberActions.clearHistory.label;</html:a>&dontrememberActions.post.label;</description>
             </vbox>
             <spacer flex="1" class="indent"/>
           </hbox>
         </vbox>
         <vbox id="historyCustomPane">
           <separator class="thin"/>
           <checkbox id="privateBrowsingAutoStart" class="indent"
-                    label="&privateBrowsingPermanent.label;"
-                    accesskey="&privateBrowsingPermanent.accesskey;"
+                    label="&privateBrowsingPermanent2.label;"
+                    accesskey="&privateBrowsingPermanent2.accesskey;"
                     preference="browser.privatebrowsing.autostart"/>
 
           <vbox class="indent">
             <vbox class="indent">
               <checkbox id="rememberHistory"
                         label="&rememberHistory.label;"
                         accesskey="&rememberHistory.accesskey;"
                         preference="places.history.enabled"/>
--- a/browser/components/preferences/tests/browser_permissions.js
+++ b/browser/components/preferences/tests/browser_permissions.js
@@ -20,16 +20,21 @@ const PERM_SESION = 8;
 const TEST_PERMS = {
   "password": PERM_ALLOW,
   "cookie": PERM_ALLOW,
   "geo": PERM_UNKNOWN,
   "indexedDB": PERM_UNKNOWN,
   "popup": PERM_DENY
 };
 
+const NO_GLOBAL_ALLOW = [
+  "geo",
+  "indexedDB"
+];
+
 // number of managed permissions in the interface
 const TEST_PERMS_COUNT = 5;
 
 function test() {
   waitForExplicitFinish();
   registerCleanupFunction(cleanUp);
 
   // add test history visit
@@ -138,16 +143,22 @@ var tests = [
     is(defaultsHeader, gHeaderDeck.selectedPanel,
        "correct header shown for all sites");
 
     ok(gBrowser.contentDocument.getElementById("passwords-count").hidden,
        "passwords count is hidden");
     ok(gBrowser.contentDocument.getElementById("cookies-count").hidden,
        "cookies count is hidden");
 
+    // Test to make sure "Allow" items hidden for certain permission types
+    NO_GLOBAL_ALLOW.forEach(function(aType) {
+      let menuitem = gBrowser.contentDocument.getElementById(aType + "-" + PERM_ALLOW);
+      ok(menuitem.hidden, aType + " allow menuitem hidden for all sites");
+    });
+
     runNextTest();
   },
 
   function test_all_sites_permission() {
     // there should be no user-set pref for cookie behavior
     is(Services.prefs.getIntPref("network.cookie.cookieBehavior"), PERM_UNKNOWN,
        "network.cookie.cookieBehavior is expected default");
 
@@ -190,16 +201,22 @@ var tests = [
        "correct header shown for a specific site");
     is(gSiteLabel.value, TEST_URI_2.host, "header updated for selected site");
 
     ok(!gBrowser.contentDocument.getElementById("passwords-count").hidden,
        "passwords count is not hidden");
     ok(!gBrowser.contentDocument.getElementById("cookies-count").hidden,
        "cookies count is not hidden");
 
+    // Test to make sure "Allow" items are *not* hidden for certain permission types
+    NO_GLOBAL_ALLOW.forEach(function(aType) {
+      let menuitem = gBrowser.contentDocument.getElementById(aType + "-" + PERM_ALLOW);
+      ok(!menuitem.hidden, aType  + " allow menuitem not hidden for single site");
+    });
+
     runNextTest();
   },
 
   function test_permissions() {
     let menulists = gBrowser.contentDocument.getElementsByClassName("pref-menulist");
     is(menulists.length, TEST_PERMS_COUNT, "got expected number of managed permissions");
 
     for (let i = 0; i < menulists.length; i++) {
--- a/browser/locales/en-US/chrome/browser/aboutDialog.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutDialog.dtd
@@ -55,26 +55,8 @@
 <!ENTITY update.downloading.start   "Downloading update — ">
 <!ENTITY update.downloading.end     "">
 
 <!-- LOCALIZATION NOTE (channel.description.start,channel.description.end): channel.description.start and
      channel.description.end create one sentence, with the current channel label inserted in between.
      example: You are currently on the _Stable_ update channel. -->
 <!ENTITY channel.description.start  "You are currently on the ">
 <!ENTITY channel.description.end    " update channel. ">
-
-<!ENTITY channel.change             "Change">
-
-<!ENTITY channel.release.description       "Enjoy the tried and tested final release being used by hundreds of millions around the world. Stay in control of your online experience with super speed, easy customization and the latest Web technologies.">
-<!ENTITY channel.beta.description          "Experience cutting edge features with more stability. Provide feedback to help refine and polish what will be in the final release.">
-<!ENTITY channel.aurora.description        "Experience the newest innovations in an unstable environment that's not for the faint of heart. Provide feedback on features and performance to help determine what makes the final release.">
-
-<!-- LOCALIZATION NOTE (channel.selector.start,channel.selector.end): channel.selector.start and
-     channel.selector.end create one sentence, with a channel selection menulist instered in between.
-     This is all in one line, so try to make the localized text short.
-     example: Switch to the [Stable] update channel. -->
-<!ENTITY channel.selector.start          "Switch to the">
-<!ENTITY channel.selector.end            "update channel.">
-
-<!-- LOCALIZATION NOTE (channel.selector.applyButton): This button applies the user's choice to switch
-     to a new update channel and starts the application update process. -->
-<!ENTITY channel.selector.applyButton    "Apply and Update">
-<!ENTITY channel.selector.cancelButton   "Cancel">
--- a/browser/locales/en-US/chrome/browser/aboutRobots.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutRobots.dtd
@@ -10,18 +10,18 @@
 <!-- Movie: Logan's Run... Box (cybog): "Welcome Humans! I am ready for you." -->
 <!ENTITY robots.errorTitleText "Welcome Humans!">
 <!-- Movie: The Day The Earth Stood Still. Spoken by Klaatu. -->
 <!ENTITY robots.errorShortDescText "We have come to visit you in peace and with goodwill!">
 <!-- Various books by Isaac Asimov. http://en.wikipedia.org/wiki/Three_Laws_of_Robotics -->
 <!ENTITY robots.errorLongDesc1 "Robots may not injure a human being or, through inaction, allow a human being to come to harm.">
 <!-- Movie: Blade Runner. Batty: "I've seen things you people wouldn't believe..." -->
 <!ENTITY robots.errorLongDesc2 "Robots have seen things you people wouldn't believe.">
-<!-- Book: Hitchiker's Guide To The Galaxy. What the Sirius Cybernetics Corporation calls robots. -->
+<!-- Book: Hitchhiker's Guide To The Galaxy. What the Sirius Cybernetics Corporation calls robots. -->
 <!ENTITY robots.errorLongDesc3 "Robots are Your Plastic Pal Who's Fun To Be With.">
 <!-- TV: Futurama. Bender's first line is "Bite my shiny metal ass." -->
 <!ENTITY robots.errorLongDesc4 "Robots have shiny metal posteriors which should not be bitten.">
 <!-- TV: Battlestar Galactica (2004 series). From the opening text. -->
 <!ENTITY robots.errorTrailerDescText "And they have a plan.">
 <!-- TV: Battlestar Galactica (2004 series). Common expletive referring to Cylons. -->
 <!ENTITY robots.imgtitle "Frakkin' Toasters">
-<!-- Book: Hitchiker's Guide To The Galaxy. Arthur presses a button and it warns him. -->
+<!-- Book: Hitchhiker's Guide To The Galaxy. Arthur presses a button and it warns him. -->
 <!ENTITY robots.dontpress "Please do not press this button again.">
--- a/browser/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd
@@ -17,19 +17,19 @@
 <!ENTITY permission.allow                "Allow">
 <!ENTITY permission.allowForSession      "Allow for Session">
 <!ENTITY permission.block                "Block">
 
 <!ENTITY password.label                  "Store Passwords">
 <!ENTITY password.manage                 "Manage Passwords…">
 
 <!ENTITY cookie.label                    "Set Cookies">
-<!ENTITY cookie.clear                    "Clear Cookies">
+<!ENTITY cookie.remove                   "Remove Cookies">
 <!ENTITY cookie.manage                   "Manage Cookies…">
-<!ENTITY cookie.clearAll                 "Clear All Cookies">
+<!ENTITY cookie.removeAll                "Remove All Cookies">
 
 <!ENTITY geo.label                       "Share Location">
 
 <!-- LOCALIZATION NOTE (indexedDB.label): This is describing indexedDB storage
      using the same language used for the permIndexedDB string in browser/pageInfo.dtd -->
 <!ENTITY indexedDB.label                 "Maintain Offline Storage">
 
 <!ENTITY popup.label                     "Open Pop-up Windows">
--- a/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
@@ -56,18 +56,18 @@
 <!ENTITY  dontrememberDescription.label  "&brandShortName; will use the same settings as private browsing, and will not remember any history as you browse the Web.">
 
 <!-- LOCALIZATION NOTE (dontrememberActions.pre.label): include a trailing space as needed -->
 <!-- LOCALIZATION NOTE (dontrememberActions.post.label): include a starting space as needed -->
 <!ENTITY  dontrememberActions.pre.label          "You may also want to ">
 <!ENTITY  dontrememberActions.clearHistory.label "clear all current history">
 <!ENTITY  dontrememberActions.post.label         ".">
 
-<!ENTITY  privateBrowsingPermanent.label "Permanent Private Browsing mode">
-<!ENTITY  privateBrowsingPermanent.accesskey "P">
+<!ENTITY  privateBrowsingPermanent2.label "Always use private browsing mode">
+<!ENTITY  privateBrowsingPermanent2.accesskey "p">
 
 <!ENTITY  rememberHistory.label      "Remember my browsing history">
 <!ENTITY  rememberHistory.accesskey  "b">
 
 <!ENTITY  rememberDownload.label         "Remember download history">
 <!ENTITY  rememberDownload.accesskey     "d">
 
 <!ENTITY  rememberSearchForm.label       "Remember search and form history">
--- a/browser/themes/gnomestripe/browser/preferences/aboutPermissions.css
+++ b/browser/themes/gnomestripe/browser/preferences/aboutPermissions.css
@@ -14,40 +14,35 @@
   border: 1px solid ThreeDShadow;
   border-radius: 5px;
 }
 
 /* sites box */
 
 #sites-box {
   padding: 10px;
+  width: 25em;
 }
 
 .site {
-  width: 250px;
-  overflow-x: hidden;
   padding: 4px;
   border-bottom: 1px solid ThreeDLightShadow;
 }
 
 .site-favicon {
   height: 16px;
   width: 16px;
   -moz-margin-end: 4px;
   list-style-image: url("moz-icon://stock/gtk-file?size=menu");
 }
 
 #all-sites-item > .site-container > .site-favicon {
   list-style-image: none;
 }
 
-.site-domain {
-  max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
-}
-
 /* permissions box */
 
 #permissions-box {
   padding-top: 10px;
   overflow-y: auto;
 }
 
 #site-description {
deleted file mode 100644
index 2f4ed89d0cd7c03c8348342a5bb4a72ca9ac8cda..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -37,17 +37,16 @@ browser.jar:
   skin/classic/browser/reload-stop-go.png
   skin/classic/browser/searchbar-dropmarker.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/Search.png
   skin/classic/browser/section_collapsed.png
   skin/classic/browser/section_collapsed-rtl.png
   skin/classic/browser/section_expanded.png
   skin/classic/browser/Secure-Glyph-White.png
-  skin/classic/browser/Secure-background.gif
   skin/classic/browser/Toolbar.png
   skin/classic/browser/toolbarbutton-dropmarker.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/urlbar-popup-blocked.png
   skin/classic/browser/feeds/subscribe.css                  (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
--- a/browser/themes/pinstripe/browser/preferences/aboutPermissions.css
+++ b/browser/themes/pinstripe/browser/preferences/aboutPermissions.css
@@ -16,40 +16,35 @@
   border: 1px solid rgba(50, 65, 92, 0.4);
   border-radius: 5px;
 }
 
 /* sites box */
 
 #sites-box {
   padding: 10px;
+  width: 25em;
 }
 
 .site {
-  width: 250px;
-  overflow-x: hidden;
   padding: 4px;
   border-bottom: 1px solid ThreeDLightShadow;
 }
 
 .site-favicon {
   height: 16px;
   width: 16px;
   -moz-margin-end: 4px;
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
 #all-sites-item > .site-container > .site-favicon {
   list-style-image: none;
 }
 
-.site-domain {
-  max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
-}
-
 /* permissions box */
 
 #permissions-box {
   padding: 10px;
   overflow-y: auto;
 }
 
 #site-description {
--- a/browser/themes/winstripe/browser/preferences/aboutPermissions.css
+++ b/browser/themes/winstripe/browser/preferences/aboutPermissions.css
@@ -19,40 +19,35 @@
   border: 1px solid #C3CEDF;
   border-radius: 5px;
 }
 
 /* sites box */
 
 #sites-box {
   padding: 10px;
+  width: 25em;
 }
 
 .site {
-  width: 250px;
-  overflow-x: hidden;
   padding: 4px;
   border-bottom: 1px solid ThreeDLightShadow;
 }
 
 .site-favicon {
   height: 16px;
   width: 16px;
   -moz-margin-end: 4px;
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
 #all-sites-item > .site-container > .site-favicon {
   list-style-image: none;
 }
 
-.site-domain {
-  max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
-}
-
 /* permissions box */
 
 #permissions-box {
   padding-top: 10px;
   overflow-y: auto;
 }
 
 #site-description {
--- a/build/unix/elfhack/elf.cpp
+++ b/build/unix/elfhack/elf.cpp
@@ -36,17 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #undef NDEBUG
 #include <cstring>
 #include <assert.h>
 #include "elfxx.h"
 
 template <class endian, typename R, typename T>
-inline void Elf_Ehdr_Traits::swap(T &t, R &r)
+void Elf_Ehdr_Traits::swap(T &t, R &r)
 {
     memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident));
     r.e_type = endian::swap(t.e_type);
     r.e_machine = endian::swap(t.e_machine);
     r.e_version = endian::swap(t.e_version);
     r.e_entry = endian::swap(t.e_entry);
     r.e_phoff = endian::swap(t.e_phoff);
     r.e_shoff = endian::swap(t.e_shoff);
@@ -55,52 +55,52 @@ inline void Elf_Ehdr_Traits::swap(T &t, 
     r.e_phentsize = endian::swap(t.e_phentsize);
     r.e_phnum = endian::swap(t.e_phnum);
     r.e_shentsize = endian::swap(t.e_shentsize);
     r.e_shnum = endian::swap(t.e_shnum);
     r.e_shstrndx = endian::swap(t.e_shstrndx);
 }
 
 template <class endian, typename R, typename T>
-inline void Elf_Phdr_Traits::swap(T &t, R &r)
+void Elf_Phdr_Traits::swap(T &t, R &r)
 {
     r.p_type = endian::swap(t.p_type);
     r.p_offset = endian::swap(t.p_offset);
     r.p_vaddr = endian::swap(t.p_vaddr);
     r.p_paddr = endian::swap(t.p_paddr);
     r.p_filesz = endian::swap(t.p_filesz);
     r.p_memsz = endian::swap(t.p_memsz);
     r.p_flags = endian::swap(t.p_flags);
     r.p_align = endian::swap(t.p_align);
 }
 
 template <class endian, typename R, typename T>
-inline void Elf_Shdr_Traits::swap(T &t, R &r)
+void Elf_Shdr_Traits::swap(T &t, R &r)
 {
     r.sh_name = endian::swap(t.sh_name);
     r.sh_type = endian::swap(t.sh_type);
     r.sh_flags = endian::swap(t.sh_flags);
     r.sh_addr = endian::swap(t.sh_addr);
     r.sh_offset = endian::swap(t.sh_offset);
     r.sh_size = endian::swap(t.sh_size);
     r.sh_link = endian::swap(t.sh_link);
     r.sh_info = endian::swap(t.sh_info);
     r.sh_addralign = endian::swap(t.sh_addralign);
     r.sh_entsize = endian::swap(t.sh_entsize);
 }
 
 template <class endian, typename R, typename T>
-inline void Elf_Dyn_Traits::swap(T &t, R &r)
+void Elf_Dyn_Traits::swap(T &t, R &r)
 {
     r.d_tag = endian::swap(t.d_tag);
     r.d_un.d_val = endian::swap(t.d_un.d_val);
 }
 
 template <class endian, typename R, typename T>
-inline void Elf_Sym_Traits::swap(T &t, R &r)
+void Elf_Sym_Traits::swap(T &t, R &r)
 {
     r.st_name = endian::swap(t.st_name);
     r.st_value = endian::swap(t.st_value);
     r.st_size = endian::swap(t.st_size);
     r.st_info = t.st_info;
     r.st_other = t.st_other;
     r.st_shndx = endian::swap(t.st_shndx);
 }
@@ -113,24 +113,24 @@ struct _Rel_info {
         r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t)));
     }
     static inline void swap(Elf32_Word &t, Elf64_Xword &r) {
         r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t)));
     }
 };
 
 template <class endian, typename R, typename T>
-inline void Elf_Rel_Traits::swap(T &t, R &r)
+void Elf_Rel_Traits::swap(T &t, R &r)
 {
     r.r_offset = endian::swap(t.r_offset);
     _Rel_info<endian>::swap(t.r_info, r.r_info);
 }
 
 template <class endian, typename R, typename T>
-inline void Elf_Rela_Traits::swap(T &t, R &r)
+void Elf_Rela_Traits::swap(T &t, R &r)
 {
     r.r_offset = endian::swap(t.r_offset);
     _Rel_info<endian>::swap(t.r_info, r.r_info);
     r.r_addend = endian::swap(t.r_addend);
 }
 
 static const Elf32_Shdr null32_section =
     { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 };
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -248,17 +248,16 @@ MOZ_LIBVPX_INCLUDES = @MOZ_LIBVPX_INCLUD
 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@
-MOZ_MATHML = @MOZ_MATHML@
 MOZ_CSS_ANIMATIONS = @MOZ_CSS_ANIMATIONS@
 MOZ_PERMISSIONS = @MOZ_PERMISSIONS@
 MOZ_XTF = @MOZ_XTF@
 MOZ_SVG_DLISTS = @MOZ_SVG_DLISTS@
 MOZ_CAIRO_CFLAGS = @MOZ_CAIRO_CFLAGS@
 MOZ_SMIL = @MOZ_SMIL@
 MOZ_XSLT_STANDALONE = @MOZ_XSLT_STANDALONE@
 
--- a/configure.in
+++ b/configure.in
@@ -2204,18 +2204,16 @@ ia64*-hpux*)
 
     MOZ_GFX_OPTIMIZE_MOBILE=1
     # If we're building with --enable-profiling, we need a frame pointer.
     if test -z "$MOZ_PROFILING"; then
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fomit-frame-pointer"
     else
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer"
     fi
-    # The Maemo builders don't know about this flag
-    MOZ_ARM_VFP_FLAGS="-mfpu=vfp"
     ;;
 
 *-*linux*)
     # Note: both GNU_CC and INTEL_CC are set when using Intel's C compiler.
     # Similarly for GNU_CXX and INTEL_CXX.
     if test "$INTEL_CC" -o "$INTEL_CXX"; then
         # -Os has been broken on Intel's C/C++ compilers for quite a
         # while; Intel recommends against using it.
@@ -3439,51 +3437,16 @@ fi # $no_x
 
 AC_SUBST(XCFLAGS)
 AC_SUBST(XLDFLAGS)
 AC_SUBST(XLIBS)
 AC_SUBST(XEXT_LIBS)
 AC_SUBST(XT_LIBS)
 AC_SUBST(XSS_LIBS)
 
-if test "$CPU_ARCH" = "arm"; then
-  AC_MSG_CHECKING(for ARM SIMD support in compiler)
-  # We try to link so that this also fails when
-  # building with LTO.
-  AC_TRY_LINK([],
-                 [asm("uqadd8 r1, r1, r2");],
-                 result="yes", result="no")
-  AC_MSG_RESULT("$result")
-  if test "$result" = "yes"; then
-      AC_DEFINE(HAVE_ARM_SIMD)
-      HAVE_ARM_SIMD=1
-  fi
-
-  AC_MSG_CHECKING(for ARM NEON support in compiler)
-  _SAVE_CFLAGS="$CFLAGS"
-  if test "$GNU_CC"; then
-    # gcc needs -mfpu=neon to recognize NEON instructions
-    CFLAGS="$CFLAGS -mfpu=neon -mfloat-abi=softfp"
-  fi
-  # We try to link so that this also fails when
-  # building with LTO.
-  AC_TRY_LINK([],
-                 [asm("vadd.i8 d0, d0, d0");],
-                 result="yes", result="no")
-  AC_MSG_RESULT("$result")
-  if test "$result" = "yes"; then
-      AC_DEFINE(HAVE_ARM_NEON)
-      HAVE_ARM_NEON=1
-  fi
-  CFLAGS="$_SAVE_CFLAGS"
-fi # CPU_ARCH = arm
-
-AC_SUBST(HAVE_ARM_SIMD)
-AC_SUBST(HAVE_ARM_NEON)
-
 dnl ========================================================
 dnl = pthread support
 dnl = Start by checking whether the system support pthreads
 dnl ========================================================
 case "$target_os" in
 darwin*)
     USE_PTHREADS=1
     ;;
@@ -4330,39 +4293,39 @@ fi
 
 MOZ_ALLOCATING_FUNCS="strndup posix_memalign memalign valloc"
 AC_CHECK_FUNCS(strndup posix_memalign memalign valloc)
 
 dnl See if compiler supports some gcc-style attributes
 
 AC_CACHE_CHECK(for __attribute__((always_inline)),
                ac_cv_attribute_always_inline,
-               [AC_TRY_COMPILE([],
-                               [inline void f(void) __attribute__((always_inline));],
+               [AC_TRY_COMPILE([inline void f(void) __attribute__((always_inline));],
+                               [],
                                ac_cv_attribute_always_inline=yes,
                                ac_cv_attribute_always_inline=no)])
 
 AC_CACHE_CHECK(for __attribute__((malloc)),
                ac_cv_attribute_malloc,
-               [AC_TRY_COMPILE([],
-                               [void* f(int) __attribute__((malloc));],
+               [AC_TRY_COMPILE([void* f(int) __attribute__((malloc));],
+                               [],
                                ac_cv_attribute_malloc=yes,
                                ac_cv_attribute_malloc=no)])
 
 AC_CACHE_CHECK(for __attribute__((warn_unused_result)),
                ac_cv_attribute_warn_unused,
-               [AC_TRY_COMPILE([],
-                               [int f(void) __attribute__((warn_unused_result));],
+               [AC_TRY_COMPILE([int f(void) __attribute__((warn_unused_result));],
+                               [],
                                ac_cv_attribute_warn_unused=yes,
                                ac_cv_attribute_warn_unused=no)])
 
 AC_CACHE_CHECK(for __attribute__((noreturn)),
                ac_cv_attribute_noreturn,
-               [AC_TRY_COMPILE([],
-                               [void f(void) __attribute__((noreturn));],
+               [AC_TRY_COMPILE([void f(void) __attribute__((noreturn));],
+                               [],
                                ac_cv_attribute_noreturn=yes,
                                ac_cv_attribute_noreturn=no)])
  
 dnl End of C++ language/feature checks
 AC_LANG_C
 
 dnl ========================================================
 dnl =  Internationalization checks
@@ -4797,17 +4760,16 @@ MOZ_ARG_HEADER(Application)
 
 ENABLE_TESTS=1
 MOZ_ACTIVEX_SCRIPTING_SUPPORT=
 MOZ_BRANDING_DIRECTORY=
 MOZ_OFFICIAL_BRANDING=
 MOZ_FEEDS=1
 MOZ_INSTALLER=1
 MOZ_JSDEBUGGER=1
-MOZ_MATHML=1
 MOZ_CSS_ANIMATIONS=1
 MOZ_MORK=
 MOZ_MORKREADER=1
 MOZ_AUTH_EXTENSION=1
 MOZ_NO_ACTIVEX_SUPPORT=1
 MOZ_NO_FAST_LOAD=
 MOZ_OGG=1
 MOZ_RAW=
@@ -4837,17 +4799,16 @@ MOZ_PSM=1
 MOZ_RDF=1
 MOZ_REFLOW_PERF=
 MOZ_SAFE_BROWSING=
 MOZ_HELP_VIEWER=
 MOZ_SPELLCHECK=1
 MOZ_SPLASHSCREEN=
 MOZ_STORAGE=1
 MOZ_SVG_DLISTS=
-MOZ_THUMB2=
 MOZ_TIMELINE=
 MOZ_TOOLKIT_SEARCH=1
 MOZ_UI_LOCALE=en-US
 MOZ_UNIVERSALCHARDET=1
 MOZ_URL_CLASSIFIER=
 MOZ_XSLT_STANDALONE=
 MOZ_XTF=1
 MOZ_XUL=1
@@ -4889,17 +4850,16 @@ case "$target_os" in
 esac
 
 case "${target}" in
     *-android*|*-linuxandroid*)
         NSS_DISABLE_DBM=1
         USE_ARM_KUSER=1
         MOZ_INSTALLER=
         NECKO_WIFI=
-        MOZ_THUMB2=1
         MOZ_THEME_FASTSTRIPE=1
         MOZ_TREE_FREETYPE=1
         MOZ_MEMORY=1
         ;;
 esac
 
 MOZ_ARG_ENABLE_STRING(application,
 [  --enable-application=APP
@@ -6403,27 +6363,16 @@ MOZ_EXTENSIONS=`${PERL} ${srcdir}/build/
 dnl Ensure every extension exists, to avoid mostly-inscrutable error messages
 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 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)
-fi
-
 AC_DEFINE(MOZ_CSS_ANIMATIONS)
 
 dnl ========================================================
 dnl SVG Display Lists
 dnl ========================================================
 if test -n "$MOZ_SVG_DLISTS"; then
   AC_DEFINE(MOZ_SVG_DLISTS)
 fi
@@ -6971,18 +6920,16 @@ if test $MOZ_PLATFORM_MAEMO; then
          if test "$_LIB_FOUND"; then
             MOZ_PLATFORM_MAEMO_LIBS="$MOZ_PLATFORM_MAEMO_LIBS $LIBCONTENTACTION_LIBS"
             MOZ_PLATFORM_MAEMO_CFLAGS="$MOZ_PLATFORM_MAEMO_CFLAGS $LIBCONTENTACTION_CFLAGS"
             MOZ_ENABLE_CONTENTACTION=1
             AC_DEFINE(MOZ_ENABLE_CONTENTACTION)
             AC_SUBST(MOZ_ENABLE_CONTENTACTION)
          fi
       fi
-
-      MOZ_THUMB2=1
    fi
 
    PKG_CHECK_MODULES(LIBLOCATION,liblocation, _LIB_FOUND=1, _LIB_FOUND=)
    MOZ_PLATFORM_MAEMO_LIBS="$MOZ_PLATFORM_MAEMO_LIBS $LIBLOCATION_LIBS"
    MOZ_PLATFORM_MAEMO_CFLAGS="$MOZ_PLATFORM_MAEMO_CFLAGS $LIBLOCATION_CFLAGS"
    if test "$_LIB_FOUND"; then
       MOZ_MAEMO_LIBLOCATION=1
       AC_DEFINE(MOZ_MAEMO_LIBLOCATION)
@@ -7001,90 +6948,214 @@ if test $MOZ_PLATFORM_MAEMO; then
       AC_MSG_WARN([Cannot find maemo-meegotouch-interfaces-dev or libmdatauri-dev. Disabling meegotouch share ui.])
    fi
    AC_SUBST(MOZ_ENABLE_MEEGOTOUCHSHARE)
 
    AC_SUBST(MOZ_PLATFORM_MAEMO_LIBS)
    AC_SUBST(MOZ_PLATFORM_MAEMO_CFLAGS)
 fi
 
-dnl Setup default CPU arch for arm target
-case "$target_cpu" in
-  arm*)
-    MOZ_ARM_ARCH=armv7
-  ;;
+dnl ========================================================
+dnl = ARM toolchain tweaks
+dnl ========================================================
+
+dnl Defaults
+case "${target}" in
+arm-android-eabi)
+    MOZ_THUMB=yes
+    MOZ_ARCH=armv7-a
+    MOZ_FPU=vfp
+    MOZ_FLOAT_ABI=softfp
+    ;;
+arm*-*)
+    if test -n "$MOZ_PLATFORM_MAEMO"; then
+        MOZ_THUMB=no
+        MOZ_ARCH=armv7-a
+        MOZ_FLOAT_ABI=softfp
+    fi
+    if test "$MOZ_PLATFORM_MAEMO" = 6; then
+        MOZ_THUMB=yes
+    fi
+    ;;
+esac
+
+dnl Kept for compatibility with some buildbot mozconfig
+MOZ_ARG_DISABLE_BOOL(thumb2, [], MOZ_THUMB=no, MOZ_THUMB=yes)
+
+MOZ_ARG_WITH_STRING(thumb,
+[  --with-thumb[[=yes|no|toolchain-default]]]
+[                          Use Thumb instruction set (-mthumb)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-thumb is not supported on non-GNU toolchains])
+    fi
+    MOZ_THUMB=$withval)
+
+MOZ_ARG_WITH_STRING(thumb-interwork,
+[  --with-thumb-interwork[[=yes|no|toolchain-default]]
+                           Use Thumb/ARM instuctions interwork (-mthumb-interwork)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-thumb-interwork is not supported on non-GNU toolchains])
+    fi
+    MOZ_THUMB_INTERWORK=$withval)
+
+MOZ_ARG_WITH_STRING(arch,
+[  --with-arch=[[type|toolchain-default]]
+                           Use specific CPU features (-march=type)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-arch is not supported on non-GNU toolchains])
+    fi
+    MOZ_ARCH=$withval)
+
+MOZ_ARG_WITH_STRING(fpu,
+[  --with-fpu=[[type|toolchain-default]]
+                           Use specific FPU type (-mfpu=type)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-fpu is not supported on non-GNU toolchains])
+    fi
+    MOZ_FPU=$withval)
+
+MOZ_ARG_WITH_STRING(float-abi,
+[  --with-float-abi=[[type|toolchain-default]]
+                           Use specific arm float ABI (-mfloat-abi=type)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-float-abi is not supported on non-GNU toolchains])
+    fi
+    MOZ_FLOAT_ABI=$withval)
+
+MOZ_ARG_WITH_STRING(soft-float,
+[  --with-soft-float[[=yes|no|toolchain-default]]
+                           Use soft float library (-msoft-float)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-soft-float is not supported on non-GNU toolchains])
+    fi
+    MOZ_SOFT_FLOAT=$withval)
+
+case "$MOZ_ARCH" in
+toolchain-default|"")
+    arch_flag=""
+    ;;
+*)
+    arch_flag="-march=$MOZ_ARCH"
+    ;;
 esac
-dnl ========================================================
-dnl = Enable building the Thumb2 instruction set
-dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(thumb2,
- [  --enable-thumb2         Enable Thumb2 instruction set (implies ARMv7)],
-    MOZ_THUMB2=1,
-    MOZ_THUMB2=)
-if test -n "$MOZ_THUMB2"; then
-  MOZ_ARM_ARCH=armv7
-fi
-
-dnl ========================================================
-dnl = Enable building for ARM specific CPU features
-dnl ========================================================
-MOZ_ARG_WITH_STRING(cpu-arch,
-[  --with-cpu-arch=arch      Use specific arm architecture CPU features, default armv7],
-    MOZ_ARM_ARCH=$withval)
-
-if test -n "$MOZ_THUMB2"; then
-  case "$target_cpu" in
-    arm*)
-      if test "$MOZ_ARM_ARCH" != "armv7"; then
-        AC_MSG_ERROR([--enable-thumb2 is not compatible with cpu-arch=$MOZ_ARM_ARCH])
-      fi
-      if test "$GNU_CC"; then
-        AC_DEFINE(MOZ_THUMB2)
-        AC_DEFINE(MOZ_ARM_ARCH)
-        CFLAGS="$CFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS"
-        CXXFLAGS="$CXXFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS"
-        ASFLAGS="$ASFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS"
-      else
-        AC_MSG_ERROR([--enable-thumb2 is not supported for non-GNU toolchains])
-      fi
-    ;;
-    *)
-      AC_MSG_ERROR([--enable-thumb2 is not supported for non-ARM CPU architectures])
-    ;;
-  esac
-elif test "$MOZ_ARM_ARCH" = "armv7"; then
-  case "$target_cpu" in
-    arm*)
-      if test "$GNU_CC"; then
-        AC_DEFINE(MOZ_ARM_ARCH)
-        CFLAGS="$CFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS"
-        CXXFLAGS="$CXXFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS"
-        ASFLAGS="$ASFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS"
-      else
-        AC_MSG_ERROR([--with-cpu-arch=armv7 is not supported for non-GNU toolchains])
-      fi
-    ;;
-    *)
-      AC_MSG_ERROR([--with-cpu-arch=armv7 is not supported for non-ARM CPU architectures])
-    ;;
-  esac
-else
-  case "$target_cpu" in
-    arm*)
-      if test "$GNU_CC"; then
-        CFLAGS="$CFLAGS -march=armv5te -mthumb-interwork -msoft-float"
-        CXXFLAGS="$CXXFLAGS -march=armv5te -mthumb-interwork -msoft-float"
-        ASFLAGS="$ASFLAGS -march=armv5te -mthumb-interwork -msoft-float"
-      fi
-      ;;
-  esac
+
+case "$MOZ_THUMB" in
+yes)
+    MOZ_THUMB2=1
+    thumb_flag="-mthumb"
+    ;;
+no)
+    MOZ_THUMB2=
+    thumb_flag="-marm"
+    ;;
+*)
+    _SAVE_CFLAGS="$CFLAGS"
+    CFLAGS="$arch_flag"
+    AC_TRY_COMPILE([],[return sizeof(__thumb2__);],
+        MOZ_THUMB2=1,
+        MOZ_THUMB2=)
+    CFLAGS="$_SAVE_CFLAGS"
+    thumb_flag=""
+    ;;
+esac
+
+if test "$MOZ_THUMB2" = 1; then
+    AC_DEFINE(MOZ_THUMB2)
+fi
+
+case "$MOZ_THUMB_INTERWORK" in
+yes)
+    thumb_interwork_flag="-mthumb-interwork"
+    ;;
+no)
+    thumb_interwork_flag="-mno-thumb-interwork"
+    ;;
+*) # toolchain-default
+    thumb_interwork_flag=""
+    ;;
+esac
+
+case "$MOZ_FPU" in
+toolchain-default|"")
+    fpu_flag=""
+    ;;
+*)
+    fpu_flag="-mfpu=$MOZ_FPU"
+    ;;
+esac
+
+case "$MOZ_FLOAT_ABI" in
+toolchain-default|"")
+    float_abi_flag=""
+    ;;
+*)
+    float_abi_flag="-mfloat-abi=$MOZ_FLOAT_ABI"
+    ;;
+esac
+
+case "$MOZ_SOFT_FLOAT" in
+yes)
+    soft_float_flag="-msoft-float"
+    ;;
+no)
+    soft_float_flag="-mno-soft-float"
+    ;;
+*) # toolchain-default
+    soft_float_flag=""
+    ;;
+esac
+
+dnl Use echo to avoid accumulating space characters
+all_flags=`echo $arch_flag $thumb_flag $thumb_interwork_flag $fpu_flag $float_abi_flag $soft_float_flag`
+if test -n "$all_flags"; then
+    _SAVE_CFLAGS="$CFLAGS"
+    CFLAGS="$all_flags"
+    AC_MSG_CHECKING(whether the chosen combination of compiler flags ($all_flags) works)
+    AC_TRY_COMPILE([],[return 0;],
+        AC_MSG_RESULT([yes]),
+        AC_MSG_ERROR([no]))
+
+    CFLAGS="$_SAVE_CFLAGS $all_flags"
+    CXXFLAGS="$CXXFLAGS $all_flags"
+    ASFLAGS="$ASFLAGS $all_flags"
+    if test -n "$thumb_flag"; then
+        LDFLAGS="$LDFLAGS $thumb_flag"
+    fi
 fi
 
 AC_SUBST(MOZ_THUMB2)
-AC_SUBST(MOZ_ARM_ARCH)
+
+if test "$CPU_ARCH" = "arm"; then
+  AC_MSG_CHECKING(for ARM SIMD support in compiler)
+  # We try to link so that this also fails when
+  # building with LTO.
+  AC_TRY_LINK([],
+                 [asm("uqadd8 r1, r1, r2");],
+                 result="yes", result="no")
+  AC_MSG_RESULT("$result")
+  if test "$result" = "yes"; then
+      AC_DEFINE(HAVE_ARM_SIMD)
+      HAVE_ARM_SIMD=1
+  fi
+
+  AC_MSG_CHECKING(for ARM NEON support in compiler)
+  # We try to link so that this also fails when
+  # building with LTO.
+  AC_TRY_LINK([],
+                 [asm(".fpu neon\n vadd.i8 d0, d0, d0");],
+                 result="yes", result="no")
+  AC_MSG_RESULT("$result")
+  if test "$result" = "yes"; then
+      AC_DEFINE(HAVE_ARM_NEON)
+      HAVE_ARM_NEON=1
+  fi
+fi # CPU_ARCH = arm
+
+AC_SUBST(HAVE_ARM_SIMD)
+AC_SUBST(HAVE_ARM_NEON)
 
 dnl ========================================================
 dnl = faststripe theme
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(faststripe,
 [  --enable-faststripe     Use faststripe theme],
     MOZ_THEME_FASTSTRIPE=1,
     MOZ_THEME_FASTSTRIPE= )
@@ -7424,18 +7495,18 @@ dnl ====================================
 MOZ_ARG_ENABLE_BOOL(wrap-malloc,
 [  --enable-wrap-malloc    Wrap malloc calls (gnu linker only)],
     _WRAP_MALLOC=1,
     _WRAP_MALLOC= )
 
 if test -n "$_WRAP_MALLOC"; then
     if test "$GNU_CC"; then
     WRAP_MALLOC_CFLAGS="${LDFLAGS} ${WRAP_MALLOC_CFLAGS} -Wl,--wrap -Wl,malloc -Wl,--wrap -Wl,calloc -Wl,--wrap -Wl,valloc -Wl,--wrap -Wl,free -Wl,--wrap -Wl,realloc -Wl,--wrap -Wl,memalign -Wl,--wrap -Wl,__builtin_new -Wl,--wrap -Wl,__builtin_vec_new -Wl,--wrap -Wl,__builtin_delete -Wl,--wrap -Wl,__builtin_vec_delete -Wl,--wrap -Wl,PR_Free -Wl,--wrap -Wl,PR_Malloc -Wl,--wrap -Wl,PR_Calloc -Wl,--wrap -Wl,PR_Realloc -Wl,--wrap -Wl,strdup -Wl,--wrap -Wl,strndup -Wl,--wrap -Wl,posix_memalign"
-    MKSHLIB='$(CXX) $(DSO_LDOPTS) $(WRAP_MALLOC_CFLAGS) $(WRAP_MALLOC_LIB) -o $@'
-    MKCSHLIB='$(CC) $(DSO_LDOPTS) $(WRAP_MALLOC_CFLAGS) $(WRAP_MALLOC_LIB) -o $@'
+    MKSHLIB="$MKSHLIB"' $(WRAP_MALLOC_CFLAGS) $(WRAP_MALLOC_LIB)'
+    MKCSHLIB="$MKCSHLIB"' $(WRAP_MALLOC_CFLAGS) $(WRAP_MALLOC_LIB)'
     fi
 fi
 
 dnl ========================================================
 dnl = Location of malloc wrapper lib
 dnl ========================================================
 MOZ_ARG_WITH_STRING(wrap-malloc,
 [  --with-wrap-malloc=DIR  Location of malloc wrapper library],
@@ -8744,17 +8815,16 @@ AC_SUBST(IMPLIB)
 AC_SUBST(FILTER)
 AC_SUBST(BIN_FLAGS)
 AC_SUBST(NS_USE_NATIVE)
 AC_SUBST(MOZ_WIDGET_TOOLKIT)
 AC_SUBST(MOZ_UPDATE_XTERM)
 AC_SUBST(MINIMO)
 AC_SUBST(MOZ_PLATFORM_MAEMO)
 AC_SUBST(MOZ_AUTH_EXTENSION)
-AC_SUBST(MOZ_MATHML)
 AC_SUBST(MOZ_CSS_ANIMATIONS)
 AC_SUBST(MOZ_PERMISSIONS)
 AC_SUBST(MOZ_XTF)
 AC_SUBST(MOZ_PREF_EXTENSIONS)
 AC_SUBST(MOZ_SMIL)
 AC_SUBST(MOZ_XSLT_STANDALONE)
 AC_SUBST(MOZ_JS_LIBS)
 AC_SUBST(MOZ_PSM)
@@ -9289,22 +9359,16 @@ HOST_LDFLAGS="$_SUBDIR_HOST_LDFLAGS"
 RC=
 
 unset MAKEFILES
 unset CONFIG_FILES
 
 # No need to run subconfigures when building with LIBXUL_SDK_DIR
 if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
 
-if test -n "$MOZ_THUMB2"; then
-  _SUBDIR_CONFIG_ARGS="$_SUBDIR_CONFIG_ARGS --enable-thumb2"
-fi
-if test -n "$MOZ_ARM_ARCH"; then
-  _SUBDIR_CONFIG_ARGS="$_SUBDIR_CONFIG_ARGS --with-cpu-arch=$MOZ_ARM_ARCH"
-fi
 if test -n "$_WRAP_MALLOC"; then
   _SUBDIR_CONFIG_ARGS="$_SUBDIR_CONFIG_ARGS --enable-wrap-malloc"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     ac_configure_args="$_SUBDIR_CONFIG_ARGS --with-dist-prefix=$MOZ_BUILD_ROOT/dist --with-mozilla"
     if test -z "$MOZ_DEBUG"; then
         ac_configure_args="$ac_configure_args --disable-debug"
--- a/content/Makefile.in
+++ b/content/Makefile.in
@@ -38,30 +38,26 @@
 DEPTH		= ..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
-PARALLEL_DIRS		= base canvas events html smil svg xml xul xbl xslt
+PARALLEL_DIRS		= base canvas events html mathml smil svg xml xul xbl xslt
 
 ifdef MOZ_MEDIA
 PARALLEL_DIRS	+= media
 endif
 
 ifdef MOZ_XTF
 PARALLEL_DIRS   += xtf
 endif
 
-ifdef MOZ_MATHML
-PARALLEL_DIRS   += mathml
-endif
-
 ifdef ENABLE_TESTS
 TOOL_DIRS += test
 endif
 
 # Prevent floating point errors caused by VC++ optimizations
 ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
 ifeq (,$(filter-out 1200 1300 1310,$(_MSC_VER)))
 CFLAGS += -Op
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -36,16 +36,21 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_Element_h__
 #define mozilla_dom_Element_h__
 
 #include "nsIContent.h"
+#include "nsEventStates.h"
+
+class nsEventStateManager;
+class nsGlobalWindow;
+class nsFocusManager;
 
 // Element-specific flags
 enum {
   // Set if the element has a pending style change.
   ELEMENT_HAS_PENDING_RESTYLE     = (1 << NODE_TYPE_SPECIFIC_BITS_OFFSET),
 
   // Set if the element is a potential restyle root (that is, has a style
   // change pending _and_ that style change will attempt to restyle
@@ -75,22 +80,124 @@ enum {
 
   // Remaining bits are for subclasses
   ELEMENT_TYPE_SPECIFIC_BITS_OFFSET = NODE_TYPE_SPECIFIC_BITS_OFFSET + 4
 };
 
 namespace mozilla {
 namespace dom {
 
+class Link;
+
 class Element : public nsIContent
 {
 public:
 #ifdef MOZILLA_INTERNAL_API
-  Element(already_AddRefed<nsINodeInfo> aNodeInfo) : nsIContent(aNodeInfo) {}
+  Element(already_AddRefed<nsINodeInfo> aNodeInfo) :
+    nsIContent(aNodeInfo),
+    mState(NS_EVENT_STATE_MOZ_READONLY)
+  {}
 #endif // MOZILLA_INTERNAL_API
+
+  /**
+   * Method to get the full state of this element.  See nsEventStates.h for
+   * the possible bits that could be set here.
+   */
+  nsEventStates State() const {
+    // mState is maintained by having whoever might have changed it
+    // call UpdateState() or one of the other mState mutators.
+    return mState;
+  }
+
+  /**
+   * Request an update of the link state for this element.  This will
+   * make sure that if the element is a link at all then either
+   * NS_EVENT_STATE_VISITED or NS_EVENT_STATE_UNVISITED is set in
+   * mState, and a history lookup kicked off if needed to find out
+   * whether the link is really visited.  This method will NOT send any
+   * state change notifications.  If you want them to happen for this
+   * call, you need to handle them yourself.
+   */
+  virtual void RequestLinkStateUpdate();
+
+  /**
+   * Ask this element to update its state.  If aNotify is false, then
+   * state change notifications will not be dispatched; in that
+   * situation it is the caller's responsibility to dispatch them.
+   *
+   * In general, aNotify should only be false if we're guaranteed that
+   * the element can't have a frame no matter what its style is
+   * (e.g. if we're in the middle of adding it to the document or
+   * removing it from the document).
+   */
+  void UpdateState(bool aNotify);
+
+protected:
+  /**
+   * Method to get the _intrinsic_ content state of this element.  This is the
+   * state that is independent of the element's presentation.  To get the full
+   * content state, use State().  See nsEventStates.h for
+   * the possible bits that could be set here.
+   */
+  virtual nsEventStates IntrinsicState() const;
+
+  /**
+   * Method to update mState with link state information.  This does not notify.
+   */
+  void UpdateLinkState(nsEventStates aState);
+
+  /**
+   * Method to add state bits.  This should be called from subclass
+   * constructors to set up our event state correctly at construction
+   * time and other places where we don't want to notify a state
+   * change.
+   */
+  void AddStatesSilently(nsEventStates aStates) {
+    mState |= aStates;
+  }
+
+  /**
+   * Method to remove state bits.  This should be called from subclass
+   * constructors to set up our event state correctly at construction
+   * time and other places where we don't want to notify a state
+   * change.
+   */
+  void RemoveStatesSilently(nsEventStates aStates) {
+    mState &= ~aStates;
+  }
+
+private:
+  // Need to allow the ESM, nsGlobalWindow, and the focus manager to
+  // set our state
+  friend class ::nsEventStateManager;
+  friend class ::nsGlobalWindow;
+  friend class ::nsFocusManager;
+
+  // Also need to allow Link to call UpdateLinkState.
+  friend class Link;
+
+  void NotifyStateChange(nsEventStates aStates);
+
+  // Methods for the ESM to manage state bits.  These will handle
+  // setting up script blockers when they notify, so no need to do it
+  // in the callers unless desired.
+  void AddStates(nsEventStates aStates) {
+    NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
+                    "Should only be adding ESM-managed states here");
+    AddStatesSilently(aStates);
+    NotifyStateChange(aStates);
+  }
+  void RemoveStates(nsEventStates aStates) {
+    NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
+                    "Should only be removing ESM-managed states here");
+    RemoveStatesSilently(aStates);
+    NotifyStateChange(aStates);
+  }
+
+  nsEventStates mState;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 inline mozilla::dom::Element* nsINode::AsElement() {
   NS_ASSERTION(IsElement(), "Not an element?");
   return static_cast<mozilla::dom::Element*>(this);
--- a/content/base/public/nsContentCreatorFunctions.h
+++ b/content/base/public/nsContentCreatorFunctions.h
@@ -106,21 +106,19 @@ NS_NewHTMLElement(nsIContent** aResult, 
                   mozilla::dom::FromParser aFromParser);
 
 // First argument should be nsHTMLTag, but that adds dependency to parser
 // for a bunch of files.
 already_AddRefed<nsGenericHTMLElement>
 CreateHTMLElement(PRUint32 aNodeType, already_AddRefed<nsINodeInfo> aNodeInfo,
                   mozilla::dom::FromParser aFromParser);
 
-#ifdef MOZ_MATHML
 nsresult
 NS_NewMathMLElement(nsIContent** aResult,
                      already_AddRefed<nsINodeInfo> aNodeInfo);
-#endif
 
 #ifdef MOZ_XUL
 nsresult
 NS_NewXULElement(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo);
 
 void
 NS_TrustedNewXULElement(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo);
 #endif
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -59,17 +59,16 @@ class nsIInputStream;
 class nsIClassInfo;
 class nsIBlobBuilder;
 
 nsresult NS_NewBlobBuilder(nsISupports* *aSupports);
 void ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd);
 
 class nsDOMFile : public nsIDOMFile,
                   public nsIXHRSendable,
-                  public nsICharsetDetectionObserver,
                   public nsIJSNativeInitializer
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMBLOB
   NS_DECL_NSIDOMFILE
   NS_DECL_NSIXHRSENDABLE
 
@@ -95,19 +94,16 @@ public:
   {
     NS_ASSERTION(mFile, "must have file");
     // Ensure non-null mContentType
     mContentType.SetIsVoid(PR_FALSE);
   }
 
   virtual ~nsDOMFile() {}
 
-  // from nsICharsetDetectionObserver
-  NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf);
-
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner,
                         JSContext* aCx,
                         JSObject* aObj,
                         PRUint32 aArgc,
                         jsval* aArgv);
 
   // DOMClassInfo constructor (for File("foo"))
@@ -119,23 +115,16 @@ protected:
 
   // start and length in 
   PRUint64 mStart;
   PRUint64 mLength;
 
   nsString mContentType;
   
   bool mIsFullFile;
-
-  // Used during charset detection
-  nsCString mCharset;
-  nsresult GuessCharset(nsIInputStream *aStream,
-                        nsACString &aCharset);
-  nsresult ConvertStream(nsIInputStream *aStream, const char *aCharset,
-                         nsAString &aResult);
 };
 
 class nsDOMMemoryFile : public nsDOMFile
 {
 public:
   nsDOMMemoryFile(void *aMemoryBuffer,
                   PRUint64 aLength,
                   const nsAString& aName,
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -71,18 +71,18 @@ enum nsLinkState {
   eLinkState_Unknown    = 0,
   eLinkState_Unvisited  = 1,
   eLinkState_Visited    = 2,
   eLinkState_NotLink    = 3
 };
 
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID       \
-{ 0x32b94ba0, 0x1ebc, 0x4dfc, \
- { 0xba, 0x8c, 0x5f, 0x24, 0x2b, 0xcb, 0xaf, 0xce } }
+{ 0x860ee35b, 0xe505, 0x438f, \
+ { 0xa7, 0x7b, 0x65, 0xb9, 0xf5, 0x0b, 0xe5, 0x29 } }
 
 /**
  * A node of content in a document's content model. This interface
  * is supported by all content objects.
  */
 class nsIContent : public nsINode {
 public:
 #ifdef MOZILLA_INTERNAL_API
@@ -782,24 +782,16 @@ public:
    * @returns PR_TRUE otherwise.
    */
   virtual PRBool IsDoneAddingChildren()
   {
     return PR_TRUE;
   }
 
   /**
-   * Method to get the _intrinsic_ content state of this content node.  This is
-   * the state that is independent of the node's presentation.  To get the full
-   * content state, use nsEventStateManager.  Also see nsEventStateManager
-   * for the possible bits that could be set here.
-   */
-  virtual nsEventStates IntrinsicState() const;
-
-  /**
    * Get the ID of this content node (the atom corresponding to the
    * value of the null-namespace attribute whose name is given by
    * GetIDAttributeName().  This may be null if there is no ID.
    */
   nsIAtom* GetID() const {
     if (HasID()) {
       return DoGetID();
     }
@@ -859,19 +851,20 @@ public:
    * content node (if applicable).  Returns null if there is no
    * "class" attribute for this type of content node.
    */
   virtual nsIAtom *GetClassAttributeName() const = 0;
 
   /**
    * Should be called when the node can become editable or when it can stop
    * being editable (for example when its contentEditable attribute changes,
-   * when it is moved into an editable parent, ...).
+   * when it is moved into an editable parent, ...).  If aNotify is true and
+   * the node is an element, this will notify the state change.
    */
-  virtual void UpdateEditableState();
+  virtual void UpdateEditableState(PRBool aNotify);
 
   /**
    * Destroy this node and its children. Ideally this shouldn't be needed
    * but for now we need to do it to break cycles.
    */
   virtual void DestroyContent() = 0;
 
   /**
--- a/content/base/public/nsIDOMFile.idl
+++ b/content/base/public/nsIDOMFile.idl
@@ -58,32 +58,24 @@ interface nsIDOMBlob : nsISupports
   // moz-filedata: protocol handler
   [noscript] DOMString getInternalUrl(in nsIPrincipal principal);
 
   [optional_argc] nsIDOMBlob mozSlice(in long long start,
                                       [optional] in long long end,
                                       [optional] in DOMString contentType);
 };
 
-[scriptable, uuid(91c9ebd9-2a4a-4a38-9412-ef492a2799be)]
+[scriptable, uuid(b096ef67-7b77-47f8-8e70-5d8ee36416bf)]
 interface nsIDOMFile : nsIDOMBlob
 {
   readonly attribute DOMString name;
   readonly attribute DOMString mozFullPath;
 
   // This performs no security checks!
   [noscript] readonly attribute DOMString mozFullPathInternal;
-
-  // These are all deprecated and not in spec. Will be removed in a future
-  // release
-  readonly attribute DOMString fileName;
-  readonly attribute unsigned long long fileSize;
-  DOMString getAsText(in DOMString encoding); // raises(FileException) on retrieval
-  DOMString getAsDataURL();             // raises(FileException) on retrieval
-  DOMString getAsBinary();              // raises(FileException) on retrieval
 };
 
 [scriptable, uuid(c4a77171-039b-4f84-97f9-820fb51626af)]
 interface nsIDOMMozBlobBuilder : nsISupports
 {
   nsIDOMBlob getBlob([optional] in DOMString contentType);
   [implicit_jscontext] void append(in jsval data);
 };
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -751,17 +751,18 @@ public:
   virtual void EndUpdate(nsUpdateType aUpdateType) = 0;
   virtual void BeginLoad() = 0;
   virtual void EndLoad() = 0;
 
   enum ReadyState { READYSTATE_UNINITIALIZED = 0, READYSTATE_LOADING = 1, READYSTATE_INTERACTIVE = 3, READYSTATE_COMPLETE = 4};
   virtual void SetReadyStateInternal(ReadyState rs) = 0;
   virtual ReadyState GetReadyStateEnum() = 0;
 
-  // notify that a content node changed state
+  // notify that a content node changed state.  This must happen under
+  // a scriptblocker but NOT within a begin/end update.
   virtual void ContentStateChanged(nsIContent* aContent,
                                    nsEventStates aStateMask) = 0;
 
   // Notify that a document state has changed.
   // This should only be called by callers whose state is also reflected in the
   // implementation of nsDocument::GetDocumentState.
   virtual void DocumentStatesChanged(nsEventStates aStateMask) = 0;
 
--- a/content/base/public/nsIDocumentObserver.h
+++ b/content/base/public/nsIDocumentObserver.h
@@ -51,18 +51,17 @@ class nsIDocument;
 #define NS_IDOCUMENT_OBSERVER_IID \
 { 0x900bc4bc, 0x8b6c, 0x4cba, \
  { 0x82, 0xfa, 0x56, 0x8a, 0x80, 0xff, 0xfd, 0x3e } }
 
 typedef PRUint32 nsUpdateType;
 
 #define UPDATE_CONTENT_MODEL 0x00000001
 #define UPDATE_STYLE         0x00000002
-#define UPDATE_CONTENT_STATE 0x00000004
-#define UPDATE_ALL (UPDATE_CONTENT_MODEL | UPDATE_STYLE | UPDATE_CONTENT_STATE)
+#define UPDATE_ALL (UPDATE_CONTENT_MODEL | UPDATE_STYLE)
 
 // Document observer interface
 class nsIDocumentObserver : public nsIMutationObserver
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_OBSERVER_IID)
 
   /**
--- a/content/base/src/Link.cpp
+++ b/content/base/src/Link.cpp
@@ -48,22 +48,23 @@
 #include "nsString.h"
 #include "mozAutoDocUpdate.h"
 
 #include "mozilla/Services.h"
 
 namespace mozilla {
 namespace dom {
 
-Link::Link()
+Link::Link(Element *aElement)
   : mLinkState(defaultState)
   , mRegistered(false)
-  , mContent(NULL)
+  , mElement(aElement)
   , mHistory(services::GetHistoryService())
 {
+  NS_ABORT_IF_FALSE(mElement, "Must have an element");
 }
 
 Link::~Link()
 {
   UnregisterFromHistory();
 }
 
 nsLinkState
@@ -79,47 +80,40 @@ Link::GetLinkState() const
 void
 Link::SetLinkState(nsLinkState aState)
 {
   NS_ASSERTION(mRegistered,
                "Setting the link state of an unregistered Link!");
   NS_ASSERTION(mLinkState != aState,
                "Setting state to the currently set state!");
 
-  // Remember our old link state for when we notify.
-  nsEventStates oldLinkState = LinkState();
-
   // Set our current state as appropriate.
   mLinkState = aState;
 
   // Per IHistory interface documentation, we are no longer registered.
   mRegistered = false;
 
-  // Notify the document that our visited state has changed.
-  nsIContent *content = Content();
-  nsIDocument *doc = content->GetCurrentDoc();
-  NS_ASSERTION(doc, "Registered but we have no document?!");
-  nsEventStates newLinkState = LinkState();
-  NS_ASSERTION(newLinkState == NS_EVENT_STATE_VISITED ||
-               newLinkState == NS_EVENT_STATE_UNVISITED,
-               "Unexpected state obtained from LinkState()!");
-  mozAutoDocUpdate update(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-  doc->ContentStateChanged(content, oldLinkState ^ newLinkState);
+  NS_ABORT_IF_FALSE(LinkState() == NS_EVENT_STATE_VISITED ||
+                    LinkState() == NS_EVENT_STATE_UNVISITED,
+                    "Unexpected state obtained from LinkState()!");
+
+  // Tell the element to update its visited state
+  mElement->UpdateState(true);
 }
 
 nsEventStates
 Link::LinkState() const
 {
   // We are a constant method, but we are just lazily doing things and have to
   // track that state.  Cast away that constness!
   Link *self = const_cast<Link *>(this);
 
   // If we are not in the document, default to not visited.
-  nsIContent *content = self->Content();
-  if (!content->IsInDoc()) {
+  Element *element = self->mElement;
+  if (!element->IsInDoc()) {
     self->mLinkState = eLinkState_Unvisited;
   }
 
   // If we have not yet registered for notifications and are in an unknown
   // state, register now!
   if (!mRegistered && mLinkState == eLinkState_Unknown) {
     // First, make sure the href attribute has a valid link (bug 23209).
     nsCOMPtr<nsIURI> hrefURI(GetURI());
@@ -132,17 +126,17 @@ Link::LinkState() const
     nsresult rv = mHistory->RegisterVisitedCallback(hrefURI, self);
     if (NS_SUCCEEDED(rv)) {
       self->mRegistered = true;
 
       // Assume that we are not visited until we are told otherwise.
       self->mLinkState = eLinkState_Unvisited;
 
       // And make sure we are in the document's link map.
-      nsIDocument *doc = content->GetCurrentDoc();
+      nsIDocument *doc = element->GetCurrentDoc();
       if (doc) {
         doc->AddStyleRelevantLink(self);
       }
     }
   }
 
   // Otherwise, return our known state.
   if (mLinkState == eLinkState_Visited) {
@@ -163,21 +157,21 @@ Link::GetURI() const
 
   // If we have this URI cached, use it.
   if (uri) {
     return uri.forget();
   }
 
   // Otherwise obtain it.
   Link *self = const_cast<Link *>(this);
-  nsIContent *content = self->Content();
-  uri = content->GetHrefURI();
+  Element *element = self->mElement;
+  uri = element->GetHrefURI();
 
   // We want to cache the URI if the node is in the document.
-  if (uri && content->IsInDoc()) {
+  if (uri && element->IsInDoc()) {
     mCachedURI = uri;
   }
 
   return uri.forget();
 }
 
 nsresult
 Link::SetProtocol(const nsAString &aProtocol)
@@ -462,41 +456,42 @@ Link::GetHash(nsAString &_hash)
 void
 Link::ResetLinkState(bool aNotify)
 {
   // If we are in our default state, bail early.
   if (mLinkState == defaultState) {
     return;
   }
 
-  nsIContent *content = Content();
+  Element *element = mElement;
 
   // Tell the document to forget about this link if we were a link before.
-  nsIDocument *doc = content->GetCurrentDoc();
+  nsIDocument *doc = element->GetCurrentDoc();
   if (doc && mLinkState != eLinkState_NotLink) {
     doc->ForgetLink(this);
   }
 
   UnregisterFromHistory();
 
   // Update our state back to the default.
   mLinkState = defaultState;
 
   // Get rid of our cached URI.
   mCachedURI = nsnull;
 
-  // If aNotify is true, notify both of the visited-related states.  We have
-  // to do that, because we might be racing with a response from history and
-  // hence need to make sure that we get restyled whether we were visited or
-  // not before.  In particular, we need to make sure that our LinkState() is
-  // called so that we'll start a new history query as needed.
-  if (aNotify && doc) {
-    nsEventStates changedState = NS_EVENT_STATE_VISITED ^ NS_EVENT_STATE_UNVISITED;
-    MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, aNotify);
-    doc->ContentStateChanged(content, changedState);
+  // We have to be very careful here: if aNotify is false we do NOT
+  // want to call UpdateState, because that will call into LinkState()
+  // and try to start off loads, etc.  But ResetLinkState is called
+  // with aNotify false when things are in inconsistent states, so
+  // we'll get confused in that situation.  Instead, just silently
+  // update the link state on mElement.
+  if (aNotify) {
+    mElement->UpdateState(aNotify);
+  } else {
+    mElement->UpdateLinkState(nsEventStates());
   }
 }
 
 void
 Link::UnregisterFromHistory()
 {
   // If we are not registered, we have nothing to do.
   if (!mRegistered) {
@@ -527,26 +522,14 @@ Link::GetURIToMutate()
 
 void
 Link::SetHrefAttribute(nsIURI *aURI)
 {
   NS_ASSERTION(aURI, "Null URI is illegal!");
 
   nsCAutoString href;
   (void)aURI->GetSpec(href);
-  (void)Content()->SetAttr(kNameSpaceID_None, nsGkAtoms::href,
-                           NS_ConvertUTF8toUTF16(href), PR_TRUE);
-}
-
-nsIContent *
-Link::Content()
-{
-  if (NS_LIKELY(mContent)) {
-    return mContent;
-  }
-
-  nsCOMPtr<nsIContent> content(do_QueryInterface(this));
-  NS_ABORT_IF_FALSE(content, "This must be able to QI to nsIContent!");
-  return mContent = content;
+  (void)mElement->SetAttr(kNameSpaceID_None, nsGkAtoms::href,
+                          NS_ConvertUTF8toUTF16(href), PR_TRUE);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/base/src/Link.h
+++ b/content/base/src/Link.h
@@ -39,33 +39,37 @@
 
 /**
  * This is the base class for all link classes.
  */
 
 #ifndef mozilla_dom_Link_h__
 #define mozilla_dom_Link_h__
 
-#include "nsIContent.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/IHistory.h"
 
 namespace mozilla {
 namespace dom {
 
 #define MOZILLA_DOM_LINK_IMPLEMENTATION_IID \
   { 0xa687a99c, 0x3893, 0x45c0, \
     {0x8e, 0xab, 0xb8, 0xf7, 0xd7, 0x9e, 0x9e, 0x7b } }
 
 class Link : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_LINK_IMPLEMENTATION_IID)
 
   static const nsLinkState defaultState = eLinkState_Unknown;
-  Link();
+
+  /**
+   * aElement is the element pointer corresponding to this link.
+   */
+  Link(Element* aElement);
   nsLinkState GetLinkState() const;
   virtual void SetLinkState(nsLinkState aState);
 
   /**
    * @return NS_EVENT_STATE_VISITED if this link is visited,
    *         NS_EVENT_STATE_UNVISTED if this link is not visited, or 0 if this
    *         link is not actually a link.
    */
@@ -122,22 +126,17 @@ private:
   void SetHrefAttribute(nsIURI *aURI);
 
   nsLinkState mLinkState;
 
   mutable nsCOMPtr<nsIURI> mCachedURI;
 
   bool mRegistered;
 
-  /**
-   * Obtains a pointer to the nsIContent interface that classes inheriting from
-   * this should also inherit from.
-   */
-  nsIContent *Content();
-  nsIContent *mContent;
+  Element * const mElement;
 
   // Strong reference to History.  The link has to unregister before History
   // can disappear.
   nsCOMPtr<IHistory> mHistory;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(Link, MOZILLA_DOM_LINK_IMPLEMENTATION_IID)
 
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -1475,46 +1475,30 @@ nsContentSink::BeginUpdate(nsIDocument *
   }
 
   // If we're in a script and we didn't do the notification,
   // something else in the script processing caused the
   // notification to occur. Since this could result in frame
   // creation, make sure we've flushed everything before we
   // continue.
 
-  // Note that UPDATE_CONTENT_STATE notifications never cause
-  // synchronous frame construction, so we never have to worry about
-  // them here.  The code that handles the async event these
-  // notifications post will flush us out if it needs to.
-
-  // Also, if this is not an UPDATE_CONTENT_STATE notification,
-  // increment mInNotification to make sure we don't flush again until
-  // the end of this update, even if nested updates or
-  // FlushPendingNotifications calls happen during it.
-  NS_ASSERTION(aUpdateType && (aUpdateType & UPDATE_ALL) == aUpdateType,
-               "Weird update type bitmask");
-  if (aUpdateType != UPDATE_CONTENT_STATE && !mInNotification++) {
+  if (!mInNotification++) {
     FlushTags();
   }
 }
 
 void
 nsContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
 {
   // If we're in a script and we didn't do the notification,
   // something else in the script processing caused the
   // notification to occur. Update our notion of how much
   // has been flushed to include any new content if ending
-  // this update leaves us not inside a notification.  Note that we
-  // exclude UPDATE_CONTENT_STATE notifications here, since those
-  // never affect the frame model directly while inside the
-  // notification.
-  NS_ASSERTION(aUpdateType && (aUpdateType & UPDATE_ALL) == aUpdateType,
-               "Weird update type bitmask");
-  if (aUpdateType != UPDATE_CONTENT_STATE && !--mInNotification) {
+  // this update leaves us not inside a notification.
+  if (!--mInNotification) {
     UpdateChildCounts();
   }
 }
 
 void
 nsContentSink::DidBuildModelImpl(PRBool aTerminated)
 {
   if (mDocument && !aTerminated) {
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -550,22 +550,16 @@ nsDOMAttribute::GetIsId(PRBool* aReturn)
     *aReturn = PR_FALSE;
     return NS_OK;
   }
 
   *aReturn = mNodeInfo->Equals(idAtom, kNameSpaceID_None);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMAttribute::GetSchemaTypeInfo(nsIDOM3TypeInfo** aReturn)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
 PRBool
 nsDOMAttribute::IsNodeOfType(PRUint32 aFlags) const
 {
     return !(aFlags & ~eATTRIBUTE);
 }
 
 PRUint32
 nsDOMAttribute::GetChildCount() const
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -146,38 +146,38 @@ nsDOMMultipartBlob::MozSlice(PRInt64 aSt
   PRUint64 thisLength;
   rv = GetSize(&thisLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!optional_argc) {
     aEnd = (PRInt64)thisLength;
   }
 
+  // Modifies aStart and aEnd.
   ParseSize((PRInt64)thisLength, aStart, aEnd);
 
   // If we clamped to nothing we create an empty blob
   nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
 
-  PRInt64 length = aEnd - aStart;
-  PRUint64 finalLength = length;
+  PRUint64 length = aEnd - aStart;
   PRUint64 skipStart = aStart;
 
-  NS_ABORT_IF_FALSE(aStart + length <= thisLength, "Er, what?");
+  NS_ABORT_IF_FALSE(PRUint64(aStart) + length <= thisLength, "Er, what?");
 
   // Prune the list of blobs if we can
   PRUint32 i;
   for (i = 0; length && skipStart && i < mBlobs.Length(); i++) {
     nsIDOMBlob* blob = mBlobs[i].get();
 
     PRUint64 l;
     rv = blob->GetSize(&l);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (skipStart < l) {
-      PRInt64 upperBound = NS_MIN<PRInt64>(l - skipStart, length);
+      PRUint64 upperBound = NS_MIN<PRUint64>(l - skipStart, length);
 
       nsCOMPtr<nsIDOMBlob> firstBlob;
       rv = mBlobs.ElementAt(i)->MozSlice(skipStart, skipStart + upperBound,
                                          aContentType, 2,
                                          getter_AddRefs(firstBlob));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Avoid wrapping a single blob inside an nsDOMMultipartBlob
@@ -207,17 +207,17 @@ nsDOMMultipartBlob::MozSlice(PRInt64 aSt
       rv = mBlobs.ElementAt(i)->MozSlice(0, length, aContentType, 2,
                                          getter_AddRefs(lastBlob));
       NS_ENSURE_SUCCESS(rv, rv);
 
       blobs.AppendElement(lastBlob);
     } else {
       blobs.AppendElement(blob);
     }
-    length -= NS_MIN<PRInt64>(l, length);
+    length -= NS_MIN<PRUint64>(l, length);
   }
 
   // we can create our blob now
   nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartBlob(blobs, aContentType);
   blob.forget(aBlob);
   return NS_OK;
 }
 
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -137,17 +137,16 @@ nsresult DataOwnerAdapter::Create(DataOw
 DOMCI_DATA(File, nsDOMFile)
 DOMCI_DATA(Blob, nsDOMFile)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMFile)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFullFile)
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
-  NS_INTERFACE_MAP_ENTRY(nsICharsetDetectionObserver)
   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFullFile)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFullFile)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsDOMFile)
 NS_IMPL_RELEASE(nsDOMFile)
 
@@ -169,28 +168,16 @@ DOMFileResult(nsresult rv)
 nsDOMFile::NewFile(nsISupports* *aNewObject)
 {
   nsCOMPtr<nsISupports> file = do_QueryObject(new nsDOMFile(nsnull));
   file.forget(aNewObject);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFile::GetFileName(nsAString &aFileName)
-{
-  return GetName(aFileName);
-}
-
-NS_IMETHODIMP
-nsDOMFile::GetFileSize(PRUint64 *aFileSize)
-{
-  return GetSize(aFileSize);
-}
-
-NS_IMETHODIMP
 nsDOMFile::GetName(nsAString &aFileName)
 {
   NS_ASSERTION(mIsFullFile, "Should only be called on files");
   return mFile->GetLeafName(aFileName);
 }
 
 NS_IMETHODIMP
 nsDOMFile::GetMozFullPath(nsAString &aFileName)
@@ -354,241 +341,16 @@ nsDOMFile::GetInternalUrl(nsIPrincipal* 
                                               aPrincipal);
 
   CopyASCIItoUTF16(url, aURL);
   
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFile::GetAsText(const nsAString &aCharset, nsAString &aResult)
-{
-  aResult.Truncate();
-
-  nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = GetInternalStream(getter_AddRefs(stream));
-  NS_ENSURE_SUCCESS(rv, DOMFileResult(rv));
-
-  nsCAutoString charsetGuess;
-  if (!aCharset.IsEmpty()) {
-    CopyUTF16toUTF8(aCharset, charsetGuess);
-  } else {
-    rv = GuessCharset(stream, charsetGuess);
-    NS_ENSURE_SUCCESS(rv, DOMFileResult(rv));
-
-    nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(stream);
-    if (!seekable) return NS_ERROR_FAILURE;
-    rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
-    NS_ENSURE_SUCCESS(rv, DOMFileResult(rv));
-  }
-
-  nsCAutoString charset;
-  nsCOMPtr<nsICharsetAlias> alias =
-    do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = alias->GetPreferred(charsetGuess, charset);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return DOMFileResult(ConvertStream(stream, charset.get(), aResult));
-}
-
-NS_IMETHODIMP
-nsDOMFile::GetAsDataURL(nsAString &aResult)
-{
-  aResult.AssignLiteral("data:");
-
-  nsresult rv;
-  if (!mContentType.Length()) {
-    nsCOMPtr<nsIMIMEService> mimeService =
-      do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCAutoString contentType;
-    rv = mimeService->GetTypeFromFile(mFile, contentType);
-    if (NS_SUCCEEDED(rv)) {
-      CopyUTF8toUTF16(contentType, mContentType);
-    }
-  }
-
-  if (mContentType.Length()) {
-    aResult.Append(mContentType);
-  } else {
-    aResult.AppendLiteral("application/octet-stream");
-  }
-  aResult.AppendLiteral(";base64,");
-
-  nsCOMPtr<nsIInputStream> stream;
-  rv = GetInternalStream(getter_AddRefs(stream));
-  NS_ENSURE_SUCCESS(rv, DOMFileResult(rv));
-
-  char readBuf[4096];
-  PRUint32 leftOver = 0;
-  PRUint32 numRead;
-  do {
-    rv = stream->Read(readBuf + leftOver, sizeof(readBuf) - leftOver, &numRead);
-    NS_ENSURE_SUCCESS(rv, DOMFileResult(rv));
-
-    PRUint32 numEncode = numRead + leftOver;
-    leftOver = 0;
-
-    if (numEncode == 0) break;
-
-    // unless this is the end of the file, encode in multiples of 3
-    if (numRead > 0) {
-      leftOver = numEncode % 3;
-      numEncode -= leftOver;
-    }
-
-    // out buffer should be at least 4/3rds the read buf, plus a terminator
-    char *base64 = PL_Base64Encode(readBuf, numEncode, nsnull);
-    if (!base64) {
-      return DOMFileResult(NS_ERROR_OUT_OF_MEMORY);
-    }
-    nsDependentCString str(base64);
-    PRUint32 strLen = str.Length();
-    PRUint32 oldLength = aResult.Length();
-    AppendASCIItoUTF16(str, aResult);
-    PR_Free(base64);
-    if (aResult.Length() - oldLength != strLen) {
-      return DOMFileResult(NS_ERROR_OUT_OF_MEMORY);
-    }
-
-    if (leftOver) {
-      memmove(readBuf, readBuf + numEncode, leftOver);
-    }
-  } while (numRead > 0);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMFile::GetAsBinary(nsAString &aResult)
-{
-  aResult.Truncate();
-
-  nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = GetInternalStream(getter_AddRefs(stream));
-  NS_ENSURE_SUCCESS(rv, DOMFileResult(rv));
-
-  PRUint32 numRead;
-  do {
-    char readBuf[4096];
-    rv = stream->Read(readBuf, sizeof(readBuf), &numRead);
-    NS_ENSURE_SUCCESS(rv, DOMFileResult(rv));
-    PRUint32 oldLength = aResult.Length();
-    AppendASCIItoUTF16(Substring(readBuf, readBuf + numRead), aResult);
-    if (aResult.Length() - oldLength != numRead) {
-      return DOMFileResult(NS_ERROR_OUT_OF_MEMORY);
-    }
-  } while (numRead > 0);
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMFile::GuessCharset(nsIInputStream *aStream,
-                        nsACString &aCharset)
-{
-
-  if (!mCharset.IsEmpty()) {
-    aCharset = mCharset;
-    return NS_OK;
-  }
-
-  // First try the universal charset detector
-  nsCOMPtr<nsICharsetDetector> detector
-    = do_CreateInstance(NS_CHARSET_DETECTOR_CONTRACTID_BASE
-                        "universal_charset_detector");
-  if (!detector) {
-    // No universal charset detector, try the default charset detector
-    const nsAdoptingCString& detectorName =
-      Preferences::GetLocalizedCString("intl.charset.detector");
-    if (!detectorName.IsEmpty()) {
-      nsCAutoString detectorContractID;
-      detectorContractID.AssignLiteral(NS_CHARSET_DETECTOR_CONTRACTID_BASE);
-      detectorContractID += detectorName;
-      detector = do_CreateInstance(detectorContractID.get());
-    }
-  }
-
-  nsresult rv;
-  if (detector) {
-    detector->Init(this);
-
-    PRBool done;
-    PRUint32 numRead;
-    do {
-      char readBuf[4096];
-      rv = aStream->Read(readBuf, sizeof(readBuf), &numRead);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = detector->DoIt(readBuf, numRead, &done);
-      NS_ENSURE_SUCCESS(rv, rv);
-    } while (!done && numRead > 0);
-
-    rv = detector->Done();
-    NS_ENSURE_SUCCESS(rv, rv);
-  } else {
-    // no charset detector available, check the BOM
-    unsigned char sniffBuf[4];
-    PRUint32 numRead;
-    rv = aStream->Read(reinterpret_cast<char*>(sniffBuf),
-                       sizeof(sniffBuf), &numRead);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (numRead >= 4 &&
-        sniffBuf[0] == 0x00 &&
-        sniffBuf[1] == 0x00 &&
-        sniffBuf[2] == 0xfe &&
-        sniffBuf[3] == 0xff) {
-      mCharset = "UTF-32BE";
-    } else if (numRead >= 4 &&
-               sniffBuf[0] == 0xff &&
-               sniffBuf[1] == 0xfe &&
-               sniffBuf[2] == 0x00 &&
-               sniffBuf[3] == 0x00) {
-      mCharset = "UTF-32LE";
-    } else if (numRead >= 2 &&
-               sniffBuf[0] == 0xfe &&
-               sniffBuf[1] == 0xff) {
-      mCharset = "UTF-16BE";
-    } else if (numRead >= 2 &&
-               sniffBuf[0] == 0xff &&
-               sniffBuf[1] == 0xfe) {
-      mCharset = "UTF-16LE";
-    } else if (numRead >= 3 &&
-               sniffBuf[0] == 0xef &&
-               sniffBuf[1] == 0xbb &&
-               sniffBuf[2] == 0xbf) {
-      mCharset = "UTF-8";
-    }
-  }
-
-  if (mCharset.IsEmpty()) {
-    // no charset detected, default to the system charset
-    nsCOMPtr<nsIPlatformCharset> platformCharset =
-      do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
-    if (NS_SUCCEEDED(rv)) {
-      rv = platformCharset->GetCharset(kPlatformCharsetSel_PlainTextInFile,
-                                       mCharset);
-    }
-  }
-
-  if (mCharset.IsEmpty()) {
-    // no sniffed or default charset, try UTF-8
-    mCharset.AssignLiteral("UTF-8");
-  }
-
-  aCharset = mCharset;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsDOMFile::GetSendInfo(nsIInputStream** aBody,
                        nsACString& aContentType,
                        nsACString& aCharset)
 {
   nsresult rv;
 
   nsCOMPtr<nsIInputStream> stream;
   rv = this->GetInternalStream(getter_AddRefs(stream));
@@ -602,24 +364,16 @@ nsDOMFile::GetSendInfo(nsIInputStream** 
 
   aCharset.Truncate();
 
   stream.forget(aBody);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFile::Notify(const char* aCharset, nsDetectionConfident aConf)
-{
-  mCharset.Assign(aCharset);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsDOMFile::Initialize(nsISupports* aOwner,
                       JSContext* aCx,
                       JSObject* aObj,
                       PRUint32 aArgc,
                       jsval* aArgv)
 {
   nsresult rv;
 
@@ -669,52 +423,16 @@ nsDOMFile::Initialize(nsISupports* aOwne
   rv = file->Exists(&exists);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
 
   mFile = file;
   return NS_OK;
 }
 
-nsresult
-nsDOMFile::ConvertStream(nsIInputStream *aStream,
-                         const char *aCharset,
-                         nsAString &aResult)
-{
-  aResult.Truncate();
-
-  nsCOMPtr<nsIConverterInputStream> converterStream =
-    do_CreateInstance("@mozilla.org/intl/converter-input-stream;1");
-  if (!converterStream) return NS_ERROR_FAILURE;
-
-  nsresult rv = converterStream->Init
-                  (aStream, aCharset,
-                   8192,
-                   nsIConverterInputStream::DEFAULT_REPLACEMENT_CHARACTER);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIUnicharInputStream> unicharStream =
-    do_QueryInterface(converterStream);
-  if (!unicharStream) return NS_ERROR_FAILURE;
-
-  PRUint32 numChars;
-  nsString result;
-  rv = unicharStream->ReadString(8192, result, &numChars);
-  while (NS_SUCCEEDED(rv) && numChars > 0) {
-    PRUint32 oldLength = aResult.Length();
-    aResult.Append(result);
-    if (aResult.Length() - oldLength != result.Length()) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    rv = unicharStream->ReadString(8192, result, &numChars);
-  }
-
-  return rv;
-}
-
 // nsDOMMemoryFile Implementation
 NS_IMETHODIMP
 nsDOMMemoryFile::GetName(nsAString &aFileName)
 {
   NS_ASSERTION(mIsFullFile, "Should only be called on files");
   aFileName = mName;
   return NS_OK;
 }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4198,16 +4198,18 @@ nsDocument::EndLoad()
   } else {
     DispatchContentLoadedEvents();
   }
 }
 
 void
 nsDocument::ContentStateChanged(nsIContent* aContent, nsEventStates aStateMask)
 {
+  NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
+                  "Someone forgot a scriptblocker");
   NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged,
                                (this, aContent, aStateMask));
 }
 
 void
 nsDocument::DocumentStatesChanged(nsEventStates aStateMask)
 {
   // Invalidate our cached state.
@@ -7037,22 +7039,31 @@ nsDocument::CanSavePresentation(nsIReque
   // Check if we have pending network requests
   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
   if (loadGroup) {
     nsCOMPtr<nsISimpleEnumerator> requests;
     loadGroup->GetRequests(getter_AddRefs(requests));
 
     PRBool hasMore = PR_FALSE;
 
+    // We want to bail out if we have any requests other than aNewRequest (or
+    // in the case when aNewRequest is a part of a multipart response the base
+    // channel the multipart response is coming in on).
+    nsCOMPtr<nsIChannel> baseChannel;
+    nsCOMPtr<nsIMultiPartChannel> part(do_QueryInterface(aNewRequest));
+    if (part) {
+      part->GetBaseChannel(getter_AddRefs(baseChannel));
+    }
+
     while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
       nsCOMPtr<nsISupports> elem;
       requests->GetNext(getter_AddRefs(elem));
 
       nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
-      if (request && request != aNewRequest) {
+      if (request && request != aNewRequest && request != baseChannel) {
 #ifdef DEBUG_PAGE_CACHE
         nsCAutoString requestName, docSpec;
         request->GetName(requestName);
         if (mDocumentURI)
           mDocumentURI->GetSpec(docSpec);
 
         printf("document %s has request %s\n",
                docSpec.get(), requestName.get());
@@ -7577,17 +7588,17 @@ 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.
   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);
+  nsAutoScriptBlocker scriptBlocker;
   for (LinkArray::size_type i = 0; i < linksToNotify.Length(); i++) {
     linksToNotify[i]->ResetLinkState(true);
   }
 }
 
 NS_IMETHODIMP
 nsDocument::GetScriptTypeID(PRUint32 *aScriptType)
 {
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -354,23 +354,27 @@ nsFrameMessageManager::ReceiveMessage(ns
         if (!object) {
           continue;
         }
         nsCxPusher pusher;
         NS_ENSURE_STATE(pusher.Push(ctx, PR_FALSE));
 
         JSAutoRequest ar(ctx);
 
+        JSAutoEnterCompartment ac;
+        if (!ac.enter(ctx, object))
+          return NS_ERROR_FAILURE;
+
         // The parameter for the listener function.
         JSObject* param = JS_NewObject(ctx, NULL, NULL, NULL);
         NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
 
         jsval targetv;
         nsContentUtils::WrapNative(ctx,
-                                   JS_GetGlobalObject(ctx),
+                                   JS_GetGlobalForObject(ctx, object),
                                    aTarget, &targetv);
 
         // To keep compatibility with e10s message manager,
         // define empty objects array.
         if (!aObjectsArray) {
           // Because we want JS messages to have always the same properties,
           // create array even if len == 0.
           aObjectsArray = JS_NewArrayObject(ctx, 0, NULL);
@@ -397,37 +401,32 @@ nsFrameMessageManager::ReceiveMessage(ns
         JS_DefineProperty(ctx, param, "sync",
                           BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "objects", OBJECT_TO_JSVAL(aObjectsArray),
                           NULL, NULL, JSPROP_ENUMERATE);
 
         jsval thisValue = JSVAL_VOID;
 
-        JSAutoEnterCompartment ac;
-
-        if (!ac.enter(ctx, object))
-          return NS_ERROR_FAILURE;
-
         jsval funval = JSVAL_VOID;
         if (JS_ObjectIsFunction(ctx, object)) {
           // If the listener is a JS function:
           funval = OBJECT_TO_JSVAL(object);
 
           // A small hack to get 'this' value right on content side where
           // messageManager is wrapped in TabChildGlobal.
           nsCOMPtr<nsISupports> defaultThisValue;
           if (mChrome) {
             defaultThisValue =
               do_QueryInterface(static_cast<nsIContentFrameMessageManager*>(this));
           } else {
             defaultThisValue = aTarget;
           }
           nsContentUtils::WrapNative(ctx,
-                                     JS_GetGlobalObject(ctx),
+                                     JS_GetGlobalForObject(ctx, object),
                                      defaultThisValue, &thisValue);
         } else {
           // If the listener is a JS object which has receiveMessage function:
           NS_ENSURE_STATE(JS_GetProperty(ctx, object, "receiveMessage",
                                          &funval) &&
                           JSVAL_IS_OBJECT(funval) &&
                           !JSVAL_IS_NULL(funval));
           JSObject* funobject = JSVAL_TO_OBJECT(funval);
@@ -441,18 +440,17 @@ nsFrameMessageManager::ReceiveMessage(ns
         argv.set(OBJECT_TO_JSVAL(param));
 
         {
           JSAutoEnterCompartment tac;
 
           JSObject* thisObject = JSVAL_TO_OBJECT(thisValue);
 
           if (!tac.enter(ctx, thisObject) ||
-              !JS_WrapValue(ctx, argv.jsval_addr()) ||
-              !JS_WrapValue(ctx, &funval))
+              !JS_WrapValue(ctx, argv.jsval_addr()))
             return NS_ERROR_UNEXPECTED;
 
           JS_CallFunctionValue(ctx, thisObject,
                                funval, 1, argv.jsval_addr(), &rval);
           if (aJSONRetVal) {
             nsString json;
             if (JS_TryJSON(ctx, &rval) &&
                 JS_Stringify(ctx, &rval, nsnull, JSVAL_NULL,
--- a/content/base/src/nsGenConImageContent.cpp
+++ b/content/base/src/nsGenConImageContent.cpp
@@ -50,16 +50,19 @@
 
 class nsGenConImageContent : public nsXMLElement,
                              public nsImageLoadingContent
 {
 public:
   nsGenConImageContent(already_AddRefed<nsINodeInfo> aNodeInfo)
     : nsXMLElement(aNodeInfo)
   {
+    // nsImageLoadingContent starts out broken, so we start out
+    // suppressed to match it.
+    AddStatesSilently(NS_EVENT_STATE_SUPPRESSED);
   }
 
   nsresult Init(imgIRequest* aImageRequest)
   {
     // No need to notify, since we have no frame.
     return UseAsPrimaryRequest(aImageRequest, PR_FALSE);
   }
 
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -530,17 +530,17 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
       aDocument->SetBidiEnabled();
     }
     // Clear the lazy frame construction bits.
     UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
   }
 
   nsNodeUtils::ParentChainChanged(this);
 
-  UpdateEditableState();
+  UpdateEditableState(PR_FALSE);
 
   NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
   NS_POSTCONDITION(aBindingParent == GetBindingParent(),
                    "Bound to wrong binding parent");
 
   return NS_OK;
 }
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -781,30 +781,102 @@ nsINode::LookupNamespaceURI(const nsAStr
                                                         aNamespaceURI))) {
     SetDOMStringToNull(aNamespaceURI);
   }
 }
 
 //----------------------------------------------------------------------
 
 nsEventStates
-nsIContent::IntrinsicState() const
+Element::IntrinsicState() const
 {
   return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
                         NS_EVENT_STATE_MOZ_READONLY;
 }
 
 void
-nsIContent::UpdateEditableState()
-{
+Element::NotifyStateChange(nsEventStates aStates)
+{
+  nsIDocument* doc = GetCurrentDoc();
+  if (doc) {
+    nsAutoScriptBlocker scriptBlocker;
+    doc->ContentStateChanged(this, aStates);
+  }
+}
+
+void
+Element::RequestLinkStateUpdate()
+{
+}
+
+void
+Element::UpdateLinkState(nsEventStates aState)
+{
+  NS_ABORT_IF_FALSE(!aState.HasAtLeastOneOfStates(~(NS_EVENT_STATE_VISITED |
+                                                    NS_EVENT_STATE_UNVISITED)),
+                    "Unexpected link state bits");
+  mState =
+    (mState & ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) |
+    aState;
+}
+
+void
+Element::UpdateState(bool aNotify)
+{
+  nsEventStates oldState = mState;
+  mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES);
+  if (aNotify) {
+    nsEventStates changedStates = oldState ^ mState;
+    if (!changedStates.IsEmpty()) {
+      nsIDocument* doc = GetCurrentDoc();
+      if (doc) {
+        nsAutoScriptBlocker scriptBlocker;
+        doc->ContentStateChanged(this, changedStates);
+      }
+    }
+  }
+}
+
+void
+nsIContent::UpdateEditableState(PRBool aNotify)
+{
+  // Guaranteed to be non-element content
+  NS_ASSERTION(!IsElement(), "What happened here?");
   nsIContent *parent = GetParent();
 
   SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
 }
 
+void
+nsGenericElement::UpdateEditableState(PRBool aNotify)
+{
+  nsIContent *parent = GetParent();
+
+  PRBool oldEditable = IsEditable();
+  SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
+  PRBool newEditable = IsEditable();
+  if (oldEditable != newEditable) {
+    if (aNotify) {
+      UpdateState(aNotify);
+    } else {
+      // Avoid calling UpdateState in this very common case, because
+      // this gets called for pretty much every single element on
+      // insertion into the document and UpdateState can be slow for
+      // some kinds of elements even when not notifying.
+      if (oldEditable) {
+        RemoveStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
+        AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
+      } else {
+        RemoveStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
+        AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
+      }
+    }
+  }
+}
+
 nsIContent*
 nsIContent::FindFirstNonNativeAnonymous() const
 {
   // This handles also nested native anonymous content.
   for (const nsIContent *content = this; content;
        content = content->GetBindingParent()) {
     if (!content->IsInNativeAnonymousSubtree()) {
       // Oops, this function signature allows casting const to
@@ -3003,17 +3075,17 @@ nsGenericElement::BindToTree(nsIDocument
         if (binding) {
           rv = BindNodesInInsertPoints(binding, this, aDocument);
           NS_ENSURE_SUCCESS(rv, rv);
         }
       }
     }
   }
 
-  UpdateEditableState();
+  UpdateEditableState(PR_FALSE);
 
   // Now recurse into our kids
   for (nsIContent* child = GetFirstChild(); child;
        child = child->GetNextSibling()) {
     rv = child->BindToTree(aDocument, this, aBindingParent,
                            aCompileEventHandlers);
     NS_ENSURE_SUCCESS(rv, rv);
   }
@@ -4637,23 +4709,16 @@ nsGenericElement::SetAttrAndNotify(PRInt
                                    PRBool aNotify,
                                    const nsAString* aValueForAfterSetAttr)
 {
   nsresult rv;
 
   nsIDocument* document = GetCurrentDoc();
   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
 
-  // When notifying, make sure to keep track of states whose value
-  // depends solely on the value of an attribute.
-  nsEventStates stateMask;
-  if (aNotify) {
-    stateMask = IntrinsicState();
-  }
-
   nsMutationGuard::DidMutate();
 
   if (aNamespaceID == kNameSpaceID_None) {
     // XXXbz Perhaps we should push up the attribute mapping function
     // stuff to nsGenericElement?
     if (!IsAttributeMapped(aName) ||
         !SetMappedAttribute(document, aName, aParsedValue, &rv)) {
       rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue);
@@ -4675,22 +4740,19 @@ nsGenericElement::SetAttrAndNotify(PRInt
       nsRefPtr<nsXBLBinding> binding =
         ownerDoc->BindingManager()->GetBinding(this);
       if (binding) {
         binding->AttributeChanged(aName, aNamespaceID, PR_FALSE, aNotify);
       }
     }
   }
 
+  UpdateState(aNotify);
+
   if (aNotify) {
-    stateMask ^= IntrinsicState();
-    if (document && !stateMask.IsEmpty()) {
-      MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, aNotify);
-      document->ContentStateChanged(this, stateMask);
-    }
     nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
   }
 
   if (aNamespaceID == kNameSpaceID_XMLEvents && 
       aName == nsGkAtoms::event && mNodeInfo->GetDocument()) {
     mNodeInfo->GetDocument()->AddXMLEventsContent(this);
   }
   if (aValueForAfterSetAttr) {
@@ -4874,23 +4936,16 @@ nsGenericElement::UnsetAttr(PRInt32 aNam
   nsIDocument *document = GetCurrentDoc();    
   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
 
   if (aNotify) {
     nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
                                      nsIDOMMutationEvent::REMOVAL);
   }
 
-  // When notifying, make sure to keep track of states whose value
-  // depends solely on the value of an attribute.
-  nsEventStates stateMask;
-  if (aNotify) {
-    stateMask = IntrinsicState();
-  }
-
   PRBool hasMutationListeners = aNotify &&
     nsContentUtils::HasMutationListeners(this,
                                          NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
                                          this);
 
   // Grab the attr node if needed before we remove it from the attr map
   nsCOMPtr<nsIDOMAttr> attrNode;
   if (hasMutationListeners) {
@@ -4920,22 +4975,19 @@ nsGenericElement::UnsetAttr(PRInt32 aNam
       nsRefPtr<nsXBLBinding> binding =
         ownerDoc->BindingManager()->GetBinding(this);
       if (binding) {
         binding->AttributeChanged(aName, aNameSpaceID, PR_TRUE, aNotify);
       }
     }
   }
 
+  UpdateState(aNotify);
+
   if (aNotify) {
-    stateMask ^= IntrinsicState();
-    if (document && !stateMask.IsEmpty()) {
-      MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, aNotify);
-      document->ContentStateChanged(this, stateMask);
-    }
     nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
                                   nsIDOMMutationEvent::REMOVAL);
   }
 
   rv = AfterSetAttr(aNameSpaceID, aName, nsnull, aNotify);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (hasMutationListeners) {
@@ -5056,17 +5108,17 @@ nsGenericElement::List(FILE* out, PRInt3
   fputs(aPrefix.get(), out);
 
   fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
 
   fprintf(out, "@%p", (void *)this);
 
   ListAttributes(out);
 
-  fprintf(out, " intrinsicstate=[%llx]", IntrinsicState().GetInternalValue());
+  fprintf(out, " state=[%llx]", State().GetInternalValue());
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%d<", mRefCnt.get());
 
   PRUint32 i, length = GetChildCount();
   if (length > 0) {
     fputs("\n", out);
 
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -350,16 +350,18 @@ public:
     nsContentUtils::GetNodeTextContent(this, PR_TRUE, aTextContent);
   }
   virtual nsresult SetTextContent(const nsAString& aTextContent)
   {
     return nsContentUtils::SetNodeTextContent(this, aTextContent, PR_FALSE);
   }
 
   // nsIContent interface methods
+  virtual void UpdateEditableState(PRBool aNotify);
+
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
   virtual already_AddRefed<nsINodeList> GetChildren(PRUint32 aFilter);
   virtual nsIAtom *GetClassAttributeName() const;
   virtual already_AddRefed<nsINodeInfo> GetExistingAttrNameFromQName(const nsAString& aStr) const;
@@ -858,17 +860,17 @@ protected:
   {
     return NS_OK;
   }
 
   /**
    * Hook that is called by nsGenericElement::SetAttr to allow subclasses to
    * deal with attribute sets.  This will only be called after we have called
    * SetAndTakeAttr and AttributeChanged (that is, after we have actually set
-   * the attr).
+   * the attr).  It will always be called under a scriptblocker.
    *
    * @param aNamespaceID the namespace of the attr being set
    * @param aName the localname of the attribute being set
    * @param aValue the value it's being set to.  If null, the attr is being
    *        removed.
    * @param aNotify Whether we plan to notify document observers.
    */
   // Note that this is inlined so that when subclasses call it it gets
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1378,17 +1378,16 @@ GK_ATOM(onrepeatEvent, "onrepeatEvent")
 GK_ATOM(repeatCount, "repeatCount")
 GK_ATOM(repeatDur, "repeatDur")
 GK_ATOM(repeatEvent, "repeatEvent")
 GK_ATOM(restart, "restart")
 GK_ATOM(to, "to")
 GK_ATOM(XML, "XML")
 #endif
 
-#ifdef MOZ_MATHML
 // internal MathML attributes: different from columnalign_, columnlines_,
 // fontstyle_, rowalign_ and rowlines_
 GK_ATOM(_moz_math_columnalign_, "_moz-math-columnalign")
 GK_ATOM(_moz_math_columnline_, "_moz-math-columnline")
 GK_ATOM(_moz_math_fontstyle_, "_moz-math-font-style")
 GK_ATOM(_moz_math_rowalign_, "_moz-math-rowalign")
 GK_ATOM(_moz_math_rowline_, "_moz-math-rowline")
 
@@ -1662,17 +1661,16 @@ GK_ATOM(vectorproduct_, "vectorproduct")
 GK_ATOM(vector_, "vector")
 GK_ATOM(verythickmathspace_, "verythickmathspace")
 GK_ATOM(verythinmathspace_, "verythinmathspace")
 GK_ATOM(veryverythickmathspace_, "veryverythickmathspace")
 GK_ATOM(veryverythinmathspace_, "veryverythinmathspace")
 GK_ATOM(voffset_, "voffset")
 GK_ATOM(xref_, "xref")
 GK_ATOM(math, "math") // the only one without an underscore
-#endif
 
 #ifndef DISABLE_XFORMS_HOOKS
 GK_ATOM(avg, "avg")
 GK_ATOM(booleanFromString, "boolean-from-string")
 GK_ATOM(countNonEmpty, "count-non-empty")
 GK_ATOM(daysFromDate, "days-from-date")
 GK_ATOM(init, "init")
 GK_ATOM(instance, "instance")
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -789,18 +789,16 @@ nsImageLoadingContent::UpdateImageState(
     return;
   }
   
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
   if (!thisContent) {
     return;
   }
 
-  nsEventStates oldState = ImageState();
-
   mLoading = mBroken = mUserDisabled = mSuppressed = PR_FALSE;
   
   // If we were blocked by server-based content policy, we claim to be
   // suppressed.  If we were blocked by type-based content policy, we claim to
   // be user-disabled.  Otherwise, claim to be broken.
   if (mImageBlockingStatus == nsIContentPolicy::REJECT_SERVER) {
     mSuppressed = PR_TRUE;
   } else if (mImageBlockingStatus == nsIContentPolicy::REJECT_TYPE) {
@@ -813,27 +811,18 @@ nsImageLoadingContent::UpdateImageState(
     nsresult rv = mCurrentRequest->GetImageStatus(&currentLoadStatus);
     if (NS_FAILED(rv) || (currentLoadStatus & imgIRequest::STATUS_ERROR)) {
       mBroken = PR_TRUE;
     } else if (!(currentLoadStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
       mLoading = PR_TRUE;
     }
   }
 
-  if (aNotify) {
-    nsIDocument* doc = thisContent->GetCurrentDoc();
-    if (doc) {
-      NS_ASSERTION(thisContent->IsInDoc(), "Something is confused");
-      nsEventStates changedBits = oldState ^ ImageState();
-      if (!changedBits.IsEmpty()) {
-        mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(thisContent, changedBits);
-      }
-    }
-  }
+  NS_ASSERTION(thisContent->IsElement(), "Not an element?");
+  thisContent->AsElement()->UpdateState(aNotify);
 }
 
 void
 nsImageLoadingContent::CancelImageRequests(PRBool aNotify)
 {
   AutoStateChanger changer(this, aNotify);
   ClearPendingRequest(NS_BINDING_ABORTED);
   ClearCurrentRequest(NS_BINDING_ABORTED);
--- a/content/base/src/nsNameSpaceManager.cpp
+++ b/content/base/src/nsNameSpaceManager.cpp
@@ -230,21 +230,19 @@ NS_NewElement(nsIContent** aResult, PRIn
   if (aElementType == kNameSpaceID_XHTML) {
     return NS_NewHTMLElement(aResult, aNodeInfo, aFromParser);
   }
 #ifdef MOZ_XUL
   if (aElementType == kNameSpaceID_XUL) {
     return NS_NewXULElement(aResult, aNodeInfo);
   }
 #endif
-#ifdef MOZ_MATHML
   if (aElementType == kNameSpaceID_MathML) {
     return NS_NewMathMLElement(aResult, aNodeInfo);
   }
-#endif
   if (aElementType == kNameSpaceID_SVG) {
     return NS_NewSVGElement(aResult, aNodeInfo, aFromParser);
   }
   if (aElementType == kNameSpaceID_XMLEvents) {
     return NS_NewXMLEventsElement(aResult, aNodeInfo);
   }
 #ifdef MOZ_XTF
   if (aElementType > kNameSpaceID_LastBuiltin) {
@@ -260,19 +258,17 @@ NS_NewElement(nsIContent** aResult, PRIn
 
 PRBool
 NameSpaceManagerImpl::HasElementCreator(PRInt32 aNameSpaceID)
 {
   return aNameSpaceID == kNameSpaceID_XHTML ||
 #ifdef MOZ_XUL
          aNameSpaceID == kNameSpaceID_XUL ||
 #endif
-#ifdef MOZ_MATHML
          aNameSpaceID == kNameSpaceID_MathML ||
-#endif
          aNameSpaceID == kNameSpaceID_SVG ||
          aNameSpaceID == kNameSpaceID_XMLEvents ||
          PR_FALSE;
 }
 
 nsresult NameSpaceManagerImpl::AddNameSpace(const nsAString& aURI,
                                             const PRInt32 aNameSpaceID)
 {
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -332,30 +332,28 @@ nsPluginCrashedEvent::Run()
 class AutoNotifier {
   public:
     AutoNotifier(nsObjectLoadingContent* aContent, PRBool aNotify) :
       mContent(aContent), mNotify(aNotify) {
         mOldType = aContent->Type();
         mOldState = aContent->ObjectState();
     }
     ~AutoNotifier() {
-      if (mNotify) {
-        mContent->NotifyStateChanged(mOldType, mOldState, PR_FALSE);
-      }
+      mContent->NotifyStateChanged(mOldType, mOldState, PR_FALSE, mNotify);
     }
 
     /**
      * Send notifications now, ignoring the value of mNotify. The new type and
      * state is saved, and the destructor will notify again if mNotify is true
      * and the values changed.
      */
     void Notify() {
       NS_ASSERTION(mNotify, "Should not notify when notify=false");
 
-      mContent->NotifyStateChanged(mOldType, mOldState, PR_TRUE);
+      mContent->NotifyStateChanged(mOldType, mOldState, PR_TRUE, PR_TRUE);
       mOldType = mContent->Type();
       mOldState = mContent->ObjectState();
     }
 
   private:
     nsObjectLoadingContent*            mContent;
     PRBool                             mNotify;
     nsObjectLoadingContent::ObjectType mOldType;
@@ -1634,45 +1632,58 @@ nsObjectLoadingContent::UnloadContent()
   }
   mType = eType_Null;
   mUserDisabled = mSuppressed = PR_FALSE;
   mFallbackReason = ePluginOtherState;
 }
 
 void
 nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
-                                          nsEventStates aOldState, PRBool aSync)
+                                           nsEventStates aOldState,
+                                           PRBool aSync,
+                                           PRBool aNotify)
 {
   LOG(("OBJLC [%p]: Notifying about state change: (%u, %llx) -> (%u, %llx) (sync=%i)\n",
        this, aOldType, aOldState.GetInternalValue(), mType,
        ObjectState().GetInternalValue(), aSync));
 
   nsCOMPtr<nsIContent> thisContent = 
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   NS_ASSERTION(thisContent, "must be a content");
 
+  NS_ASSERTION(thisContent->IsElement(), "Not an element?");
+
+  // Unfortunately, we do some state changes without notifying
+  // (e.g. in Fallback when canceling image requests), so we have to
+  // manually notify object state changes.
+  thisContent->AsElement()->UpdateState(false);
+
+  if (!aNotify) {
+    // We're done here
+    return;
+  }
+
   nsIDocument* doc = thisContent->GetCurrentDoc();
   if (!doc) {
     return; // Nothing to do
   }
 
   nsEventStates newState = ObjectState();
 
   if (newState != aOldState) {
     // This will trigger frame construction
     NS_ASSERTION(thisContent->IsInDoc(), "Something is confused");
     nsEventStates changedBits = aOldState ^ newState;
 
     {
-      mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
+      nsAutoScriptBlocker scriptBlocker;
       doc->ContentStateChanged(thisContent, changedBits);
     }
     if (aSync) {
-      // Make sure that frames are actually constructed, and do it after
-      // EndUpdate was called.
+      // Make sure that frames are actually constructed immediately.
       doc->FlushPendingNotifications(Flush_Frames);
     }
   } else if (aOldType != mType) {
     // If our state changed, then we already recreated frames
     // Otherwise, need to do that here
     nsCOMPtr<nsIPresShell> shell = doc->GetShell();
     if (shell) {
       shell->RecreateFramesFor(thisContent);
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -251,19 +251,20 @@ class nsObjectLoadingContent : public ns
     /**
      * Notifies document observes about a new type/state of this object.
      * Triggers frame construction as needed. mType must be set correctly when
      * this method is called. This method is cheap if the type and state didn't
      * actually change.
      *
      * @param aSync If a synchronous frame construction is required. If false,
      *              the construction may either be sync or async.
+     * @param aNotify if false, only need to update the state of our element.
      */
     void NotifyStateChanged(ObjectType aOldType, nsEventStates aOldState,
-                            PRBool aSync);
+                            PRBool aSync, PRBool aNotify);
 
     /**
      * Fires the "Plugin not found" event. This function doesn't do any checks
      * whether it should be fired, the caller should do that.
      */
     static void FirePluginError(nsIContent* thisContent, PluginSupportState state);
 
     ObjectType GetTypeOfContent(const nsCString& aMIMEType);
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -233,17 +233,16 @@ nsTextNode::UnbindFromAttribute()
 #ifdef DEBUG
 void
 nsTextNode::List(FILE* out, PRInt32 aIndent) const
 {
   PRInt32 index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
 
   fprintf(out, "Text@%p", static_cast<const void*>(this));
-  fprintf(out, " intrinsicstate=[%llx]", IntrinsicState().GetInternalValue());
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%d<", mRefCnt.get());
 
   nsAutoString tmp;
   ToCString(tmp, 0, mText.GetLength());
   fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -153,17 +153,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug403868.xml \
 		test_bug405182.html \
 		test_bug403841.html \
 		test_bug409380.html \
 		test_bug410229.html \
 		test_bug413974.html \
 		test_bug415860.html \
 		test_bug414190.html \
-		test_bug414796.html \
 		test_bug527896.html \
 		test_bug416317-1.html \
 		test_bug416317-2.html \
 		test_XHRSendData.html \
 		file_XHRSendData.sjs \
 		file_XHRSendData_doc.xml \
 		file_XHRSendData_doc.xml^headers^ \
 		file_bug416317.xhtml \
deleted file mode 100644
--- a/content/base/test/test_bug414796.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=414796
--->
-  <title>Test for Bug 414796</title>
-  <script type="text/javascript" src="/MochiKit/packed.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=414796">Mozilla Bug 414796</a>
-<p id="display">
-  <input id="fileList" type="file"></input>
-</p>
-<div id="content" style="display: none">
-</div>
-
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
-
-// Write a test file > 8192 characters
-
-var testData = "asdfblahqwer";
-for (var i = 0; i < 10; i++) {
-  testData = testData + testData;
-}
-
-var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
-var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
-testFile.append("testfile");
-
-var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
-outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-               0666, 0);
-outStream.write(testData, testData.length);
-outStream.close();
-
-var fileList = document.getElementById('fileList');
-fileList.value = testFile.path;
-
-var domFileData = fileList.files[0].getAsText("iso-8859-1");
-ok(domFileData.length == testData.length);
-ok(domFileData == testData);
-
-testFile.remove(false);
-
-</script>
-</pre>
-</body> </html>
--- a/content/base/test/test_bug592366.html
+++ b/content/base/test/test_bug592366.html
@@ -8,41 +8,52 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=592366">Mozilla Bug 592366</a>
 <p id="display"></p>
 <div id="content" style="display: none">
-<iframe onload='runTest();'></iframe>  
-<iframe onload='runTest();'></iframe>  
+<iframe></iframe>
+<iframe></iframe>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-SimpleTest.waitForExplicitFinish();
+
 /** Test for Bug 592366 **/
-var iframesToLoad = 2;
-function runTest() {
-  --iframesToLoad;
-  if (iframesToLoad) {
+
+var gExecuted = false;
+
+function hitEventLoop(times, next)
+{
+  if (times == 0) {
+    next();
     return;
   }
 
-  ok(true, "Obligatory succeeding assertion.");
+  SimpleTest.executeSoon(function() {
+    hitEventLoop(times - 1, next);
+  });
+}
 
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
   var s = document.createElement("script");
-  s.src = "data:text/javascript,parent.ok(false, 'This script should not be executed.');"
-  
+  s.src = "data:text/javascript,parent.gExecuted=true;";
+
   var iframes = document.getElementsByTagName("iframe");
 
   iframes[0].contentDocument.body.appendChild(s);
   iframes[1].contentDocument.body.appendChild(s);
 
-  setTimeout(function() {
+  // It seems to work with 1 event loop hit locally but using 2 given that it
+  // was hsivonen advice.
+  hitEventLoop(2, function() {
+    ok(!gExecuted, "The scripts should not have been executed");
     SimpleTest.finish();
-  }, 500);
-}
+  });
+});
+
 </script>
 </pre>
 </body>
 </html>
-
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -944,17 +944,17 @@ protected:
 
     size_t mFacesCount, mMaxLevelWithCustomImages;
     nsTArray<ImageInfo> mImageInfos;
 
     PRBool mHaveGeneratedMipmap;
     FakeBlackStatus mFakeBlackStatus;
 
     void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
-        mMaxLevelWithCustomImages = PR_MAX(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
+        mMaxLevelWithCustomImages = NS_MAX(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
         mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount);
     }
 
     PRBool CheckFloatTextureFilterParams() const {
         // Without OES_texture_float_linear, only NEAREST and NEAREST_MIMPAMP_NEAREST are supported
         return (mMagFilter == LOCAL_GL_NEAREST) &&
             (mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     }
@@ -974,18 +974,18 @@ protected:
         ImageInfo expected = ImageInfoAt(0, face);
 
         // checks if custom level>0 images are all defined up to the highest level defined
         // and have the expected dimensions
         for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
             const ImageInfo& actual = ImageInfoAt(level, face);
             if (actual != expected)
                 return PR_FALSE;
-            expected.mWidth = PR_MAX(1, expected.mWidth >> 1);
-            expected.mHeight = PR_MAX(1, expected.mHeight >> 1);
+            expected.mWidth = NS_MAX(1, expected.mWidth >> 1);
+            expected.mHeight = NS_MAX(1, expected.mHeight >> 1);
 
             // if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
             // of extra useless levels.
             if (actual.mWidth == 1 && actual.mHeight == 1)
                 return PR_TRUE;
         }
 
         // if we're here, we've exhausted all levels without finding a 1x1 image
@@ -1086,17 +1086,17 @@ public:
             // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
             // we need to compute now all the mipmap image info.
 
             // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
             // and are power-of-two.
             ImageInfo imageInfo = ImageInfoAt(0, 0);
             NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
 
-            WebGLsizei size = PR_MAX(imageInfo.mWidth, imageInfo.mHeight);
+            WebGLsizei size = NS_MAX(imageInfo.mWidth, imageInfo.mHeight);
 
             // so, the size is a power of two, let's find its log in base 2.
             size_t maxLevel = 0;
             for (WebGLsizei n = size; n > 1; n >>= 1)
                 ++maxLevel;
 
             EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
 
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -739,23 +739,23 @@ WebGLContext::CopyTexSubImage2D_base(Web
             || x+width <= 0
             || y >= framebufferHeight
             || y+height <= 0)
         {
             // we are completely outside of range, can exit now with buffer filled with zeros
             return NS_OK;
         }
 
-        GLint   actual_x             = PR_MIN(framebufferWidth, PR_MAX(0, x));
-        GLint   actual_x_plus_width  = PR_MIN(framebufferWidth, PR_MAX(0, x + width));
+        GLint   actual_x             = NS_MIN(framebufferWidth, NS_MAX(0, x));
+        GLint   actual_x_plus_width  = NS_MIN(framebufferWidth, NS_MAX(0, x + width));
         GLsizei actual_width   = actual_x_plus_width  - actual_x;
         GLint   actual_xoffset = xoffset + actual_x - x;
 
-        GLint   actual_y             = PR_MIN(framebufferHeight, PR_MAX(0, y));
-        GLint   actual_y_plus_height = PR_MIN(framebufferHeight, PR_MAX(0, y + height));
+        GLint   actual_y             = NS_MIN(framebufferHeight, NS_MAX(0, y));
+        GLint   actual_y_plus_height = NS_MIN(framebufferHeight, NS_MAX(0, y + height));
         GLsizei actual_height  = actual_y_plus_height - actual_y;
         GLint   actual_yoffset = yoffset + actual_y - y;
 
         gl->fCopyTexSubImage2D(target, level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
     }
 
     return NS_OK;
 }
@@ -2982,22 +2982,22 @@ WebGLContext::ReadPixels_base(WebGLint x
             || y >= boundHeight
             || y+height <= 0)
         {
             // we are completely outside of range, can exit now with buffer filled with zeros
             return NS_OK;
         }
 
         // compute the parameters of the subrect we're actually going to call glReadPixels on
-        GLint   subrect_x      = PR_MAX(x, 0);
-        GLint   subrect_end_x  = PR_MIN(x+width, boundWidth);
+        GLint   subrect_x      = NS_MAX(x, 0);
+        GLint   subrect_end_x  = NS_MIN(x+width, boundWidth);
         GLsizei subrect_width  = subrect_end_x - subrect_x;
 
-        GLint   subrect_y      = PR_MAX(y, 0);
-        GLint   subrect_end_y  = PR_MIN(y+height, boundHeight);
+        GLint   subrect_y      = NS_MAX(y, 0);
+        GLint   subrect_end_y  = NS_MIN(y+height, boundHeight);
         GLsizei subrect_height = subrect_end_y - subrect_y;
 
         if (subrect_width < 0 || subrect_height < 0 ||
             subrect_width > width || subrect_height > height)
             return ErrorInvalidOperation("ReadPixels: integer overflow computing clipped rect size");
 
         // now we know that subrect_width is in the [0..width] interval, and same for heights.
 
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -533,17 +533,17 @@ WebGLContext::InitAndValidateGL()
         GLint maxVertexOutputComponents,
               minFragmentInputComponents;
         gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
         gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &minFragmentInputComponents);
 
         error = gl->fGetError();
         switch (error) {
             case LOCAL_GL_NO_ERROR:
-                mGLMaxVaryingVectors = PR_MIN(maxVertexOutputComponents, minFragmentInputComponents) / 4;
+                mGLMaxVaryingVectors = NS_MIN(maxVertexOutputComponents, minFragmentInputComponents) / 4;
                 break;
             case LOCAL_GL_INVALID_ENUM:
                 mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
                 break;
             default:
                 LogMessage("GL error 0x%x occurred during WebGL context initialization!", error);
                 return PR_FALSE;
         }
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -3228,17 +3228,18 @@ nsCanvasRenderingContext2D::GetMiterLimi
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::IsPointInPath(float x, float y, PRBool *retVal)
 {
     if (!FloatValidate(x,y)) {
         *retVal = PR_FALSE;
         return NS_OK;
     }
 
-    *retVal = mThebes->PointInFill(gfxPoint(x,y));
+    gfxPoint pt(x, y);
+    *retVal = mThebes->PointInFill(mThebes->DeviceToUser(pt));
     return NS_OK;
 }
 
 //
 // image
 //
 
 // drawImage(in HTMLImageElement image, in float dx, in float dy);
@@ -3452,30 +3453,27 @@ NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
 {
     gfxContext::GraphicsOperator thebes_op;
 
 #define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
     if (op.EqualsLiteral(cvsop))   \
         thebes_op = gfxContext::OPERATOR_##thebesop;
 
-    CANVAS_OP_TO_THEBES_OP("clear", CLEAR)
-    else CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
+    CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
     else CANVAS_OP_TO_THEBES_OP("destination-atop", DEST_ATOP)
     else CANVAS_OP_TO_THEBES_OP("destination-in", DEST_IN)
     else CANVAS_OP_TO_THEBES_OP("destination-out", DEST_OUT)
     else CANVAS_OP_TO_THEBES_OP("destination-over", DEST_OVER)
     else CANVAS_OP_TO_THEBES_OP("lighter", ADD)
     else CANVAS_OP_TO_THEBES_OP("source-atop", ATOP)
     else CANVAS_OP_TO_THEBES_OP("source-in", IN)
     else CANVAS_OP_TO_THEBES_OP("source-out", OUT)
     else CANVAS_OP_TO_THEBES_OP("source-over", OVER)
     else CANVAS_OP_TO_THEBES_OP("xor", XOR)
-    // not part of spec, kept here for compat
-    else CANVAS_OP_TO_THEBES_OP("over", OVER)
     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
     else return NS_OK;
 
 #undef CANVAS_OP_TO_THEBES_OP
 
     mThebes->SetOperator(thebes_op);
     return NS_OK;
 }
@@ -3484,20 +3482,17 @@ NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op)
 {
     gfxContext::GraphicsOperator thebes_op = mThebes->CurrentOperator();
 
 #define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
     if (thebes_op == gfxContext::OPERATOR_##thebesop) \
         op.AssignLiteral(cvsop);
 
-    // XXX "darker" isn't really correct
-    CANVAS_OP_TO_THEBES_OP("clear", CLEAR)
-    else CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
-    else CANVAS_OP_TO_THEBES_OP("darker", SATURATE)  // XXX
+    CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
     else CANVAS_OP_TO_THEBES_OP("destination-atop", DEST_ATOP)
     else CANVAS_OP_TO_THEBES_OP("destination-in", DEST_IN)
     else CANVAS_OP_TO_THEBES_OP("destination-out", DEST_OUT)
     else CANVAS_OP_TO_THEBES_OP("destination-over", DEST_OVER)
     else CANVAS_OP_TO_THEBES_OP("lighter", ADD)
     else CANVAS_OP_TO_THEBES_OP("source-atop", ATOP)
     else CANVAS_OP_TO_THEBES_OP("source-in", IN)
     else CANVAS_OP_TO_THEBES_OP("source-out", OUT)
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -1481,17 +1481,17 @@ ok(!_thrown_outer, 'should not throw exc
 
 function test_2d_composite_operation_clear() {
 
 var canvas = document.getElementById('c55');
 var ctx = canvas.getContext('2d');
 
 ctx.globalCompositeOperation = 'xor';
 ctx.globalCompositeOperation = 'clear';
-todo(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'");
+ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'");
 
 
 }
 </script>
 
 <!-- [[[ test_2d.composite.operation.darker.html ]]] -->
 
 <p>Canvas test: 2d.composite.operation.darker</p>
@@ -1614,17 +1614,17 @@ ok(!_thrown_outer, 'should not throw exc
 
 function test_2d_composite_operation_over() {
 
 var canvas = document.getElementById('c61');
 var ctx = canvas.getContext('2d');
 
 ctx.globalCompositeOperation = 'xor';
 ctx.globalCompositeOperation = 'over';
-todo(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'");
+ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'");
 
 
 }
 </script>
 
 <!-- [[[ test_2d.composite.operation.unrecognised.html ]]] -->
 
 <p>Canvas test: 2d.composite.operation.unrecognised - bug 401788</p>
@@ -13271,20 +13271,20 @@ ok(ctx.isPointInPath(50, 10) === true, "
 function test_2d_path_isPointInPath_transform_1() {
 
 var canvas = document.getElementById('c409');
 var ctx = canvas.getContext('2d');
 
 ctx.translate(50, 0);
 ctx.rect(0, 0, 20, 20);
 ok(ctx.isPointInPath(-40, 10) === false, "ctx.isPointInPath(-40, 10) === false");
-todo(ctx.isPointInPath(10, 10) === false, "ctx.isPointInPath(10, 10) === false");
+ok(ctx.isPointInPath(10, 10) === false, "ctx.isPointInPath(10, 10) === false");
 ok(ctx.isPointInPath(49, 10) === false, "ctx.isPointInPath(49, 10) === false");
-todo(ctx.isPointInPath(51, 10) === true, "ctx.isPointInPath(51, 10) === true");
-todo(ctx.isPointInPath(69, 10) === true, "ctx.isPointInPath(69, 10) === true");
+ok(ctx.isPointInPath(51, 10) === true, "ctx.isPointInPath(51, 10) === true");
+ok(ctx.isPointInPath(69, 10) === true, "ctx.isPointInPath(69, 10) === true");
 ok(ctx.isPointInPath(71, 10) === false, "ctx.isPointInPath(71, 10) === false");
 
 
 }
 </script>
 
 <!-- [[[ test_2d.path.isPointInPath.transform.2.html ]]] -->
 
@@ -13296,20 +13296,20 @@ ok(ctx.isPointInPath(71, 10) === false, 
 function test_2d_path_isPointInPath_transform_2() {
 
 var canvas = document.getElementById('c410');
 var ctx = canvas.getContext('2d');
 
 ctx.rect(50, 0, 20, 20);
 ctx.translate(50, 0);
 ok(ctx.isPointInPath(-40, 10) === false, "ctx.isPointInPath(-40, 10) === false");
-todo(ctx.isPointInPath(10, 10) === false, "ctx.isPointInPath(10, 10) === false");
+ok(ctx.isPointInPath(10, 10) === false, "ctx.isPointInPath(10, 10) === false");
 ok(ctx.isPointInPath(49, 10) === false, "ctx.isPointInPath(49, 10) === false");
-todo(ctx.isPointInPath(51, 10) === true, "ctx.isPointInPath(51, 10) === true");
-todo(ctx.isPointInPath(69, 10) === true, "ctx.isPointInPath(69, 10) === true");
+ok(ctx.isPointInPath(51, 10) === true, "ctx.isPointInPath(51, 10) === true");
+ok(ctx.isPointInPath(69, 10) === true, "ctx.isPointInPath(69, 10) === true");
 ok(ctx.isPointInPath(71, 10) === false, "ctx.isPointInPath(71, 10) === false");
 
 
 }
 </script>
 
 <!-- [[[ test_2d.path.isPointInPath.transform.3.html ]]] -->
 
@@ -13323,18 +13323,18 @@ function test_2d_path_isPointInPath_tran
 var canvas = document.getElementById('c411');
 var ctx = canvas.getContext('2d');
 
 ctx.scale(-1, 1);
 ctx.rect(-70, 0, 20, 20);
 ok(ctx.isPointInPath(-40, 10) === false, "ctx.isPointInPath(-40, 10) === false");
 ok(ctx.isPointInPath(10, 10) === false, "ctx.isPointInPath(10, 10) === false");
 ok(ctx.isPointInPath(49, 10) === false, "ctx.isPointInPath(49, 10) === false");
-todo(ctx.isPointInPath(51, 10) === true, "ctx.isPointInPath(51, 10) === true");
-todo(ctx.isPointInPath(69, 10) === true, "ctx.isPointInPath(69, 10) === true");
+ok(ctx.isPointInPath(51, 10) === true, "ctx.isPointInPath(51, 10) === true");
+ok(ctx.isPointInPath(69, 10) === true, "ctx.isPointInPath(69, 10) === true");
 ok(ctx.isPointInPath(71, 10) === false, "ctx.isPointInPath(71, 10) === false");
 
 
 }
 </script>
 
 <!-- [[[ test_2d.path.isPointInPath.unclosed.html ]]] -->
 
--- a/content/canvas/test/test_mozGetAsFile.html
+++ b/content/canvas/test/test_mozGetAsFile.html
@@ -1,35 +1,48 @@
 <!DOCTYPE HTML>
 <title>Canvas test: mozGetAsFile</title>
 <script src="/MochiKit/MochiKit.js"></script>
 <script src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" href="/tests/SimpleTest/test.css">
 <body>
 <canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
+
+function compareAsync(file, canvas, type)
+{
+  SimpleTest.waitForExplicitFinish();
+
+  var reader = new FileReader();
+  reader.onload = 
+    function(e) {
+      is(e.target.result, canvas.toDataURL(type),
+ "<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
+      SimpleTest.finish();
+    };
+  reader.readAsDataURL(file);
+}
+
 SimpleTest.waitForExplicitFinish();
 MochiKit.DOM.addLoadEvent(function () {
 
 var canvas = document.getElementById('c');
 var ctx = canvas.getContext('2d');
 
 ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
 
 var pngfile = canvas.mozGetAsFile("foo.png");
 is(pngfile.type, "image/png", "Default type for mozGetAsFile should be PNG");
-is(pngfile.getAsDataURL(), canvas.toDataURL(),
-   "<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
+compareAsync(pngfile, canvas, "image/png");
 is(pngfile.name, "foo.png", "File name should be what we passed in");
 
 var jpegfile = canvas.mozGetAsFile("bar.jpg", "image/jpeg");
 is(jpegfile.type, "image/jpeg",
    "When a valid type is specified that should be returned");
-is(jpegfile.getAsDataURL(), canvas.toDataURL("image/jpeg"),
-   "<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
+compareAsync(jpegfile, canvas, "image/jpeg");
 is(jpegfile.name, "bar.jpg", "File name should be what we passed in");
 
 SimpleTest.finish();
 
 });
 </script>
 <img src="image_yellow75.png" id="yellow75.png" class="resource">
 
--- a/content/events/public/nsEventStates.h
+++ b/content/events/public/nsEventStates.h
@@ -237,19 +237,17 @@ private:
 #define NS_EVENT_STATE_USERDISABLED  NS_DEFINE_EVENT_STATE_MACRO(20)
 // Content suppressed by the user (ad blocking, etc).
 #define NS_EVENT_STATE_SUPPRESSED    NS_DEFINE_EVENT_STATE_MACRO(21)
 // Content is still loading such that there is nothing to show the
 // user (eg an image which hasn't started coming in yet).
 #define NS_EVENT_STATE_LOADING       NS_DEFINE_EVENT_STATE_MACRO(22)
 // Content is of a type that gecko can't handle.
 #define NS_EVENT_STATE_TYPE_UNSUPPORTED NS_DEFINE_EVENT_STATE_MACRO(23)
-#ifdef MOZ_MATHML
 #define NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL NS_DEFINE_EVENT_STATE_MACRO(24)
-#endif
 // Handler for the content has been blocked.
 #define NS_EVENT_STATE_HANDLER_BLOCKED NS_DEFINE_EVENT_STATE_MACRO(25)
 // Handler for the content has been disabled.
 #define NS_EVENT_STATE_HANDLER_DISABLED NS_DEFINE_EVENT_STATE_MACRO(26)
 // Content is in the indeterminate state.
 #define NS_EVENT_STATE_INDETERMINATE NS_DEFINE_EVENT_STATE_MACRO(27)
 // Handler for the content has crashed
 #define NS_EVENT_STATE_HANDLER_CRASHED NS_DEFINE_EVENT_STATE_MACRO(28)
@@ -263,10 +261,16 @@ private:
 #define NS_EVENT_STATE_MOZ_UI_INVALID NS_DEFINE_EVENT_STATE_MACRO(32)
 // UI friendly version of :valid pseudo-class.
 #define NS_EVENT_STATE_MOZ_UI_VALID NS_DEFINE_EVENT_STATE_MACRO(33)
 
 /**
  * NOTE: do not go over 63 without updating nsEventStates::InternalType!
  */
 
+#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS |     \
+                            NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER |   \
+                            NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING)
+
+#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
+
 #endif // nsEventStates_h__
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -765,17 +765,17 @@ nsMouseWheelTransaction::LimitToOnePageS
   nscoord lineScroll = aIsHorizontal ? lineAmount.width : lineAmount.height;
 
   if (lineScroll == 0)
     return aScrollLines;
 
   nsSize pageAmount = sf->GetPageScrollAmount();
   nscoord pageScroll = aIsHorizontal ? pageAmount.width : pageAmount.height;
 
-  if (PR_ABS(aScrollLines) * lineScroll < pageScroll)
+  if (NS_ABS(aScrollLines) * lineScroll < pageScroll)
     return aScrollLines;
 
   nscoord maxLines = (pageScroll / lineScroll);
   if (maxLines >= 1)
     return ((aScrollLines < 0) ? -1 : 1) * maxLines;
 
   *aScrollQuantity = nsIScrollableFrame::PAGES;
   return (aScrollLines < 0) ? -1 : 1;
@@ -858,16 +858,19 @@ nsEventStateManager::Init()
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (!observerService)
     return NS_ERROR_FAILURE;
 
   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
 
   if (sESMInstanceCount == 1) {
+    sKeyCausesActivation =
+      Preferences::GetBool("accessibility.accesskeycausesactivation",
+                           sKeyCausesActivation);
     sLeftClickOnly =
       Preferences::GetBool("nglayout.events.dispatchLeftClickOnly",
                            sLeftClickOnly);
     sChromeAccessModifier =
       GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeChrome);
     sContentAccessModifier =
       GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeContent);
   }
@@ -1267,32 +1270,32 @@ nsEventStateManager::PreHandleEvent(nsPr
         nscoord pixelHeight = aPresContext->AppUnitsToIntCSSPixels(
           GetScrollableLineHeight(aTargetFrame));
 
         if (msEvent->scrollFlags & nsMouseScrollEvent::kIsVertical) {
           gPixelScrollDeltaX += msEvent->delta;
           if (!gPixelScrollDeltaX || !pixelHeight)
             break;
 
-          if (PR_ABS(gPixelScrollDeltaX) >= pixelHeight) {
+          if (NS_ABS(gPixelScrollDeltaX) >= pixelHeight) {
             PRInt32 numLines = (PRInt32)ceil((float)gPixelScrollDeltaX/(float)pixelHeight);
 
             gPixelScrollDeltaX -= numLines*pixelHeight;
 
             nsWeakFrame weakFrame(aTargetFrame);
             SendLineScrollEvent(aTargetFrame, msEvent, aPresContext,
               aStatus, numLines);
             NS_ENSURE_STATE(weakFrame.IsAlive());
           }
         } else if (msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
           gPixelScrollDeltaY += msEvent->delta;
           if (!gPixelScrollDeltaY || !pixelHeight)
             break;
 
-          if (PR_ABS(gPixelScrollDeltaY) >= pixelHeight) {
+          if (NS_ABS(gPixelScrollDeltaY) >= pixelHeight) {
             PRInt32 numLines = (PRInt32)ceil((float)gPixelScrollDeltaY/(float)pixelHeight);
 
             gPixelScrollDeltaY -= numLines*pixelHeight;
 
             nsWeakFrame weakFrame(aTargetFrame);
             SendLineScrollEvent(aTargetFrame, msEvent, aPresContext,
               aStatus, numLines);
             NS_ENSURE_STATE(weakFrame.IsAlive());
@@ -1985,18 +1988,18 @@ nsEventStateManager::GenerateDragGesture
       if (!pixelThresholdX)
         pixelThresholdX = 5;
       if (!pixelThresholdY)
         pixelThresholdY = 5;
     }
 
     // fire drag gesture if mouse has moved enough
     nsIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
-    if (PR_ABS(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
-        PR_ABS(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
+    if (NS_ABS(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
+        NS_ABS(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
       if (mClickHoldContextMenu) {
         // stop the click-hold before we fire off the drag gesture, in case
         // it takes a long time
         KillClickHoldTimer();
       }
 
       nsRefPtr<nsDOMDataTransfer> dataTransfer = new nsDOMDataTransfer();
       if (!dataTransfer)
@@ -4206,72 +4209,16 @@ GetLabelTarget(nsIContent* aPossibleLabe
 {
   nsHTMLLabelElement* label = nsHTMLLabelElement::FromContent(aPossibleLabel);
   if (!label)
     return nsnull;
 
   return label->GetLabeledElement();
 }
 
-static bool
-IsAncestorOf(nsIContent* aPossibleAncestor, nsIContent* aPossibleDescendant)
-{
-  for (; aPossibleDescendant; aPossibleDescendant = aPossibleDescendant->GetParent()) {
-    if (aPossibleAncestor == aPossibleDescendant)
-      return true;
-
-    Element* labelTarget = GetLabelTarget(aPossibleDescendant);
-    if (labelTarget == aPossibleAncestor)
-      return true;
-  }
-  return false;
-}
-
-static bool
-ShouldShowFocusRing(nsIContent* aContent)
-{
-  nsIDocument* doc = aContent->GetOwnerDoc();
-  if (doc) {
-    nsPIDOMWindow* window = doc->GetWindow();
-    return window && window->ShouldShowFocusRing();
-  }
-
-  return false;
-}
-
-nsEventStates
-nsEventStateManager::GetContentState(nsIContent *aContent)
-{
-  nsEventStates state = aContent->IntrinsicState();
-
-  if (IsAncestorOf(aContent, mActiveContent)) {
-    state |= NS_EVENT_STATE_ACTIVE;
-  }
-  if (IsAncestorOf(aContent, mHoverContent)) {
-    state |= NS_EVENT_STATE_HOVER;
-  }
-
-  nsFocusManager* fm = nsFocusManager::GetFocusManager();
-  nsIContent* focusedContent = fm ? fm->GetFocusedContent() : nsnull;
-  if (aContent == focusedContent) {
-    state |= NS_EVENT_STATE_FOCUS;
-
-    if (ShouldShowFocusRing(aContent)) {
-      state |= NS_EVENT_STATE_FOCUSRING;
-    }
-  }
-  if (aContent == mDragOverContent) {
-    state |= NS_EVENT_STATE_DRAGOVER;
-  }
-  if (aContent == mURLTargetContent) {
-    state |= NS_EVENT_STATE_URLTARGET;
-  }
-  return state;
-}
-
 static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2)
 {
   // Find closest common ancestor
   if (aNode1 && aNode2) {
     // Find the nearest common ancestor by counting the distance to the
     // root and then walking up again, in pairs.
     PRInt32 offset = 0;
     nsIContent *anc1 = aNode1;
@@ -4306,48 +4253,80 @@ static nsIContent* FindCommonAncestor(ns
         anc2 = anc2->GetParent();
       }
       return anc1;
     }
   }
   return nsnull;
 }
 
-static void
-NotifyAncestors(nsIDocument* aDocument, nsIContent* aStartNode,
-                nsIContent* aStopBefore, nsEventStates aState)
+/* static */
+inline void
+nsEventStateManager::DoStateChange(Element* aElement, nsEventStates aState,
+                                   PRBool aAddState)
+{
+  if (aAddState) {
+    aElement->AddStates(aState);
+  } else {
+    aElement->RemoveStates(aState);
+  }
+}
+
+/* static */
+inline void
+nsEventStateManager::DoStateChange(nsIContent* aContent, nsEventStates aState,
+                                   PRBool aStateAdded)
 {
-  while (aStartNode && aStartNode != aStopBefore) {
-    aDocument->ContentStateChanged(aStartNode, aState);
-    Element* labelTarget = GetLabelTarget(aStartNode);
+  if (aContent->IsElement()) {
+    DoStateChange(aContent->AsElement(), aState, aStateAdded);
+  }
+}
+
+/* static */
+void
+nsEventStateManager::UpdateAncestorState(nsIContent* aStartNode,
+                                         nsIContent* aStopBefore,
+                                         nsEventStates aState,
+                                         PRBool aAddState)
+{
+  for (; aStartNode && aStartNode != aStopBefore;
+       aStartNode = aStartNode->GetParent()) {
+    // We might be starting with a non-element (e.g. a text node) and
+    // if someone is doing something weird might be ending with a
+    // non-element too (e.g. a document fragment)
+    if (!aStartNode->IsElement()) {
+      continue;
+    }
+    Element* element = aStartNode->AsElement();
+    DoStateChange(element, aState, aAddState);
+    Element* labelTarget = GetLabelTarget(element);
     if (labelTarget) {
-      aDocument->ContentStateChanged(labelTarget, aState);
+      DoStateChange(labelTarget, aState, aAddState);
     }
-    aStartNode = aStartNode->GetParent();
   }
 }
 
 PRBool
 nsEventStateManager::SetContentState(nsIContent *aContent, nsEventStates aState)
 {
   // We manage 4 states here: ACTIVE, HOVER, DRAGOVER, URLTARGET
   // The input must be exactly one of them.
   NS_PRECONDITION(aState == NS_EVENT_STATE_ACTIVE ||
                   aState == NS_EVENT_STATE_HOVER ||
                   aState == NS_EVENT_STATE_DRAGOVER ||
                   aState == NS_EVENT_STATE_URLTARGET,
                   "Unexpected state");
 
   nsCOMPtr<nsIContent> notifyContent1;
   nsCOMPtr<nsIContent> notifyContent2;
-  PRBool notifyAncestors;
+  PRBool updateAncestors;
 
   if (aState == NS_EVENT_STATE_HOVER || aState == NS_EVENT_STATE_ACTIVE) {
     // Hover and active are hierarchical
-    notifyAncestors = PR_TRUE;
+    updateAncestors = PR_TRUE;
 
     // check to see that this state is allowed by style. Check dragover too?
     // XXX Is this even what we want?
     if (mCurrentTarget)
     {
       const nsStyleUserInterface* ui = mCurrentTarget->GetStyleUserInterface();
       if (ui->mUserInput == NS_STYLE_USER_INPUT_NONE)
         return PR_FALSE;
@@ -4382,56 +4361,69 @@ nsEventStateManager::SetContentState(nsI
 
       if (newHover != mHoverContent) {
         notifyContent1 = newHover;
         notifyContent2 = mHoverContent;
         mHoverContent = newHover;
       }
     }
   } else {
-    notifyAncestors = PR_FALSE;
+    updateAncestors = PR_FALSE;
     if (aState == NS_EVENT_STATE_DRAGOVER) {
       if (aContent != mDragOverContent) {
         notifyContent1 = aContent;
         notifyContent2 = mDragOverContent;
         mDragOverContent = aContent;
       }
     } else if (aState == NS_EVENT_STATE_URLTARGET) {
       if (aContent != mURLTargetContent) {
         notifyContent1 = aContent;
         notifyContent2 = mURLTargetContent;
         mURLTargetContent = aContent;
       }
     }
   }
 
+  // We need to keep track of which of notifyContent1 and notifyContent2 is
+  // getting the state set and which is getting it unset.  If both are
+  // non-null, then notifyContent1 is having the state set and notifyContent2
+  // is having it unset.  But if one of them is null, we need to keep track of
+  // the right thing for notifyContent1 explicitly.
+  PRBool content1StateSet = PR_TRUE;
   if (!notifyContent1) {
     // This is ok because FindCommonAncestor wouldn't find anything
     // anyway if notifyContent1 is null.
     notifyContent1 = notifyContent2;
     notifyContent2 = nsnull;
+    content1StateSet = PR_FALSE;
   }
 
   if (notifyContent1 && mPresContext) {
     EnsureDocument(mPresContext);
     if (mDocument) {
-      MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_STATE, PR_TRUE);
-
-      if (notifyAncestors) {
+      nsAutoScriptBlocker scriptBlocker;
+
+      if (updateAncestors) {
         nsCOMPtr<nsIContent> commonAncestor =
           FindCommonAncestor(notifyContent1, notifyContent2);
-        NotifyAncestors(mDocument, notifyContent1, commonAncestor, aState);
         if (notifyContent2) {
-          NotifyAncestors(mDocument, notifyContent2, commonAncestor, aState);
+          // It's very important to first notify the state removal and
+          // then the state addition, because due to labels it's
+          // possible that we're removing state from some element but
+          // then adding it again (say because mHoverContent changed
+          // from a control to its label).
+          UpdateAncestorState(notifyContent2, commonAncestor, aState, PR_FALSE);
         }
+        UpdateAncestorState(notifyContent1, commonAncestor, aState,
+                            content1StateSet);
       } else {
-        mDocument->ContentStateChanged(notifyContent1, aState);
         if (notifyContent2) {
-          mDocument->ContentStateChanged(notifyContent2, aState);
+          DoStateChange(notifyContent2, aState, PR_FALSE);
         }
+        DoStateChange(notifyContent1, aState, content1StateSet);
       }
     }
   }
 
   return PR_TRUE;
 }
 
 void
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -115,23 +115,16 @@ public:
   void NotifyDestroyPresContext(nsPresContext* aPresContext);
   void SetPresContext(nsPresContext* aPresContext);
   void ClearFrameRefs(nsIFrame* aFrame);
 
   nsIFrame* GetEventTarget();
   already_AddRefed<nsIContent> GetEventTargetContent(nsEvent* aEvent);
 
   /**
-   * Returns the content state of aContent.
-   * @param aContent      The control whose state is requested.
-   * @return              The content state.
-   */
-  virtual nsEventStates GetContentState(nsIContent *aContent);
-
-  /**
    * Notify that the given NS_EVENT_STATE_* bit has changed for this content.
    * @param aContent Content which has changed states
    * @param aState   Corresponding state flags such as NS_EVENT_STATE_FOCUS
    * @return  Whether the content was able to change all states. Returns PR_FALSE
    *                  if a resulting DOM event causes the content node passed in
    *                  to not change states. Note, the frame for the content may
    *                  change as a result of the content state change, because of
    *                  frame reconstructions that may occur, but this does not
@@ -429,16 +422,26 @@ protected:
 
   void DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
                                nsIFrame* aTargetFrame);
 
   PRBool RemoteQueryContentEvent(nsEvent *aEvent);
   mozilla::dom::TabParent *GetCrossProcessTarget();
   PRBool IsTargetCrossProcess(nsGUIEvent *aEvent);
 
+private:
+  static inline void DoStateChange(mozilla::dom::Element* aElement,
+                                   nsEventStates aState, PRBool aAddState);
+  static inline void DoStateChange(nsIContent* aContent, nsEventStates aState,
+                                   PRBool aAddState);
+  static void UpdateAncestorState(nsIContent* aStartNode,
+                                  nsIContent* aStopBefore,
+                                  nsEventStates aState,
+                                  PRBool aAddState);
+
   PRInt32     mLockCursor;
 
   nsWeakFrame mCurrentTarget;
   nsCOMPtr<nsIContent> mCurrentTargetContent;
   nsWeakFrame mLastMouseOverFrame;
   nsCOMPtr<nsIContent> mLastMouseOverElement;
   nsWeakFrame mLastDragOverFrame;
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -17,16 +17,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):
  *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Ms2ger <ms2ger@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -439,37 +440,17 @@ nsGenericHTMLElement::SetLang(const nsAS
 }
 
 static const nsAttrValue::EnumTable kDirTable[] = {
   { "ltr", NS_STYLE_DIRECTION_LTR },
   { "rtl", NS_STYLE_DIRECTION_RTL },
   { 0 }
 };
 
-nsresult
-nsGenericHTMLElement::GetDir(nsAString& aDir)
-{
-  const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsGkAtoms::dir);
-
-  if (attr && attr->Type() == nsAttrValue::eEnum) {
-    attr->ToString(aDir);
-  }
-  else {
-    aDir.Truncate();
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsGenericHTMLElement::SetDir(const nsAString& aDir)
-{
-  SetAttr(kNameSpaceID_None, nsGkAtoms::dir, aDir, PR_TRUE);
-  return NS_OK;
-}
+NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsGenericHTMLElement, Dir, dir, NULL)
 
 nsresult
 nsGenericHTMLElement::GetClassName(nsAString& aClassName)
 {
   GetAttr(kNameSpaceID_None, nsGkAtoms::_class, aClassName);
   return NS_OK;
 }
 
@@ -934,27 +915,26 @@ nsGenericHTMLElement::SetDraggable(PRBoo
 
 PRBool
 nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
 {
   return aDoc && aDoc->GetCompatibilityMode() == eCompatibility_NavQuirks;
 }
 
 void
-nsGenericHTMLElement::UpdateEditableState()
+nsGenericHTMLElement::UpdateEditableState(PRBool aNotify)
 {
   // XXX Should we do this only when in a document?
   ContentEditableTristate value = GetContentEditableValue();
   if (value != eInherit) {
-    SetEditableFlag(!!value);
-
+    DoSetEditableFlag(!!value, aNotify);
     return;
   }
 
-  nsStyledElement::UpdateEditableState();
+  nsStyledElement::UpdateEditableState(aNotify);
 }
 
 nsresult
 nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                  nsIContent* aBindingParent,
                                  PRBool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElementBase::BindToTree(aDocument, aParent,
@@ -1708,45 +1688,44 @@ nsGenericHTMLElement::MapCommonAttribute
       if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) {
         display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
       }
     }
   }
 }
 
 void
-nsGenericHTMLFormElement::UpdateEditableFormControlState()
+nsGenericHTMLFormElement::UpdateEditableFormControlState(PRBool aNotify)
 {
   // nsCSSFrameConstructor::MaybeConstructLazily is based on the logic of this
   // function, so should be kept in sync with that.
 
   ContentEditableTristate value = GetContentEditableValue();
   if (value != eInherit) {
-    SetEditableFlag(!!value);
-
+    DoSetEditableFlag(!!value, aNotify);
     return;
   }
 
   nsIContent *parent = GetParent();
 
   if (parent && parent->HasFlag(NODE_IS_EDITABLE)) {
-    SetEditableFlag(PR_TRUE);
+    DoSetEditableFlag(PR_TRUE, aNotify);
     return;
   }
 
   if (!IsTextControl(PR_FALSE)) {
-    SetEditableFlag(PR_FALSE);
+    DoSetEditableFlag(PR_FALSE, aNotify);
     return;
   }
 
   // If not contentEditable we still need to check the readonly attribute.
   PRBool roState;
   GetBoolAttr(nsGkAtoms::readonly, &roState);
 
-  SetEditableFlag(!roState);
+  DoSetEditableFlag(!roState, aNotify);
 }
 
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
 nsGenericHTMLElement::sCommonAttributeMap[] = {
   { &nsGkAtoms::contenteditable },
   { &nsGkAtoms::lang },
   { &nsGkAtoms::hidden },
@@ -2328,17 +2307,17 @@ nsGenericHTMLElement::GetEnumAttr(nsIAto
                                   nsAString& aResult)
 {
   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
 
   aResult.Truncate();
 
   if (attrVal && attrVal->Type() == nsAttrValue::eEnum) {
     attrVal->GetEnumString(aResult, PR_TRUE);
-  } else {
+  } else if (aDefault) {
     AppendASCIItoUTF16(nsDependentCString(aDefault), aResult);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetContentEditable(nsAString& aContentEditable)
@@ -2405,16 +2384,19 @@ nsGenericHTMLElement::GetIsContentEditab
 
 NS_IMPL_INT_ATTR(nsGenericHTMLFrameElement, TabIndex, tabindex)
 
 nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
   , mForm(nsnull)
   , mFieldSet(nsnull)
 {
+  // We should add the NS_EVENT_STATE_ENABLED bit here as needed, but
+  // that depends on our type, which is not initialized yet.  So we
+  // have to do this in subclasses.
 }
 
 nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
 {
   if (mFieldSet) {
     static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
   }
 
@@ -2559,17 +2541,17 @@ nsGenericHTMLFormElement::BindToTree(nsI
   // We should not call UpdateFormOwner if none of these conditions are
   // fulfilled.
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ? !!GetCurrentDoc()
                                                   : !!aParent) {
     UpdateFormOwner(true, nsnull);
   }
 
   // Set parent fieldset which should be used for the disabled state.
-  UpdateFieldSet();
+  UpdateFieldSet(PR_FALSE);
 
   return NS_OK;
 }
 
 void
 nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   // Save state before doing anything
@@ -2584,29 +2566,34 @@ nsGenericHTMLFormElement::UnbindFromTree
       // Recheck whether we should still have an mForm.
       if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
           !FindAncestorForm(mForm)) {
         ClearForm(PR_TRUE);
       } else {
         UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
       }
     }
+
+    if (!mForm) {
+      // Our novalidate state might have changed
+      UpdateState(false);
+    }
   }
 
   // We have to remove the form id observer if there was one.
   // We will re-add one later if needed (during bind to tree).
   if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
                                       nsGkAtoms::form)) {
     RemoveFormIdObserver();
   }
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 
   // The element might not have a fieldset anymore.
-  UpdateFieldSet();
+  UpdateFieldSet(PR_FALSE);
 }
 
 nsresult
 nsGenericHTMLFormElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                         const nsAString* aValue, PRBool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     nsAutoString tmp;
@@ -2617,18 +2604,16 @@ nsGenericHTMLFormElement::BeforeSetAttr(
       GetAttr(kNameSpaceID_None, aName, tmp);
 
       if (!tmp.IsEmpty()) {
         mForm->RemoveElementFromTable(this, tmp);
       }
     }
 
     if (mForm && aName == nsGkAtoms::type) {
-      nsIDocument* doc = GetCurrentDoc();
-
       GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
 
       if (!tmp.IsEmpty()) {
         mForm->RemoveElementFromTable(this, tmp);
       }
 
       GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
 
@@ -2637,20 +2622,18 @@ nsGenericHTMLFormElement::BeforeSetAttr(
       }
 
       mForm->RemoveElement(this, false);
 
       // Removing the element from the form can make it not be the default
       // control anymore.  Go ahead and notify on that change, though we might
       // end up readding and becoming the default control again in
       // AfterSetAttr.
-      if (doc && aNotify) {
-        MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(this, NS_EVENT_STATE_DEFAULT);
-      }
+      // FIXME: Bug 656197
+      UpdateState(aNotify);
     }
 
     if (aName == nsGkAtoms::form) {
       // If @form isn't set or set to the empty string, there were no observer
       // so we don't have to remove it.
       if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
                                           nsGkAtoms::form)) {
         // The current form id observer is no longer needed.
@@ -2674,17 +2657,16 @@ nsGenericHTMLFormElement::AfterSetAttr(P
     if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
         aValue) {
       if (!aValue->IsEmpty()) {
         mForm->AddElementToTable(this, *aValue);
       }
     }
 
     if (mForm && aName == nsGkAtoms::type) {
-      nsIDocument* doc = GetDocument();
       nsAutoString tmp;
 
       GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
 
       if (!tmp.IsEmpty()) {
         mForm->AddElementToTable(this, tmp);
       }
 
@@ -2695,20 +2677,17 @@ nsGenericHTMLFormElement::AfterSetAttr(P
       }
 
       mForm->AddElement(this, false, aNotify);
 
       // Adding the element to the form can make it be the default control .
       // Go ahead and notify on that change.
       // Note: no need to notify on CanBeDisabled(), since type attr
       // changes can't affect that.
-      if (doc && aNotify) {
-        MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(this, NS_EVENT_STATE_DEFAULT);
-      }
+      UpdateState(aNotify);
     }
 
     if (aName == nsGkAtoms::form) {
       // We need a new form id observer.
       nsIDocument* doc = GetCurrentDoc();
       if (doc) {
         Element* formIdElement = nsnull;
         if (aValue && !aValue->IsEmpty()) {
@@ -2909,22 +2888,24 @@ nsGenericHTMLFormElement::FormIdUpdated(
 
 void
 nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
                                           Element* aFormIdElement)
 {
   NS_PRECONDITION(!aBindToTree || !aFormIdElement,
                   "aFormIdElement shouldn't be set if aBindToTree is true!");
 
-  bool hadForm = mForm;
-
+  PRBool needStateUpdate = PR_FALSE;
   if (!aBindToTree) {
+    needStateUpdate = mForm && mForm->IsDefaultSubmitElement(this);
     ClearForm(PR_TRUE);
   }
 
+  nsHTMLFormElement *oldForm = mForm;
+
   if (!mForm) {
     // If @form is set, we have to use that to find the form.
     nsAutoString formId;
     if (GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId)) {
       if (!formId.IsEmpty()) {
         Element* element = nsnull;
 
         if (aBindToTree) {
@@ -2960,72 +2941,76 @@ nsGenericHTMLFormElement::UpdateFormOwne
     // Now we need to add ourselves to the form
     nsAutoString nameVal, idVal;
     GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
     GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
 
     SetFlags(ADDED_TO_FORM);
 
     // Notify only if we just found this mForm.
-    mForm->AddElement(this, true, !hadForm);
+    mForm->AddElement(this, true, oldForm == nsnull);
 
     if (!nameVal.IsEmpty()) {
       mForm->AddElementToTable(this, nameVal);
     }
 
     if (!idVal.IsEmpty()) {
       mForm->AddElementToTable(this, idVal);
     }
   }
+
+  if (mForm != oldForm || needStateUpdate) {
+    UpdateState(true);
+  }
 }
 
 void
-nsGenericHTMLFormElement::UpdateFieldSet()
+nsGenericHTMLFormElement::UpdateFieldSet(PRBool aNotify)
 {
   nsIContent* parent = nsnull;
   nsIContent* prev = nsnull;
 
   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 == fieldset) {
+          // We already have the right fieldset;
+          return;
+        }
+
         if (mFieldSet) {
           static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
         }
         mFieldSet = fieldset;
         fieldset->AddElement(this);
+
+        // The disabled state may have changed
+        FieldSetDisabledChanged(aNotify);
         return;
       }
     }
   }
 
   // No fieldset found.
   if (mFieldSet) {
     static_cast<nsHTMLFieldSetElement*>(mFieldSet)->RemoveElement(this);
+    mFieldSet = nsnull;
+    // The disabled state may have changed
+    FieldSetDisabledChanged(aNotify);
   }
-  mFieldSet = nsnull;
 }
 
 void
-nsGenericHTMLFormElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
+nsGenericHTMLFormElement::FieldSetDisabledChanged(PRBool aNotify)
 {
-  if (!aNotify) {
-    return;
-  }
-
-  aStates |= NS_EVENT_STATE_DISABLED | NS_EVENT_STATE_ENABLED;
-
-  nsIDocument* doc = GetCurrentDoc();
-  if (doc) {
-    MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-    doc->ContentStateChanged(this, aStates);
-  }
+  UpdateState(aNotify);
 }
 
 //----------------------------------------------------------------------
 
 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
 {
   if (mFrameLoader) {
     mFrameLoader->Destroy();
@@ -3539,29 +3524,32 @@ nsGenericHTMLElement::IsEditableRoot() c
   nsIContent *parent = GetParent();
 
   return !parent || !parent->HasFlag(NODE_IS_EDITABLE);
 }
 
 static void
 MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
 {
-  nsEventStates stateBefore = aContent->IntrinsicState();
-
-  aContent->UpdateEditableState();
-
-  if (aDocument && stateBefore != aContent->IntrinsicState()) {
-    aDocument->ContentStateChanged(aContent,
-                                   NS_EVENT_STATE_MOZ_READONLY |
-                                   NS_EVENT_STATE_MOZ_READWRITE);
+  // If aContent is not an element, we just need to update its
+  // internal editable state and don't need to notify anyone about
+  // that.  For elements, we need to send a ContentStateChanged
+  // notification.
+  if (!aContent->IsElement()) {
+    aContent->UpdateEditableState(PR_FALSE);
+    return;
   }
 
-  PRUint32 i, n = aContent->GetChildCount();
-  for (i = 0; i < n; ++i) {
-    nsIContent *child = aContent->GetChildAt(i);
+  Element *element = aContent->AsElement();
+
+  element->UpdateEditableState(PR_TRUE);
+
+  for (nsIContent *child = aContent->GetFirstChild();
+       child;
+       child = child->GetNextSibling()) {
     if (!child->HasAttr(kNameSpaceID_None, nsGkAtoms::contenteditable)) {
       MakeContentDescendantsEditable(child, aDocument);
     }
   }
 }
 
 void
 nsGenericHTMLElement::ChangeEditableState(PRInt32 aChange)
@@ -3580,12 +3568,12 @@ nsGenericHTMLElement::ChangeEditableStat
   }
 
   if (document->HasFlag(NODE_IS_EDITABLE)) {
     document = nsnull;
   }
 
   // MakeContentDescendantsEditable is going to call ContentStateChanged for
   // this element and all descendants if editable state has changed.
-  // We have to create a document update batch now so it's created once.
-  MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE);
+  // We might as well wrap it all in one script blocker.
+  nsAutoScriptBlocker scriptBlocker;
   MakeContentDescendantsEditable(this, document);
 }
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -111,18 +111,18 @@ public:
   // methods, implementations are expected to forward calls to these
   // methods.
   nsresult GetId(nsAString& aId);
   nsresult SetId(const nsAString& aId);
   nsresult GetTitle(nsAString& aTitle);
   nsresult SetTitle(const nsAString& aTitle);
   nsresult GetLang(nsAString& aLang);
   nsresult SetLang(const nsAString& aLang);
-  nsresult GetDir(nsAString& aDir);
-  nsresult SetDir(const nsAString& aDir);
+  NS_IMETHOD GetDir(nsAString& aDir);
+  NS_IMETHOD SetDir(const nsAString& aDir);
   nsresult GetClassName(nsAString& aClassName);
   nsresult SetClassName(const nsAString& aClassName);
 
   // nsIDOMNSHTMLElement methods. Note that these are non-virtual
   // methods, implementations are expected to forward calls to these
   // methods.
   nsresult GetOffsetTop(PRInt32* aOffsetTop);
   nsresult GetOffsetLeft(PRInt32* aOffsetLeft);
@@ -194,17 +194,23 @@ public:
   PRBool CheckHandleEventForAnchorsPreconditions(nsEventChainVisitor& aVisitor);
   nsresult PreHandleEventForAnchors(nsEventChainPreVisitor& aVisitor);
   nsresult PostHandleEventForAnchors(nsEventChainPostVisitor& aVisitor);
   PRBool IsHTMLLink(nsIURI** aURI) const;
 
   // HTML element methods
   void Compact() { mAttrsAndChildren.Compact(); }
 
-  virtual void UpdateEditableState();
+  virtual void UpdateEditableState(PRBool aNotify);
+
+  // Helper for setting our editable flag and notifying
+  void DoSetEditableFlag(PRBool aEditable, bool aNotify) {
+    SetEditableFlag(aEditable);
+    UpdateState(aNotify);
+  }
 
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
 
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
@@ -865,32 +871,28 @@ public:
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   virtual bool IsDisabled() const {
     return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) ||
            (mFieldSet && mFieldSet->IsDisabled());
   }
 
   /**
-   * This callback is called by a fieldest on all it's elements whenever it's
-   * disabled attribute is changed so the element knows it's disabled state
+   * This callback is called by a fieldest on all its elements whenever its
+   * disabled attribute is changed so the element knows its disabled state
    * might have changed.
    *
-   * @param aStates States for which a change should be notified.
-   * @note Classes redefining this method should not call ContentStatesChanged
-   * but they should pass aStates instead.
+   * @note Classes redefining this method should not do any content
+   * state updates themselves but should just make sure to call into
+   * nsGenericHTMLFormElement::FieldSetDisabledChanged.
    */
-  virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
+  virtual void FieldSetDisabledChanged(PRBool aNotify);
 
   void FieldSetFirstLegendChanged(PRBool aNotify) {
-    UpdateFieldSet();
-
-    // The disabled state may have change because the element might not be in
-    // the first legend anymore.
-    FieldSetDisabledChanged(nsEventStates(), aNotify);
+    UpdateFieldSet(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.
@@ -911,17 +913,17 @@ public:
 
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
 
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAString* aValue, PRBool aNotify);
 
-  void UpdateEditableFormControlState();
+  void UpdateEditableFormControlState(PRBool aNotify);
 
   /**
    * This method will update the form owner, using @form or looking to a parent.
    *
    * @param aBindToTree Whether the element is being attached to the tree.
    * @param aFormIdElement The element associated with the id in @form. If
    * aBindToTree is false, aFormIdElement *must* contain the element associated
    * with the id in @form. Otherwise, it *must* be null.
@@ -929,17 +931,17 @@ protected:
    * @note Callers of UpdateFormOwner have to be sure the element is in a
    * document (GetCurrentDoc() != nsnull).
    */
   void UpdateFormOwner(bool aBindToTree, Element* aFormIdElement);
 
   /**
    * This method will update mFieldset and set it to the first fieldset parent.
    */
-  void UpdateFieldSet();
+  void UpdateFieldSet(PRBool aNotify);
 
   /**
    * Add a form id observer which will observe when the element with the id in
    * @form will change.
    *
    * @return The element associated with the current id in @form (may be null).
    */
   Element* AddFormIdObserver();
--- a/content/html/content/src/nsHTMLAnchorElement.cpp
+++ b/content/html/content/src/nsHTMLAnchorElement.cpp
@@ -94,16 +94,17 @@ public:
                               PRBool aNullParent = PR_TRUE);
   virtual PRBool IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex);
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void GetLinkTarget(nsAString& aTarget);
   virtual nsLinkState GetLinkState() const;
+  virtual void RequestLinkStateUpdate();
   virtual already_AddRefed<nsIURI> GetHrefURI() const;
 
   nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                    const nsAString& aValue, PRBool aNotify)
   {
     return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
   }
   virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
@@ -122,17 +123,18 @@ public:
 
   virtual nsXPCClassInfo* GetClassInfo();
 };
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Anchor)
 
 nsHTMLAnchorElement::nsHTMLAnchorElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-  : nsGenericHTMLElement(aNodeInfo)
+  : nsGenericHTMLElement(aNodeInfo),
+    Link(this)
 {
 }
 
 nsHTMLAnchorElement::~nsHTMLAnchorElement()
 {
 }
 
 
@@ -363,16 +365,22 @@ nsHTMLAnchorElement::SetPing(const nsASt
 }
 
 nsLinkState
 nsHTMLAnchorElement::GetLinkState() const
 {
   return Link::GetLinkState();
 }
 
+void
+nsHTMLAnchorElement::RequestLinkStateUpdate()
+{
+  UpdateLinkState(Link::LinkState());
+}
+
 already_AddRefed<nsIURI>
 nsHTMLAnchorElement::GetHrefURI() const
 {
   return GetHrefURIForAnchors();
 }
 
 nsresult
 nsHTMLAnchorElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
--- a/content/html/content/src/nsHTMLAreaElement.cpp
+++ b/content/html/content/src/nsHTMLAreaElement.cpp
@@ -77,16 +77,17 @@ public:
   NS_IMETHOD LinkAdded() { return NS_OK; }
   NS_IMETHOD LinkRemoved() { return NS_OK; }
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void GetLinkTarget(nsAString& aTarget);
   virtual nsLinkState GetLinkState() const;
+  virtual void RequestLinkStateUpdate();
   virtual already_AddRefed<nsIURI> GetHrefURI() const;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
   nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
@@ -107,17 +108,18 @@ public:
   virtual nsXPCClassInfo* GetClassInfo();
 };
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Area)
 
 
 nsHTMLAreaElement::nsHTMLAreaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-  : nsGenericHTMLElement(aNodeInfo)
+  : nsGenericHTMLElement(aNodeInfo),
+    Link(this)
 {
 }
 
 nsHTMLAreaElement::~nsHTMLAreaElement()
 {
 }
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLAreaElement, nsGenericElement) 
@@ -290,16 +292,22 @@ nsHTMLAreaElement::SetPing(const nsAStri
 }
 
 nsLinkState
 nsHTMLAreaElement::GetLinkState() const
 {
   return Link::GetLinkState();
 }
 
+void
+nsHTMLAreaElement::RequestLinkStateUpdate()
+{
+  UpdateLinkState(Link::LinkState());
+}
+
 already_AddRefed<nsIURI>
 nsHTMLAreaElement::GetHrefURI() const
 {
   return GetHrefURIForAnchors();
 }
 
 nsEventStates
 nsHTMLAreaElement::IntrinsicState() const
--- a/content/html/content/src/nsHTMLBodyElement.cpp
+++ b/content/html/content/src/nsHTMLBodyElement.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):
  *   Daniel Glazman <glazman@netscape.com>
+ *   Ms2ger <ms2ger@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -309,18 +310,17 @@ NS_INTERFACE_TABLE_HEAD(nsHTMLBodyElemen
   NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLBodyElement, nsIDOMHTMLBodyElement)
   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLBodyElement,
                                                nsGenericHTMLElement)
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLBodyElement)
 
 NS_IMPL_ELEMENT_CLONE(nsHTMLBodyElement)
 
 
-NS_IMPL_URI_ATTR(nsHTMLBodyElement, Background, background)
-
+NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Background, background)
 NS_IMPL_STRING_ATTR(nsHTMLBodyElement, VLink, vlink)
 NS_IMPL_STRING_ATTR(nsHTMLBodyElement, ALink, alink)
 NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Link, link)
 NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Text, text)
 NS_IMPL_STRING_ATTR(nsHTMLBodyElement, BgColor, bgcolor)
 
 PRBool
 nsHTMLBodyElement::ParseAttribute(PRInt32 aNamespaceID,
--- a/content/html/content/src/nsHTMLButtonElement.cpp
+++ b/content/html/content/src/nsHTMLButtonElement.cpp
@@ -59,16 +59,18 @@
 #include "nsEventDispatcher.h"
 #include "nsPresState.h"
 #include "nsLayoutErrors.h"
 #include "nsFocusManager.h"
 #include "nsHTMLFormElement.h"
 #include "nsIConstraintValidation.h"
 #include "mozAutoDocUpdate.h"
 
+using namespace mozilla::dom;
+
 #define NS_IN_SUBMIT_CLICK      (1 << 0)
 #define NS_OUTER_ACTIVATE_EVENT (1 << 1)
 
 static const nsAttrValue::EnumTable kButtonTypeTable[] = {
   { "button", NS_FORM_BUTTON_BUTTON },
   { "reset", NS_FORM_BUTTON_RESET },
   { "submit", NS_FORM_BUTTON_SUBMIT },
   { 0 }
@@ -79,17 +81,18 @@ static const nsAttrValue::EnumTable* kBu
 
 class nsHTMLButtonElement : public nsGenericHTMLFormElement,
                             public nsIDOMHTMLButtonElement,
                             public nsIConstraintValidation
 {
 public:
   using nsIConstraintValidation::GetValidationMessage;
 
-  nsHTMLButtonElement(already_AddRefed<nsINodeInfo> aNodeInfo);
+  nsHTMLButtonElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                      FromParser aFromParser = NOT_FROM_PARSER);
   virtual ~nsHTMLButtonElement();
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE(nsGenericHTMLFormElement::)
 
@@ -126,46 +129,58 @@ public:
   virtual PRBool IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex);
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
 
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
+                              PRBool aNullParent = PR_TRUE);
+
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual void DoneCreatingElement();
   virtual nsXPCClassInfo* GetClassInfo();
 
 protected:
   PRUint8 mType;
   PRPackedBool mDisabledChanged;
   PRPackedBool mInInternalActivate;
+  PRPackedBool mInhibitStateRestoration;
 
 private:
   // The analogue of defaultValue in the DOM for input and textarea
   nsresult SetDefaultValue(const nsAString& aDefaultValue);
   nsresult GetDefaultValue(nsAString& aDefaultValue);
 };
 
 
 // Construction, destruction
 
 
-NS_IMPL_NS_NEW_HTML_ELEMENT(Button)
+NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Button)
 
 
-nsHTMLButtonElement::nsHTMLButtonElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+nsHTMLButtonElement::nsHTMLButtonElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                                         FromParser aFromParser)
   : nsGenericHTMLFormElement(aNodeInfo),
     mType(kButtonDefaultType->value),
     mDisabledChanged(PR_FALSE),
-    mInInternalActivate(PR_FALSE)
+    mInInternalActivate(PR_FALSE),
+    mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT))
 {
   // <button> is always barred from constraint validation.
   SetBarredFromConstraintValidation(PR_TRUE);
+
+  // Set up our default state: enabled
+  AddStatesSilently(NS_EVENT_STATE_ENABLED);
 }
 
 nsHTMLButtonElement::~nsHTMLButtonElement()
 {
 }
 
 // nsISupports
 
@@ -476,16 +491,41 @@ nsHTMLButtonElement::PostHandleEvent(nsE
     // Note, NS_IN_SUBMIT_CLICK is set only when we're in outer activate event.
     mForm->FlushPendingSubmission();
   } //if
 
   return rv;
 }
 
 nsresult
+nsHTMLButtonElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                nsIContent* aBindingParent,
+                                PRBool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
+                                                     aBindingParent,
+                                                     aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Update our state; we may now be the default submit element
+  UpdateState(false);
+
+  return NS_OK;
+}
+
+void
+nsHTMLButtonElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
+{
+  nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
+
+  // Update our state; we may no longer be the default submit element
+  UpdateState(false);
+}
+
+nsresult
 nsHTMLButtonElement::GetDefaultValue(nsAString& aDefaultValue)
 {
   GetAttr(kNameSpaceID_None, nsGkAtoms::value, aDefaultValue);
   return NS_OK;
 }
 
 nsresult
 nsHTMLButtonElement::SetDefaultValue(const nsAString& aDefaultValue)
@@ -540,18 +580,20 @@ nsHTMLButtonElement::SubmitNamesValues(n
   rv = aFormSubmission->AddNameValuePair(name, value);
 
   return rv;
 }
 
 void
 nsHTMLButtonElement::DoneCreatingElement()
 {
-  // Restore state as needed.
-  RestoreFormControlState(this, this);
+  if (!mInhibitStateRestoration) {
+    // Restore state as needed.
+    RestoreFormControlState(this, this);
+  }
 }
 
 nsresult
 nsHTMLButtonElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                    const nsAString* aValue, PRBool aNotify)
 {
   if (aNotify && aName == nsGkAtoms::disabled &&
       aNameSpaceID == kNameSpaceID_None) {
@@ -561,33 +603,23 @@ nsHTMLButtonElement::BeforeSetAttr(PRInt
   return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
                                                  aValue, aNotify);
 }
 
 nsresult
 nsHTMLButtonElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                   const nsAString* aValue, PRBool aNotify)
 {
-  nsEventStates states;
-
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::type) {
       if (!aValue) {
         mType = kButtonDefaultType->value;
       }
 
-      states |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
-    }
-
-    if (aNotify && !states.IsEmpty()) {
-      nsIDocument* doc = GetCurrentDoc();
-      if (doc) {
-        MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(this, states);
-      }
+      UpdateState(aNotify);
     }
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
                                                 aValue, aNotify);
 }
 
 NS_IMETHODIMP
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -49,16 +49,19 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(FieldSet)
 
 nsHTMLFieldSetElement::nsHTMLFieldSetElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLFormElement(aNodeInfo)
   , mElements(nsnull)
   , mFirstLegend(nsnull)
 {
   // <fieldset> is always barred from constraint validation.
   SetBarredFromConstraintValidation(PR_TRUE);
+
+  // We start out enabled
+  AddStatesSilently(NS_EVENT_STATE_ENABLED);
 }
 
 nsHTMLFieldSetElement::~nsHTMLFieldSetElement()
 {
   PRUint32 length = mDependentElements.Length();
   for (PRUint32 i=0; i<length; ++i) {
     mDependentElements[i]->ForgetFieldSet(this);
   }
@@ -122,17 +125,17 @@ nsHTMLFieldSetElement::AfterSetAttr(PRIn
     if (!mElements) {
       mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull,
                                     PR_TRUE);
     }
 
     PRUint32 length = mElements->Length(PR_TRUE);
     for (PRUint32 i=0; i<length; ++i) {
       static_cast<nsGenericHTMLFormElement*>(mElements->GetNodeAt(i))
-        ->FieldSetDisabledChanged(nsEventStates(), aNotify);
+        ->FieldSetDisabledChanged(aNotify);
     }
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
                                                 aValue, aNotify);
 }
 
 // nsIDOMHTMLFieldSetElement
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -377,33 +377,24 @@ nsHTMLFormElement::SetAttr(PRInt32 aName
 
 nsresult
 nsHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAString* aValue, PRBool aNotify)
 {
   if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) {
     // Update all form elements states because they might be [no longer]
     // affected by :-moz-ui-valid or :-moz-ui-invalid.
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
+    for (PRUint32 i = 0, length = mControls->mElements.Length();
+         i < length; ++i) {
+      mControls->mElements[i]->UpdateState(true);
+    }
 
-      for (PRUint32 i = 0, length = mControls->mElements.Length();
-           i < length; ++i) {
-        doc->ContentStateChanged(mControls->mElements[i],
-                                 NS_EVENT_STATE_MOZ_UI_VALID |
-                                 NS_EVENT_STATE_MOZ_UI_INVALID);
-      }
-
-      for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
-           i < length; ++i) {
-        doc->ContentStateChanged(mControls->mNotInElements[i],
-                                 NS_EVENT_STATE_MOZ_UI_VALID |
-                                 NS_EVENT_STATE_MOZ_UI_INVALID);
-      }
+    for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
+         i < length; ++i) {
+      mControls->mNotInElements[i]->UpdateState(true);
     }
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify);
 }
 
 NS_IMPL_STRING_ATTR(nsHTMLFormElement, AcceptCharset, acceptcharset)
 NS_IMPL_ACTION_ATTR(nsHTMLFormElement, Action, action)
@@ -502,19 +493,18 @@ MarkOrphans(const nsTArray<nsGenericHTML
 
 static void
 CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsGenericHTMLFormElement*> aArray
 #ifdef DEBUG
                , nsIDOMHTMLFormElement* aThisForm
 #endif
                )
 {
-  // Prepare document update batch.
-  nsIDocument* doc = aArray.IsEmpty() ? nsnull : aArray[0]->GetCurrentDoc();
-  MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
+  // Put a script blocker around all the notifications we're about to do.
+  nsAutoScriptBlocker scriptBlocker;
 
   // Walk backwards so that if we remove elements we can just keep iterating
   PRUint32 length = aArray.Length();
   for (PRUint32 i = length; i > 0; --i) {
     nsGenericHTMLFormElement* node = aArray[i-1];
 
     // Now if MAYBE_ORPHAN_FORM_ELEMENT is not set, that would mean that the
     // node is in fact a descendant of the form and hence should stay in the
@@ -524,30 +514,18 @@ CollectOrphans(nsINode* aRemovalRoot, ns
 #ifdef DEBUG
     PRBool removed = PR_FALSE;
 #endif
     if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) {
       node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
       if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
         node->ClearForm(PR_TRUE);
 
-        // When a form control loses its form owner, :-moz-ui-invalid and
-        // :-moz-ui-valid might not apply any more.
-        nsEventStates states = NS_EVENT_STATE_MOZ_UI_VALID |
-                               NS_EVENT_STATE_MOZ_UI_INVALID;
-
-        // In addition, submit controls shouldn't have
-        // NS_EVENT_STATE_MOZ_SUBMITINVALID applying if they do not have a form.
-        if (node->IsSubmitControl()) {
-          states |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
-        }
-
-        if (doc) {
-          doc->ContentStateChanged(node, states);
-        }
+        // When a form control loses its form owner, its state can change.
+        node->UpdateState(true);
 #ifdef DEBUG
         removed = PR_TRUE;
 #endif
       }
     }
 
 #ifdef DEBUG
     if (!removed) {
@@ -1200,17 +1178,17 @@ nsHTMLFormElement::AddElement(nsGenericH
     // The new child is the new first submit in its list if the firstSubmitSlot
     // is currently empty or if the child is before what's currently in the
     // slot.  Note that if we already have a control in firstSubmitSlot and
     // we're appending this element can't possibly replace what's currently in
     // the slot.  Also note that aChild can't become the mDefaultSubmitElement
     // unless it replaces what's in the slot.  If it _does_ replace what's in
     // the slot, it becomes the default submit if either the default submit is
     // what's in the slot or the child is earlier than the default submit.
-    nsIFormControl* oldDefaultSubmit = mDefaultSubmitElement;
+    nsGenericHTMLFormElement* oldDefaultSubmit = mDefaultSubmitElement;
     if (!*firstSubmitSlot ||
         (!lastElement &&
          CompareFormControlPosition(aChild, *firstSubmitSlot, this) < 0)) {
       // Update mDefaultSubmitElement if it's currently in a valid state.
       // Valid state means either non-null or null because there are in fact
       // no submit elements around.
       if ((mDefaultSubmitElement ||
            (!mFirstSubmitInElements && !mFirstSubmitNotInElements)) &&
@@ -1223,26 +1201,19 @@ nsHTMLFormElement::AddElement(nsGenericH
     }
     NS_POSTCONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
                      mDefaultSubmitElement == mFirstSubmitNotInElements ||
                      !mDefaultSubmitElement,
                      "What happened here?");
 
     // Notify that the state of the previous default submit element has changed
     // if the element which is the default submit element has changed.  The new
-    // default submit element is responsible for its own ContentStateChanged
-    // call.
-    if (aNotify && oldDefaultSubmit &&
-        oldDefaultSubmit != mDefaultSubmitElement) {
-      nsIDocument* document = GetCurrentDoc();
-      if (document) {
-        MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE);
-        nsCOMPtr<nsIContent> oldElement(do_QueryInterface(oldDefaultSubmit));
-        document->ContentStateChanged(oldElement, NS_EVENT_STATE_DEFAULT);
-      }
+    // default submit element is responsible for its own state update.
+    if (oldDefaultSubmit && oldDefaultSubmit != mDefaultSubmitElement) {
+      oldDefaultSubmit->UpdateState(aNotify);
     }
   }
 
   // If the element is subject to constraint validaton and is invalid, we need
   // to update our internal counter.
   if (aUpdateValidity) {
     nsCOMPtr<nsIConstraintValidation> cvElmt =
       do_QueryInterface(static_cast<nsGenericHTMLElement*>(aChild));
@@ -1365,22 +1336,17 @@ nsHTMLFormElement::HandleDefaultSubmitRe
   }
 
   NS_POSTCONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
                    mDefaultSubmitElement == mFirstSubmitNotInElements,
                    "What happened here?");
 
   // Notify about change if needed.
   if (mDefaultSubmitElement) {
-    nsIDocument* document = GetCurrentDoc();
-    if (document) {
-      MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE);
-      document->ContentStateChanged(mDefaultSubmitElement,
-                                    NS_EVENT_STATE_DEFAULT);
-    }
+    mDefaultSubmitElement->UpdateState(true);
   }
 }
 
 nsresult
 nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
                                           const nsAString& aName)
 {
   return mControls->RemoveElementFromTable(aElement, aName);
@@ -1739,50 +1705,43 @@ nsHTMLFormElement::CheckValidFormSubmiss
 
     if (!CheckFormValidity(invalidElements.get())) {
       // For the first invalid submission, we should update element states.
       // We have to do that _before_ calling the observers so we are sure they
       // will not interfere (like focusing the element).
       if (!mEverTriedInvalidSubmit) {
         mEverTriedInvalidSubmit = true;
 
-        nsIDocument* doc = GetCurrentDoc();
-        if (doc) {
-          /*
-           * We are going to call ContentStateChanged assuming elements want to
-           * be notified because we can't know.
-           * Submissions shouldn't happen during parsing so it _should_ be safe.
-           */
+        /*
+         * We are going to call update states assuming elements want to
+         * be notified because we can't know.
+         * Submissions shouldn't happen during parsing so it _should_ be safe.
+         */
 
-          MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
+        nsAutoScriptBlocker scriptBlocker;
 
-          for (PRUint32 i = 0, length = mControls->mElements.Length();
-               i < length; ++i) {
-            // Input elements can trigger a form submission and we want to
-            // update the style in that case.
-            if (mControls->mElements[i]->IsHTML(nsGkAtoms::input) &&
-                nsContentUtils::IsFocusedContent(mControls->mElements[i])) {
-              static_cast<nsHTMLInputElement*>(mControls->mElements[i])
-                ->UpdateValidityUIBits(true);
-            }
-
-            doc->ContentStateChanged(mControls->mElements[i],
-                                     NS_EVENT_STATE_MOZ_UI_VALID |
-                                     NS_EVENT_STATE_MOZ_UI_INVALID);
+        for (PRUint32 i = 0, length = mControls->mElements.Length();
+             i < length; ++i) {
+          // Input elements can trigger a form submission and we want to
+          // update the style in that case.
+          if (mControls->mElements[i]->IsHTML(nsGkAtoms::input) &&
+              nsContentUtils::IsFocusedContent(mControls->mElements[i])) {
+            static_cast<nsHTMLInputElement*>(mControls->mElements[i])
+              ->UpdateValidityUIBits(true);
           }
 
-          // Because of backward compatibility, <input type='image'> is not in
-          // elements but can be invalid.
-          // TODO: should probably be removed when bug 606491 will be fixed.
-          for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
-               i < length; ++i) {
-            doc->ContentStateChanged(mControls->mNotInElements[i],
-                                     NS_EVENT_STATE_MOZ_UI_VALID |
-                                     NS_EVENT_STATE_MOZ_UI_INVALID);
-          }
+          mControls->mElements[i]->UpdateState(true);
+        }
+
+        // Because of backward compatibility, <input type='image'> is not in
+        // elements but can be invalid.
+        // TODO: should probably be removed when bug 606491 will be fixed.
+        for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
+             i < length; ++i) {
+          mControls->mNotInElements[i]->UpdateState(true);
         }
       }
 
       nsCOMPtr<nsISupports> inst;
       nsCOMPtr<nsIFormSubmitObserver> observer;
       PRBool more = PR_TRUE;
       while (NS_SUCCEEDED(theEnum->HasMoreElements(&more)) && more) {
         theEnum->GetNext(getter_AddRefs(inst));
@@ -1820,46 +1779,39 @@ nsHTMLFormElement::UpdateValidity(PRBool
   // - there are no more invalid elements ;
   // - or there is one invalid elmement and an element just became invalid.
   // If we have invalid elements and we used to before as well, do nothing.
   if (mInvalidElementsCount &&
       (mInvalidElementsCount != 1 || aElementValidity)) {
     return;
   }
 
-  nsIDocument* doc = GetCurrentDoc();
-  if (!doc) {
-    return;
-  }
-
   /*
-   * We are going to call ContentStateChanged assuming submit controls want to
+   * We are going to update states assuming submit controls want to
    * be notified because we can't know.
    * UpdateValidity shouldn't be called so much during parsing so it _should_
    * be safe.
    */
 
-  MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
+  nsAutoScriptBlocker scriptBlocker;
 
   // Inform submit controls that the form validity has changed.
   for (PRUint32 i = 0, length = mControls->mElements.Length();
        i < length; ++i) {
     if (mControls->mElements[i]->IsSubmitControl()) {
-      doc->ContentStateChanged(mControls->mElements[i],
-                               NS_EVENT_STATE_MOZ_SUBMITINVALID);
+      mControls->mElements[i]->UpdateState(true);
     }
   }
 
   // Because of backward compatibility, <input type='image'> is not in elements
   // so we have to check for controls not in elements too.
   PRUint32 length = mControls->mNotInElements.Length();
   for (PRUint32 i = 0; i < length; ++i) {
     if (mControls->mNotInElements[i]->IsSubmitControl()) {
-      doc->ContentStateChanged(mControls->mNotInElements[i],
-                               NS_EVENT_STATE_MOZ_SUBMITINVALID);
+      mControls->mNotInElements[i]->UpdateState(true);
     }
   }
 }
 
 // nsIWebProgressListener
 NS_IMETHODIMP
 nsHTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress,
                                  nsIRequest* aRequest,
--- a/content/html/content/src/nsHTMLImageElement.cpp
+++ b/content/html/content/src/nsHTMLImageElement.cpp
@@ -175,16 +175,18 @@ NS_NewHTMLImageElement(already_AddRefed<
   }
 
   return new nsHTMLImageElement(nodeInfo.forget());
 }
 
 nsHTMLImageElement::nsHTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
+  // We start out broken
+  AddStatesSilently(NS_EVENT_STATE_BROKEN);
 }
 
 nsHTMLImageElement::~nsHTMLImageElement()
 {
   DestroyImageLoadingContent();
 }
 
 
@@ -501,17 +503,20 @@ nsHTMLImageElement::BindToTree(nsIDocume
                                PRBool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
+    // FIXME: Bug 660963 it would be nice if we could just have
+    // ClearBrokenState update our state and do it fast...
     ClearBrokenState();
+    RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
     // If loading is temporarily disabled, don't even launch MaybeLoadImage.
     // Otherwise MaybeLoadImage may run later when someone has reenabled
     // loading.
     if (LoadingEnabled()) {
       nsContentUtils::AddScriptRunner(
         NS_NewRunnableMethod(this, &nsHTMLImageElement::MaybeLoadImage));
     }
   }
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -626,16 +626,25 @@ nsHTMLInputElement::nsHTMLInputElement(a
       aFromParser & mozilla::dom::FROM_PARSER_FRAGMENT);
   SET_BOOLBIT(mBitField, BF_CAN_SHOW_INVALID_UI, PR_TRUE);
   SET_BOOLBIT(mBitField, BF_CAN_SHOW_VALID_UI, PR_TRUE);
   mInputData.mState = new nsTextEditorState(this);
   NS_ADDREF(mInputData.mState);
   
   if (!gUploadLastDir)
     nsHTMLInputElement::InitUploadLastDir();
+
+  // Set up our default state.  By default we're enabled (since we're
+  // a control type that can be disabled but not actually disabled
+  // right now), optional, and valid.  We are NOT readwrite by default
+  // until someone calls UpdateEditableState on us, apparently!  Also
+  // by default we don't have to show validity UI and so forth.
+  AddStatesSilently(NS_EVENT_STATE_ENABLED |
+                    NS_EVENT_STATE_OPTIONAL |
+                    NS_EVENT_STATE_VALID);
 }
 
 nsHTMLInputElement::~nsHTMLInputElement()
 {
   DestroyImageLoadingContent();
   FreeData();
 }
 
@@ -795,33 +804,28 @@ nsHTMLInputElement::BeforeSetAttr(PRInt3
                                                  aValue, aNotify);
 }
 
 nsresult
 nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue,
                                  PRBool aNotify)
 {
-  // States changes that have to be passed to ContentStateChanged().
-  nsEventStates states;
-
   if (aNameSpaceID == kNameSpaceID_None) {
     //
     // When name or type changes, radio should be added to radio group.
     // (type changes are handled in the form itself currently)
     // If the parser is not done creating the radio, we also should not do it.
     //
     if ((aName == nsGkAtoms::name ||
          (aName == nsGkAtoms::type && !mForm)) &&
         mType == NS_FORM_INPUT_RADIO &&
         (mForm || !(GET_BOOLBIT(mBitField, BF_PARSER_CREATING)))) {
       AddedToRadioGroup();
       UpdateValueMissingValidityStateForRadio(false);
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_REQUIRED | NS_EVENT_STATE_OPTIONAL;
     }
 
     // If @value is changed and BF_VALUE_CHANGED is false, @value is the value
     // of the element so, if the value of the element is different than @value,
     // we have to re-set it. This is only the case when GetValueMode() returns
     // VALUE_MODE_VALUE.
     if (aName == nsGkAtoms::value &&
         !GetValueChanged() && GetValueMode() == VALUE_MODE_VALUE) {
@@ -878,40 +882,16 @@ nsHTMLInputElement::AfterSetAttr(PRInt32
       } else if (aNotify) {
         // We just got switched to be an image input; we should see
         // whether we have an image to load;
         nsAutoString src;
         if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
           LoadImage(src, PR_FALSE, aNotify);
         }
       }
-
-      // Changing type affects the applicability of some states.  Just notify
-      // on them all now, just in case.  Note that we can't rely on the
-      // notifications LoadImage or CancelImageRequests might have sent, because
-      // those didn't include all the possibly-changed states in the mask. We
-      // have to do this here because we just updated mType, so the code in
-      // nsGenericElement::SetAttrAndNotify didn't see the new states.
-      states |= NS_EVENT_STATE_CHECKED |
-                NS_EVENT_STATE_DEFAULT |
-                NS_EVENT_STATE_BROKEN |
-                NS_EVENT_STATE_USERDISABLED |
-                NS_EVENT_STATE_SUPPRESSED |
-                NS_EVENT_STATE_LOADING |
-                NS_EVENT_STATE_MOZ_READONLY |
-                NS_EVENT_STATE_MOZ_READWRITE |
-                NS_EVENT_STATE_REQUIRED |
-                NS_EVENT_STATE_OPTIONAL |
-                NS_EVENT_STATE_VALID |
-                NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID |
-                NS_EVENT_STATE_MOZ_UI_INVALID |
-                NS_EVENT_STATE_INDETERMINATE |
-                NS_EVENT_STATE_MOZ_PLACEHOLDER |
-                NS_EVENT_STATE_MOZ_SUBMITINVALID;
     }
 
     if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
       nsIRadioGroupContainer* c = GetRadioGroupContainer();
       nsCOMPtr<nsIRadioGroupContainer_MOZILLA_2_0_BRANCH> container =
         do_QueryInterface(c);
 
       if (container) {
@@ -924,45 +904,24 @@ nsHTMLInputElement::AfterSetAttr(PRInt32
     if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
         aName == nsGkAtoms::readonly) {
       UpdateValueMissingValidityState();
 
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         UpdateBarredFromConstraintValidation();
       }
-
-      states |= NS_EVENT_STATE_REQUIRED | NS_EVENT_STATE_OPTIONAL |
-                NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     } else if (MaxLengthApplies() && aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     } else if (aName == nsGkAtoms::pattern) {
       UpdatePatternMismatchValidityState();
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     }
 
-    if (aNotify) {
-      nsIDocument* doc = GetCurrentDoc();
-
-      if (aName == nsGkAtoms::type) {
-        UpdateEditableState();
-      } else if (IsSingleLineTextControl(PR_FALSE) && aName == nsGkAtoms::readonly) {
-        UpdateEditableState();
-        states |= NS_EVENT_STATE_MOZ_READONLY | NS_EVENT_STATE_MOZ_READWRITE;
-      }
-
-      if (doc && !states.IsEmpty()) {
-        MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(this, states);
-      }
-    }
+    UpdateEditableState(aNotify);
+    UpdateState(aNotify);
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
                                                 aValue, aNotify);
 }
 
 // nsIDOMHTMLInputElement
 
@@ -1019,22 +978,17 @@ nsHTMLInputElement::SetIndeterminateInte
 
   if (aShouldInvalidate) {
     // Repaint the frame
     nsIFrame* frame = GetPrimaryFrame();
     if (frame)
       frame->InvalidateFrameSubtree();
   }
 
-  // Notify the document so it can update :indeterminate pseudoclass rules
-  nsIDocument* document = GetCurrentDoc();
-  if (document) {
-    mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, PR_TRUE);
-    document->ContentStateChanged(this, NS_EVENT_STATE_INDETERMINATE);
-  }
+  UpdateState(true);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetIndeterminate(PRBool aValue)
 {
   return SetIndeterminateInternal(aValue, PR_TRUE);
@@ -1367,16 +1321,41 @@ nsHTMLInputElement::GetDisplayFileName(n
 
 void
 nsHTMLInputElement::SetFiles(const nsCOMArray<nsIDOMFile>& aFiles,
                              bool aSetValueChanged)
 {
   mFiles.Clear();
   mFiles.AppendObjects(aFiles);
 
+  AfterSetFiles(aSetValueChanged);
+}
+
+void
+nsHTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
+                             bool aSetValueChanged)
+{
+  mFiles.Clear();
+
+  if (aFiles) {
+    PRUint32 listLength;
+    aFiles->GetLength(&listLength);
+    for (PRUint32 i = 0; i < listLength; i++) {
+      nsCOMPtr<nsIDOMFile> file;
+      aFiles->Item(i, getter_AddRefs(file));
+      mFiles.AppendObject(file);
+    }
+  }
+
+  AfterSetFiles(aSetValueChanged);
+}
+
+void
+nsHTMLInputElement::AfterSetFiles(bool aSetValueChanged)
+{
   // No need to flush here, if there's no frame at this point we
   // don't need to force creation of one just to tell it about this
   // new value.  We just want the display to update as needed.
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
   if (formControlFrame) {
     nsAutoString readableValue;
     GetDisplayFileName(readableValue);
     formControlFrame->SetFormProperty(nsGkAtoms::value, readableValue);
@@ -1437,21 +1416,17 @@ nsHTMLInputElement::SetValueInternal(con
 
     if (aSetValueChanged) {
       SetValueChanged(PR_TRUE);
     }
     mInputData.mState->SetValue(value, aUserInput);
 
     if (PlaceholderApplies() &&
         HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
-      nsIDocument* doc = GetCurrentDoc();
-      if (doc) {
-        mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_PLACEHOLDER);
-      }
+      UpdateState(true);
     }
 
     return NS_OK;
   }
 
   // If the value of a hidden input was changed, we mark it changed so that we
   // will know we need to save / restore the value.  Yes, we are overloading
   // the meaning of ValueChanged just a teensy bit to save a measly byte of
@@ -1476,22 +1451,17 @@ nsHTMLInputElement::SetValueChanged(PRBo
 
   if (!aValueChanged) {
     if (!IsSingleLineTextControl(PR_FALSE)) {
       FreeData();
     }
   }
 
   if (valueChangedBefore != aValueChanged) {
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_UI_VALID |
-                                     NS_EVENT_STATE_MOZ_UI_INVALID);
-    }
+    UpdateState(true);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsHTMLInputElement::GetChecked(PRBool* aChecked)
 {
@@ -1525,23 +1495,17 @@ nsHTMLInputElement::SetCheckedChangedInt
 {
   PRBool checkedChangedBefore = GetCheckedChanged();
 
   SET_BOOLBIT(mBitField, BF_CHECKED_CHANGED, aCheckedChanged);
 
   // This method can't be called when we are not authorized to notify
   // so we do not need a aNotify parameter.
   if (checkedChangedBefore != aCheckedChanged) {
-    nsIDocument* document = GetCurrentDoc();
-    if (document) {
-      mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, PR_TRUE);
-      document->ContentStateChanged(this,
-                                    NS_EVENT_STATE_MOZ_UI_VALID |
-                                    NS_EVENT_STATE_MOZ_UI_INVALID);
-    }
+    UpdateState(true);
   }
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetChecked(PRBool aChecked)
 {
   return DoSetChecked(aChecked, PR_TRUE, PR_TRUE);
 }
@@ -1725,27 +1689,21 @@ nsHTMLInputElement::SetCheckedInternal(P
   //
   if (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO) {
     nsIFrame* frame = GetPrimaryFrame();
     if (frame) {
       frame->InvalidateFrameSubtree();
     }
   }
 
+  UpdateAllValidityStates(aNotify);
+
   // Notify the document that the CSS :checked pseudoclass for this element
   // has changed state.
-  if (aNotify) {
-    nsIDocument* document = GetCurrentDoc();
-    if (document) {
-      mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, aNotify);
-      document->ContentStateChanged(this, NS_EVENT_STATE_CHECKED);
-    }
-  }
-
-  UpdateAllValidityStates(aNotify);
+  UpdateState(aNotify);
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::Focus()
 {
   if (mType == NS_FORM_INPUT_FILE) {
     // for file inputs, focus the button instead
     nsIFrame* frame = GetPrimaryFrame();
@@ -2053,40 +2011,20 @@ nsresult
 nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   if (!aVisitor.mPresContext) {
     return NS_OK;
   }
 
   if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
       aVisitor.mEvent->message == NS_BLUR_CONTENT) {
-    nsEventStates states;
-
-    if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) {
-      UpdateValidityUIBits(true);
-
-      // We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor
-      // NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change.
-    } else { // NS_BLUR_CONTENT
-      UpdateValidityUIBits(false);
-      states |= NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
-    }
-
-    if (PlaceholderApplies() &&
-        HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
-        // TODO: checking if the value is empty could be a good idea but we do not
-      // have a simple way to do that, see bug 585100
-      states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
-    }
-
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, states);
-    }
+
+    UpdateValidityUIBits(aVisitor.mEvent->message == NS_FOCUS_CONTENT);
+
+    UpdateState(true);
   }
 
   // ignore the activate event fired by the "Browse..." button
   // (file input controls fire their own) (bug 500885)
   if (mType == NS_FORM_INPUT_FILE) {
     nsCOMPtr<nsIContent> maybeButton =
       do_QueryInterface(aVisitor.mEvent->originalTarget);
     if (maybeButton &&
@@ -2451,17 +2389,20 @@ nsHTMLInputElement::BindToTree(nsIDocume
                                                      aBindingParent,
                                                      aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mType == NS_FORM_INPUT_IMAGE) {
     // Our base URI may have changed; claim that our URI changed, and the
     // nsImageLoadingContent will decide whether a new image load is warranted.
     if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
+      // FIXME: Bug 660963 it would be nice if we could just have
+      // ClearBrokenState update our state and do it fast...
       ClearBrokenState();
+      RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
       nsContentUtils::AddScriptRunner(
         NS_NewRunnableMethod(this, &nsHTMLInputElement::MaybeLoadImage));
     }
   }
 
   // Add radio to document if we don't have a form already (if we do it's
   // already been added into that group)
   if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) {
@@ -2472,16 +2413,19 @@ nsHTMLInputElement::BindToTree(nsIDocume
   // We have to check if we suffer from that as we are now in a document.
   UpdateValueMissingValidityState();
 
   // If there is a disabled fieldset in the parent chain, the element is now
   // barred from constraint validation and can't suffer from value missing
   // (call done before).
   UpdateBarredFromConstraintValidation();
 
+  // And now make sure our state is up to date
+  UpdateState(false);
+
   return rv;
 }
 
 void
 nsHTMLInputElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   // If we have a form and are unbound from it,
   // nsGenericHTMLFormElement::UnbindFromTree() will unset the form and
@@ -2494,16 +2438,19 @@ nsHTMLInputElement::UnbindFromTree(PRBoo
 
   nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
 
   // GetCurrentDoc is returning nsnull so we can update the value
   // missing validity state to reflect we are no longer into a doc.
   UpdateValueMissingValidityState();
   // We might be no longer disabled because of parent chain changed.
   UpdateBarredFromConstraintValidation();
+
+  // And now make sure our state is up to date
+  UpdateState(false);
 }
 
 void
 nsHTMLInputElement::HandleTypeChange(PRUint8 aNewType)
 {
   ValueModeType aOldValueMode = GetValueMode();
   nsAutoString aOldValue;
 
@@ -3650,24 +3597,17 @@ nsHTMLInputElement::DoesPatternApply() c
 
 // nsIConstraintValidation
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetCustomValidity(const nsAString& aError)
 {
   nsIConstraintValidation::SetCustomValidity(aError);
 
-  nsIDocument* doc = GetCurrentDoc();
-  if (doc) {
-    MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-    doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
-                                   NS_EVENT_STATE_VALID |
-                                   NS_EVENT_STATE_MOZ_UI_INVALID |
-                                   NS_EVENT_STATE_MOZ_UI_VALID);
-  }
+  UpdateState(true);
 
   return NS_OK;
 }
 
 PRBool
 nsHTMLInputElement::IsTooLong()
 {
   if (!MaxLengthApplies() ||
@@ -3828,16 +3768,18 @@ nsHTMLInputElement::UpdateValueMissingVa
 
   valueMissing = required && !selected;
 
   if (container->GetValueMissingState(name) != valueMissing) {
     container->SetValueMissingState(name, valueMissing);
 
     SetValidityState(VALIDITY_STATE_VALUE_MISSING, valueMissing);
 
+    // nsRadioSetValueMissingState will call ContentStateChanged while visiting.
+    nsAutoScriptBlocker scriptBlocker;
     nsCOMPtr<nsIRadioVisitor> visitor =
       new nsRadioSetValueMissingState(this, valueMissing, notify);
     VisitGroup(visitor, notify);
   }
 }
 
 void
 nsHTMLInputElement::UpdateValueMissingValidityState()
@@ -3866,25 +3808,18 @@ void
 nsHTMLInputElement::UpdateAllValidityStates(PRBool aNotify)
 {
   PRBool validBefore = IsValid();
   UpdateTooLongValidityState();
   UpdateValueMissingValidityState();
   UpdateTypeMismatchValidityState();
   UpdatePatternMismatchValidityState();
 
-  if (validBefore != IsValid() && aNotify) {
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this,
-                               NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                               NS_EVENT_STATE_MOZ_UI_VALID |
-                               NS_EVENT_STATE_MOZ_UI_INVALID);
-    }
+  if (validBefore != IsValid()) {
+    UpdateState(aNotify);
   }
 }
 
 void
 nsHTMLInputElement::UpdateBarredFromConstraintValidation()
 {
   SetBarredFromConstraintValidation(mType == NS_FORM_INPUT_HIDDEN ||
                                     mType == NS_FORM_INPUT_BUTTON ||
@@ -4167,36 +4102,30 @@ nsHTMLInputElement::InitializeKeyboardEv
 
 NS_IMETHODIMP_(void)
 nsHTMLInputElement::OnValueChanged(PRBool aNotify)
 {
   UpdateAllValidityStates(aNotify);
 
   // :-moz-placeholder pseudo-class may change when the value changes.
   // However, we don't want to waste cycles if the state doesn't apply.
-  if (aNotify && PlaceholderApplies()
+  if (PlaceholderApplies()
       && HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
       && !nsContentUtils::IsFocusedContent((nsIContent*)(this))) {
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_PLACEHOLDER);
-    }
+    UpdateState(aNotify);
   }
 }
 
 void
-nsHTMLInputElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
+nsHTMLInputElement::FieldSetDisabledChanged(PRBool aNotify)
 {
   UpdateValueMissingValidityState();
   UpdateBarredFromConstraintValidation();
 
-  aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-             NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
-  nsGenericHTMLFormElement::FieldSetDisabledChanged(aStates, aNotify);
+  nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
 }
 
 PRInt32
 nsHTMLInputElement::GetFilterFromAccept()
 {
   NS_ASSERTION(HasAttr(kNameSpaceID_None, nsGkAtoms::accept),
                "You should not call GetFileFiltersFromAccept if the element"
                " has no accept attribute!");
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -140,33 +140,33 @@ public:
   // nsIPhonetic
   NS_DECL_NSIPHONETIC
 
   // nsIDOMNSEditableElement
   NS_IMETHOD GetEditor(nsIEditor** aEditor)
   {
     return nsGenericHTMLElement::GetEditor(aEditor);
   }
-
-  // Forward nsIDOMHTMLElement
-  NS_FORWARD_NSIDOMHTMLELEMENT_NOFOCUSCLICK(nsGenericHTMLFormElement::)
-  NS_IMETHOD Focus();
-  NS_IMETHOD Click();
+
+  // Forward nsIDOMHTMLElement
+  NS_FORWARD_NSIDOMHTMLELEMENT_NOFOCUSCLICK(nsGenericHTMLFormElement::)
+  NS_IMETHOD Focus();
+  NS_IMETHOD Click();
 
   NS_IMETHOD SetUserInput(const nsAString& aInput);
 
   // Overriden nsIFormControl methods
   NS_IMETHOD_(PRUint32) GetType() const { return mType; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual PRBool RestoreState(nsPresState* aState);
   virtual PRBool AllowDrop();
 
-  virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
+  virtual void FieldSetDisabledChanged(PRBool aNotify);
 
   // nsIContent
   virtual PRBool IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex);
 
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
@@ -213,16 +213,17 @@ public:
   NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify);
   NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
   NS_IMETHOD_(void) InitializeKeyboardEventListeners();
   NS_IMETHOD_(void) OnValueChanged(PRBool aNotify);
 
   void GetDisplayFileName(nsAString& aFileName) const;
   const nsCOMArray<nsIDOMFile>& GetFiles() const;
   void SetFiles(const nsCOMArray<nsIDOMFile>& aFiles, bool aSetValueChanged);
+  void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
 
   void SetCheckedChangedInternal(PRBool aCheckedChanged);
   PRBool GetCheckedChanged() const {
     return GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED);
   }
   void AddedToRadioGroup();
   void WillRemoveFromRadioGroup();
 
@@ -234,19 +235,19 @@ public:
    * @return the selected button (or null).
    */
   already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   NS_IMETHOD FireAsyncClickHandler();
 
-  virtual void UpdateEditableState()
+  virtual void UpdateEditableState(PRBool aNotify)
   {
-    return UpdateEditableFormControlState();
+    return UpdateEditableFormControlState(aNotify);
   }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLInputElement,
                                                      nsGenericHTMLFormElement)
 
   static UploadLastDir* gUploadLastDir;
   // create and destroy the static UploadLastDir object for remembering
   // which directory was last used on a site-by-site basis
@@ -453,16 +454,21 @@ protected:
   nsresult MaybeSubmitForm(nsPresContext* aPresContext);
 
   /**
    * Update mFileList with the currently selected file.
    */
   nsresult UpdateFileList();
 
   /**
+   * Called after calling one of the SetFiles() functions.
+   */
+  void AfterSetFiles(bool aSetValueChanged);
+
+  /**
    * Determine whether the editor needs to be initialized explicitly for
    * a particular event.
    */
   PRBool NeedToInitializeEditorForEvent(nsEventChainPreVisitor& aVisitor) const;
 
   /**
    * Get the value mode of the element, depending of the type.
    */
--- a/content/html/content/src/nsHTMLLinkElement.cpp
+++ b/content/html/content/src/nsHTMLLinkElement.cpp
@@ -107,16 +107,17 @@ public:
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              PRBool aNotify);
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void GetLinkTarget(nsAString& aTarget);
   virtual nsLinkState GetLinkState() const;
+  virtual void RequestLinkStateUpdate();
   virtual already_AddRefed<nsIURI> GetHrefURI() const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsEventStates IntrinsicState() const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
@@ -127,17 +128,18 @@ protected:
                                  PRBool* aIsAlternate);
 };
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Link)
 
 
 nsHTMLLinkElement::nsHTMLLinkElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-  : nsGenericHTMLElement(aNodeInfo)
+  : nsGenericHTMLElement(aNodeInfo),
+    Link(this)
 {
 }
 
 nsHTMLLinkElement::~nsHTMLLinkElement()
 {
 }
 
 
@@ -373,16 +375,22 @@ nsHTMLLinkElement::GetLinkTarget(nsAStri
 }
 
 nsLinkState
 nsHTMLLinkElement::GetLinkState() const
 {
   return Link::GetLinkState();
 }
 
+void
+nsHTMLLinkElement::RequestLinkStateUpdate()
+{
+  UpdateLinkState(Link::LinkState());
+}
+
 already_AddRefed<nsIURI>
 nsHTMLLinkElement::GetHrefURI() const
 {
   return GetHrefURIForAnchors();
 }
 
 already_AddRefed<nsIURI>
 nsHTMLLinkElement::GetStyleSheetURL(PRBool* aIsInline)
--- a/content/html/content/src/nsHTMLObjectElement.cpp
+++ b/content/html/content/src/nsHTMLObjectElement.cpp
@@ -158,16 +158,19 @@ nsHTMLObjectElement::nsHTMLObjectElement
   : nsGenericHTMLFormElement(aNodeInfo),
     mIsDoneAddingChildren(!aFromParser)
 {
   RegisterFreezableElement();
   SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
 
   // <object> is always barred from constraint validation.
   SetBarredFromConstraintValidation(PR_TRUE);
+
+  // By default we're in the loading state
+  AddStatesSilently(NS_EVENT_STATE_LOADING);
 }
 
 nsHTMLObjectElement::~nsHTMLObjectElement()
 {
   UnregisterFreezableElement();
   DestroyImageLoadingContent();
 }
 
--- a/content/html/content/src/nsHTMLOptGroupElement.cpp
+++ b/content/html/content/src/nsHTMLOptGroupElement.cpp
@@ -96,16 +96,18 @@ protected:
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(OptGroup)
 
 
 nsHTMLOptGroupElement::nsHTMLOptGroupElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
+  // We start off enabled
+  AddStatesSilently(NS_EVENT_STATE_ENABLED);
 }
 
 nsHTMLOptGroupElement::~nsHTMLOptGroupElement()
 {
 }
 
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLOptGroupElement, nsGenericElement)
--- a/content/html/content/src/nsHTMLOptionElement.cpp
+++ b/content/html/content/src/nsHTMLOptionElement.cpp
@@ -115,16 +115,18 @@ NS_NewHTMLOptionElement(already_AddRefed
 }
 
 nsHTMLOptionElement::nsHTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
     mSelectedChanged(PR_FALSE),
     mIsSelected(PR_FALSE),
     mIsInSetDefaultSelected(PR_FALSE)
 {
+  // We start off enabled
+  AddStatesSilently(NS_EVENT_STATE_ENABLED);
 }
 
 nsHTMLOptionElement::~nsHTMLOptionElement()
 {
 }
 
 // ISupports
 
@@ -164,24 +166,20 @@ nsHTMLOptionElement::GetForm(nsIDOMHTMLF
 }
 
 void
 nsHTMLOptionElement::SetSelectedInternal(PRBool aValue, PRBool aNotify)
 {
   mSelectedChanged = PR_TRUE;
   mIsSelected = aValue;
 
-  // When mIsInSetDefaultSelected is true, the notification will be handled by
+  // When mIsInSetDefaultSelected is true, the state change will be handled by
   // SetAttr/UnsetAttr.
-  if (aNotify && !mIsInSetDefaultSelected) {
-    nsIDocument* document = GetCurrentDoc();
-    if (document) {
-      mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, aNotify);
-      document->ContentStateChanged(this, NS_EVENT_STATE_CHECKED);
-    }
+  if (!mIsInSetDefaultSelected) {
+    UpdateState(aNotify);
   }
 }
 
 NS_IMETHODIMP 
 nsHTMLOptionElement::GetSelected(PRBool* aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = PR_FALSE;
--- a/content/html/content/src/nsHTMLOutputElement.cpp
+++ b/content/html/content/src/nsHTMLOutputElement.cpp
@@ -81,16 +81,20 @@ public:
 
   nsresult Clone(nsINodeInfo* aNodeInfo, nsINode** aResult) const;
 
   PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
                         const nsAString& aValue, nsAttrValue& aResult);
 
   nsEventStates IntrinsicState() const;
 
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                               nsIContent* aBindingParent,
+                               PRBool aCompileEventHandlers);
+
   // This function is called when a callback function from nsIMutationObserver
   // has to be used to update the defaultValue attribute.
   void DescendantsChanged();
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
@@ -115,16 +119,19 @@ protected:
 NS_IMPL_NS_NEW_HTML_ELEMENT(Output)
 
 
 nsHTMLOutputElement::nsHTMLOutputElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLFormElement(aNodeInfo)
   , mValueModeFlag(eModeDefault)
 {
   AddMutationObserver(this);
+
+  // We start out valid and ui-valid (since we have no form).
+  AddStatesSilently(NS_EVENT_STATE_VALID | NS_EVENT_STATE_MOZ_UI_VALID);
 }
 
 nsHTMLOutputElement::~nsHTMLOutputElement()
 {
   if (mTokenList) {
     mTokenList->DropReference();
   }
 }
@@ -152,24 +159,17 @@ NS_IMPL_STRING_ATTR(nsHTMLOutputElement,
 // nsIConstraintValidation
 NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(nsHTMLOutputElement)
 
 NS_IMETHODIMP
 nsHTMLOutputElement::SetCustomValidity(const nsAString& aError)
 {
   nsIConstraintValidation::SetCustomValidity(aError);
 
-  nsIDocument* doc = GetCurrentDoc();
-  if (doc) {
-    MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-    doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
-                                   NS_EVENT_STATE_VALID |
-                                   NS_EVENT_STATE_MOZ_UI_INVALID |
-                                   NS_EVENT_STATE_MOZ_UI_VALID);
-  }
+  UpdateState(true);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLOutputElement::Reset()
 {
   mValueModeFlag = eModeDefault;
@@ -217,16 +217,36 @@ nsHTMLOutputElement::IntrinsicState() co
     if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) {
       states |= NS_EVENT_STATE_MOZ_UI_INVALID;
     }
   }
 
   return states;
 }
 
+nsresult
+nsHTMLOutputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                nsIContent* aBindingParent,
+                                PRBool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
+                                                     aBindingParent,
+                                                     aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Unfortunately, we can actually end up having to change our state
+  // as a result of being bound to a tree even from the parser: we
+  // might end up a in a novalidate form, and unlike other form
+  // controls that on its own is enough to make change ui-valid state.
+  // So just go ahead and update our state now.
+  UpdateState(false);
+
+  return rv;
+}
+
 NS_IMETHODIMP
 nsHTMLOutputElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
   return nsGenericHTMLFormElement::GetForm(aForm);
 }
 
 NS_IMETHODIMP
 nsHTMLOutputElement::GetType(nsAString& aType)
--- a/content/html/content/src/nsHTMLProgressElement.cpp
+++ b/content/html/content/src/nsHTMLProgressElement.cpp
@@ -97,16 +97,18 @@ const double nsHTMLProgressElement::kDef
 const double nsHTMLProgressElement::kDefaultMax            =  1.0;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Progress)
 
 
 nsHTMLProgressElement::nsHTMLProgressElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLFormElement(aNodeInfo)
 {
+  // We start out indeterminate
+  AddStatesSilently(NS_EVENT_STATE_INDETERMINATE);
 }
 
 nsHTMLProgressElement::~nsHTMLProgressElement()
 {
 }
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLProgressElement, nsGenericElement)
 NS_IMPL_RELEASE_INHERITED(nsHTMLProgressElement, nsGenericElement)
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -151,16 +151,21 @@ nsHTMLSelectElement::nsHTMLSelectElement
     mOptGroupCount(0),
     mSelectedIndex(-1)
 {
   // FIXME: Bug 328908, set mOptions in an Init function and get rid of null
   // checks.
 
   // DoneAddingChildren() will be called later if it's from the parser,
   // otherwise it is
+
+  // Set up our default state: enabled, optional, and valid.
+  AddStatesSilently(NS_EVENT_STATE_ENABLED |
+                    NS_EVENT_STATE_OPTIONAL |
+                    NS_EVENT_STATE_VALID);
 }
 
 nsHTMLSelectElement::~nsHTMLSelectElement()
 {
   if (mOptions) {
     mOptions->DropReference();
   }
 }
@@ -198,24 +203,17 @@ NS_IMPL_ELEMENT_CLONE(nsHTMLSelectElemen
 // nsIConstraintValidation
 NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(nsHTMLSelectElement)
 
 NS_IMETHODIMP
 nsHTMLSelectElement::SetCustomValidity(const nsAString& aError)
 {
   nsIConstraintValidation::SetCustomValidity(aError);
 
-  nsIDocument* doc = GetCurrentDoc();
-  if (doc) {
-    MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-    doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
-                                   NS_EVENT_STATE_VALID |
-                                   NS_EVENT_STATE_MOZ_UI_INVALID |
-                                   NS_EVENT_STATE_MOZ_UI_VALID);
-  }
+  UpdateState(true);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
   return nsGenericHTMLFormElement::GetForm(aForm);
@@ -350,26 +348,17 @@ nsHTMLSelectElement::RemoveOptionsFromLi
 
     // Select something in case we removed the selected option on a
     // single select
     if (!CheckSelectSomething(aNotify) && mSelectedIndex == -1) {
       // Update the validity state in case of we've just removed the last
       // option.
       UpdateValueMissingValidityState();
 
-      if (aNotify) {
-        nsIDocument* doc = GetCurrentDoc();
-        if (doc) {
-          MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-          doc->ContentStateChanged(this, NS_EVENT_STATE_VALID |
-                                         NS_EVENT_STATE_INVALID |
-                                         NS_EVENT_STATE_MOZ_UI_INVALID |
-                                         NS_EVENT_STATE_MOZ_UI_VALID);
-        }
-      }
+      UpdateState(aNotify);
     }
   }
 
   return NS_OK;
 }
 
 static PRBool IsOptGroup(nsIContent *aContent)
 {
@@ -883,26 +872,17 @@ nsHTMLSelectElement::OnOptionSelected(ns
   }
 
   // Let the frame know too
   if (aSelectFrame) {
     aSelectFrame->OnOptionSelected(aIndex, aSelected);
   }
 
   UpdateValueMissingValidityState();
-  if (aNotify) {
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, NS_EVENT_STATE_VALID |
-                                     NS_EVENT_STATE_INVALID |
-                                     NS_EVENT_STATE_MOZ_UI_INVALID |
-                                     NS_EVENT_STATE_MOZ_UI_VALID);
-    }
-  }
+  UpdateState(aNotify);
 }
 
 void
 nsHTMLSelectElement::FindSelectedIndex(PRInt32 aStartIndex, PRBool aNotify)
 {
   mSelectedIndex = -1;
   SetSelectionChanged(PR_TRUE, aNotify);
   PRUint32 len;
@@ -1316,26 +1296,17 @@ nsHTMLSelectElement::SelectSomething(PRB
     PRBool disabled;
     nsresult rv = IsOptionDisabled(i, &disabled);
 
     if (NS_FAILED(rv) || !disabled) {
       rv = SetSelectedIndexInternal(i, aNotify);
       NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
       UpdateValueMissingValidityState();
-      if (aNotify) {
-        nsIDocument* doc = GetCurrentDoc();
-        if (doc) {
-          MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-          doc->ContentStateChanged(this, NS_EVENT_STATE_VALID |
-                                         NS_EVENT_STATE_INVALID |
-                                         NS_EVENT_STATE_MOZ_UI_INVALID |
-                                         NS_EVENT_STATE_MOZ_UI_VALID);
-        }
-      }
+      UpdateState(aNotify);
 
       return PR_TRUE;
     }
   }
 
   return PR_FALSE;
 }
 
@@ -1346,21 +1317,40 @@ nsHTMLSelectElement::BindToTree(nsIDocum
 {
   nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
                                                      aBindingParent,
                                                      aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If there is a disabled fieldset in the parent chain, the element is now
   // barred from constraint validation.
+  // XXXbz is this still needed now that fieldset changes always call
+  // FieldSetDisabledChanged?
   UpdateBarredFromConstraintValidation();
 
+  // And now make sure our state is up to date
+  UpdateState(false);
+
   return rv;
 }
 
+void
+nsHTMLSelectElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
+{
+  nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
+
+  // We might be no longer disabled because our parent chain changed.
+  // XXXbz is this still needed now that fieldset changes always call
+  // FieldSetDisabledChanged?
+  UpdateBarredFromConstraintValidation();
+
+  // And now make sure our state is up to date
+  UpdateState(false);
+}
+
 nsresult
 nsHTMLSelectElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                    const nsAString* aValue, PRBool aNotify)
 {
   if (aNotify && aName == nsGkAtoms::disabled &&
       aNameSpaceID == kNameSpaceID_None) {
     mDisabledChanged = PR_TRUE;
   }
@@ -1368,36 +1358,24 @@ nsHTMLSelectElement::BeforeSetAttr(PRInt
   return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
                                                  aValue, aNotify);
 }
 
 nsresult
 nsHTMLSelectElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                   const nsAString* aValue, PRBool aNotify)
 {
-  nsEventStates states;
-
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::disabled) {
       UpdateBarredFromConstraintValidation();
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     } else if (aName == nsGkAtoms::required) {
       UpdateValueMissingValidityState();
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     }
-  }
 
-  if (aNotify && !states.IsEmpty()) {
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, states);
-    }
+    UpdateState(aNotify);
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
                                                 aValue, aNotify);
 }
 
 nsresult
 nsHTMLSelectElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
@@ -1456,16 +1434,19 @@ nsHTMLSelectElement::DoneAddingChildren(
 
   // Now that we're done, select something (if it's a single select something
   // must be selected)
   if (!CheckSelectSomething(PR_FALSE)) {
     // If an option has @selected set, it will be selected during parsing but
     // with an empty value. We have to make sure the select element updates it's
     // validity state to take this into account.
     UpdateValueMissingValidityState();
+
+    // And now make sure we update our content state too
+    UpdateState(aHaveNotified);
   }
 
   mDefaultSelectionSet = PR_TRUE;
 
   return NS_OK;
 }
 
 PRBool
@@ -1559,22 +1540,17 @@ nsHTMLSelectElement::PostHandleEvent(nsE
     mCanShowValidUI = ShouldShowValidityUI();
 
     // We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor
     // NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change.
   } else if (aVisitor.mEvent->message == NS_BLUR_CONTENT) {
     mCanShowInvalidUI = PR_TRUE;
     mCanShowValidUI = PR_TRUE;
 
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_UI_VALID |
-                                     NS_EVENT_STATE_MOZ_UI_INVALID);
-    }
+    UpdateState(true);
   }
 
   return nsGenericHTMLFormElement::PostHandleEvent(aVisitor);
 }
 
 nsEventStates
 nsHTMLSelectElement::IntrinsicState() const
 {
@@ -2273,37 +2249,30 @@ nsHTMLOptionCollection::Remove(PRInt32 a
 
 void
 nsHTMLSelectElement::UpdateBarredFromConstraintValidation()
 {
   SetBarredFromConstraintValidation(IsDisabled());
 }
 
 void
-nsHTMLSelectElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
+nsHTMLSelectElement::FieldSetDisabledChanged(PRBool aNotify)
 {
   UpdateBarredFromConstraintValidation();
 
-  aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-             NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
-  nsGenericHTMLFormElement::FieldSetDisabledChanged(aStates, aNotify);
+  nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
 }
 
 void
 nsHTMLSelectElement::SetSelectionChanged(PRBool aValue, PRBool aNotify)
 {
   if (!mDefaultSelectionSet) {
     return;
   }
 
   PRBool previousSelectionChangedValue = mSelectionHasChanged;
   mSelectionHasChanged = aValue;
 
-  if (aNotify && mSelectionHasChanged != previousSelectionChangedValue) {
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, NS_EVENT_STATE_MOZ_UI_INVALID |
-                                     NS_EVENT_STATE_MOZ_UI_VALID);
-    }
+  if (mSelectionHasChanged != previousSelectionChangedValue) {
+    UpdateState(aNotify);
   }
 }
 
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -284,17 +284,17 @@ public:
 
   // Overriden nsIFormControl methods
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_SELECT; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual PRBool RestoreState(nsPresState* aState);
 
-  virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
+  virtual void FieldSetDisabledChanged(PRBool aNotify);
 
   nsEventStates IntrinsicState() const;
 
   /**
    * To be called when stuff is added under a child of the select--but *before*
    * they are actually added.
    *
    * @param aOptions the content that was added (usually just an option, but
@@ -371,16 +371,17 @@ public:
   NS_IMETHOD GetHasOptGroups(PRBool* aHasGroups);
 
   /**
    * Called when an attribute is about to be changed
    */
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                nsIContent* aBindingParent,
                                PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep, PRBool aNullParent);
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAString* aValue, PRBool aNotify);
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              PRBool aNotify);
   
   virtual nsresult DoneAddingChildren(PRBool aHaveNotified);
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp
+++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp
@@ -175,16 +175,19 @@ 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);
+
+  // By default we're in the loading state
+  AddStatesSilently(NS_EVENT_STATE_LOADING);
 }
 
 nsHTMLSharedObjectElement::~nsHTMLSharedObjectElement()
 {
   UnregisterFreezableElement();
   DestroyImageLoadingContent();
 }
 
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -129,17 +129,17 @@ public:
 
   // nsIFormControl
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_TEXTAREA; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual PRBool RestoreState(nsPresState* aState);
 
-  virtual void FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify);
+  virtual void FieldSetDisabledChanged(PRBool aNotify);
 
   virtual nsEventStates IntrinsicState() const;
 
   // nsITextControlElemet
   NS_IMETHOD SetValueChanged(PRBool aValueChanged);
   NS_IMETHOD_(PRBool) IsSingleLineTextControl() const;
   NS_IMETHOD_(PRBool) IsTextArea() const;
   NS_IMETHOD_(PRBool) IsPlainTextControl() const;
@@ -199,19 +199,19 @@ public:
                                  const nsAString* aValue, PRBool aNotify);
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
-  virtual void UpdateEditableState()
+  virtual void UpdateEditableState(PRBool aNotify)
   {
-    return UpdateEditableFormControlState();
+    return UpdateEditableFormControlState(aNotify);
   }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTextAreaElement,
                                            nsGenericHTMLFormElement)
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   // nsIConstraintValidation
@@ -316,16 +316,25 @@ nsHTMLTextAreaElement::nsHTMLTextAreaEle
     mDoneAddingChildren(!aFromParser),
     mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
     mDisabledChanged(PR_FALSE),
     mCanShowInvalidUI(PR_TRUE),
     mCanShowValidUI(PR_TRUE),
     mState(new nsTextEditorState(this))
 {
   AddMutationObserver(this);
+
+  // Set up our default state.  By default we're enabled (since we're
+  // a control type that can be disabled but not actually disabled
+  // right now), optional, and valid.  We are NOT readwrite by default
+  // until someone calls UpdateEditableState on us, apparently!  Also
+  // by default we don't have to show validity UI and so forth.
+  AddStatesSilently(NS_EVENT_STATE_ENABLED |
+                    NS_EVENT_STATE_OPTIONAL |
+                    NS_EVENT_STATE_VALID);
 }
 
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLTextAreaElement)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLTextAreaElement,
                                                 nsGenericHTMLFormElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -582,28 +591,17 @@ nsHTMLTextAreaElement::SetValueChanged(P
   PRBool previousValue = mValueChanged;
 
   mValueChanged = aValueChanged;
   if (!aValueChanged && !mState->IsEmpty()) {
     mState->EmptyValue();
   }
 
   if (mValueChanged != previousValue) {
-    nsEventStates states = NS_EVENT_STATE_MOZ_UI_VALID |
-                           NS_EVENT_STATE_MOZ_UI_INVALID;
-
-    if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
-      states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
-    }
-
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, states);
-    }
+    UpdateState(true);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::GetDefaultValue(nsAString& aDefaultValue)
 {
@@ -742,46 +740,30 @@ nsresult
 nsHTMLTextAreaElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   if (aVisitor.mEvent->message == NS_FORM_SELECTED) {
     mHandlingSelect = PR_FALSE;
   }
 
   if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
       aVisitor.mEvent->message == NS_BLUR_CONTENT) {
-    nsEventStates states;
-
     if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) {
       // If the invalid UI is shown, we should show it while focusing (and
       // update). Otherwise, we should not.
       mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
 
       // If neither invalid UI nor valid UI is shown, we shouldn't show the valid
       // UI while typing.
       mCanShowValidUI = ShouldShowValidityUI();
-
-      // We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor
-      // NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change.
     } else { // NS_BLUR_CONTENT
       mCanShowInvalidUI = PR_TRUE;
       mCanShowValidUI = PR_TRUE;
-      states |= NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     }
 
-    if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
-      // TODO: checking if the value is empty could be a good idea but we do not
-      // have a simple way to do that, see bug 585100
-      states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
-    }
-
-    nsIDocument* doc = GetCurrentDoc();
-    if (doc) {
-      MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-      doc->ContentStateChanged(this, states);
-    }
+    UpdateState(true);
   }
 
   // Reset the flag for other content besides this text field
   aVisitor.mEvent->flags |= (aVisitor.mItemFlags & NS_NO_CONTENT_DISPATCH)
     ? NS_EVENT_FLAG_NO_CONTENT_DISPATCH : NS_EVENT_FLAG_NONE;
 
   return NS_OK;
 }
@@ -1111,27 +1093,33 @@ nsHTMLTextAreaElement::BindToTree(nsIDoc
                                                      aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If there is a disabled fieldset in the parent chain, the element is now
   // barred from constraint validation and can't suffer from value missing.
   UpdateValueMissingValidityState();
   UpdateBarredFromConstraintValidation();
 
+  // And now make sure our state is up to date
+  UpdateState(false);
+
   return rv;
 }
 
 void
 nsHTMLTextAreaElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
 
   // We might be no longer disabled because of parent chain changed.
   UpdateValueMissingValidityState();
   UpdateBarredFromConstraintValidation();
+
+  // And now make sure our state is up to date
+  UpdateState(false);
 }
 
 nsresult
 nsHTMLTextAreaElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                      const nsAString* aValue, PRBool aNotify)
 {
   if (aNotify && aName == nsGkAtoms::disabled &&
       aNameSpaceID == kNameSpaceID_None) {
@@ -1189,50 +1177,33 @@ nsHTMLTextAreaElement::ContentChanged(ns
     Reset();
   }
 }
 
 nsresult
 nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                     const nsAString* aValue, PRBool aNotify)
 {
-  nsEventStates states;
-
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
         aName == nsGkAtoms::readonly) {
       UpdateValueMissingValidityState();
 
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         UpdateBarredFromConstraintValidation();
       }
-
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID |
-                NS_EVENT_STATE_MOZ_SUBMITINVALID;
     } else if (aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     }
 
-    if (aNotify) {
-      nsIDocument* doc = GetCurrentDoc();
-
-      if (aName == nsGkAtoms::readonly) {
-        UpdateEditableState();
-        states |= NS_EVENT_STATE_MOZ_READONLY | NS_EVENT_STATE_MOZ_READWRITE;
-      }
-
-      if (doc && !states.IsEmpty()) {
-        MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(this, states);
-      }
+    if (aName == nsGkAtoms::readonly) {
+      UpdateEditableState(aNotify);
     }
+    UpdateState(aNotify);
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                                 aNotify);
 }
 
 nsresult
 nsHTMLTextAreaElement::CopyInnerTo(nsGenericElement* aDest) const
@@ -1265,24 +1236,17 @@ nsHTMLTextAreaElement::IsValueEmpty() co
 
 // nsIConstraintValidation
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::SetCustomValidity(const nsAString& aError)
 {
   nsIConstraintValidation::SetCustomValidity(aError);
 
-  nsIDocument* doc = GetCurrentDoc();
-  if (doc) {
-    MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-    doc->ContentStateChanged(this, NS_EVENT_STATE_INVALID |
-                                   NS_EVENT_STATE_VALID |
-                                   NS_EVENT_STATE_MOZ_UI_INVALID |
-                                   NS_EVENT_STATE_MOZ_UI_VALID);
-  }
+  UpdateState(true);
 
   return NS_OK;
 }
 
 PRBool
 nsHTMLTextAreaElement::IsTooLong()
 {
   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength) || !mValueChanged) {
@@ -1483,41 +1447,24 @@ nsHTMLTextAreaElement::InitializeKeyboar
 NS_IMETHODIMP_(void)
 nsHTMLTextAreaElement::OnValueChanged(PRBool aNotify)
 {
   // Update the validity state
   PRBool validBefore = IsValid();
   UpdateTooLongValidityState();
   UpdateValueMissingValidityState();
 
-  if (aNotify) {
-    nsEventStates states;
-    if (validBefore != IsValid()) {
-      states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-                NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
-    }
-
-    if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
-        && !nsContentUtils::IsFocusedContent((nsIContent*)(this))) {
-      states |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
-    }
-
-    if (!states.IsEmpty()) {
-      nsIDocument* doc = GetCurrentDoc();
-      if (doc) {
-        MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
-        doc->ContentStateChanged(this, states);
-      }
-    }
+  if (validBefore != IsValid() ||
+      (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
+       && !nsContentUtils::IsFocusedContent((nsIContent*)(this)))) {
+    UpdateState(aNotify);
   }
 }
 
 void
-nsHTMLTextAreaElement::FieldSetDisabledChanged(nsEventStates aStates, PRBool aNotify)
+nsHTMLTextAreaElement::FieldSetDisabledChanged(PRBool aNotify)
 {
   UpdateValueMissingValidityState();
   UpdateBarredFromConstraintValidation();
 
-  aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
-             NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
-  nsGenericHTMLFormElement::FieldSetDisabledChanged(aStates, aNotify);
+  nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
 }
 
--- a/content/html/content/src/nsRadioVisitor.cpp
+++ b/content/html/content/src/nsRadioVisitor.cpp
@@ -78,19 +78,13 @@ nsRadioSetValueMissingState::Visit(nsIFo
     return PR_TRUE;
   }
 
   nsHTMLInputElement* input = static_cast<nsHTMLInputElement*>(aRadio);
 
   input->SetValidityState(nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING,
                           mValidity);
 
-  nsIDocument* doc = input->GetCurrentDoc();
-  if (mNotify && doc) {
-    doc->ContentStateChanged(input, NS_EVENT_STATE_VALID |
-                                    NS_EVENT_STATE_INVALID |
-                                    NS_EVENT_STATE_MOZ_UI_VALID |
-                                    NS_EVENT_STATE_MOZ_UI_INVALID);
-  }
+  input->UpdateState(true);
 
   return PR_TRUE;
 }
 
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -235,16 +235,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug557087-3.html \
 		test_bug557087-4.html \
 		test_bug557087-5.html \
 		test_bug557087-6.html \
 		test_bug586763.html \
 		test_bug587469.html \
 		test_bug598643.html \
 		test_bug596350.html \
+		test_bug598833-1.html \
 		test_bug600155.html \
 		test_bug556007.html \
 		test_bug606817.html \
 		test_bug297761.html \
 		file_bug297761.html \
 		test_bug607145.html \
 		test_bug601061.html \
 		test_bug596511.html \
@@ -274,12 +275,14 @@ include $(topsrcdir)/config/rules.mk
 		test_bug643051.html \
 		test_bug583514.html \
 		test_bug514437.html \
 		test_bug560112.html \
 		test_bug649134.html \
 		test_bug658746.html \
 		test_bug659596.html \
 		test_bug659743.xml \
+		test_bug660663.html \
+		test_restore_from_parser_fragment.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/html/content/test/reflect.js
+++ b/content/html/content/test/reflect.js
@@ -88,8 +88,52 @@ function reflectUnsignedInt(aElement, aA
   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");
   }
 }
+
+/**
+ * @param aElement            Element     node to test on
+ * @param aAttr               String      name of the attribute
+ * @param aSupportedValues    Array       values we supported
+ * @param aUnsupportedValues  Array       values we don't support
+ */
+function reflectLimitedEnumerated(aElement, aAttr, aSupportedValues,
+                                  aUnsupportedValues)
+{
+  aSupportedValues.forEach(function (v) {
+    aElement.setAttribute(aAttr, v);
+    is(aElement[aAttr], v);
+    is(aElement.getAttribute(aAttr), v);
+    aElement.removeAttribute(aAttr);
+
+    aElement.setAttribute(aAttr, v.toUpperCase());
+    is(aElement[aAttr], v);
+    is(aElement.getAttribute(aAttr), v.toUpperCase());
+    aElement.removeAttribute(aAttr);
+
+    aElement[aAttr] = v;
+    is(aElement[aAttr], v);
+    is(aElement.getAttribute(aAttr), v);
+    aElement.removeAttribute(aAttr);
+
+    aElement[aAttr] = v.toUpperCase();
+    is(aElement[aAttr], v);
+    is(aElement.getAttribute(aAttr), v.toUpperCase());
+    aElement.removeAttribute(aAttr);
+  });
+  ["cheesecake"].concat(aUnsupportedValues).forEach(function (v) {
+    aElement.setAttribute(aAttr, v);
+    is(aElement[aAttr], "");
+    is(aElement.getAttribute(aAttr), v);
+    aElement.removeAttribute(aAttr);
+
+    aElement[aAttr] = v;
+    is(aElement[aAttr], "");
+    is(aElement.getAttribute(aAttr), v);
+    aElement.removeAttribute(aAttr);
+  });
+}
+
--- a/content/html/content/test/test_bug345822.html
+++ b/content/html/content/test/test_bug345822.html
@@ -58,17 +58,17 @@ function checkNotSufferingFromBeingMissi
   ok(element.validity.valid, "Element should be valid");
   ok(element.checkValidity(), "Element should be valid");
   is(element.validationMessage, "",
     "Validation message should be the empty string");
 
   if (element.type != 'radio' && element.type != 'checkbox') {
     is(window.getComputedStyle(element, null).getPropertyValue('background-color'),
        doNotApply ? "rgb(0, 0, 0)" : "rgb(0, 255, 0)",
-       "The pseudo-class is not correctly applied");
+       "The pseudo-class is not correctly applied to " + element.localName);
   }
 }
 
 function checkSufferingFromBeingMissing(element)
 {
   ok(element.validity.valueMissing, "Element should suffer from value missing");
   ok(!element.validity.valid, "Element should not be valid");
   ok(!element.checkValidity(), "Element should not be valid");
--- a/content/html/content/test/test_bug514437.html
+++ b/content/html/content/test/test_bug514437.html
@@ -10,17 +10,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <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=514437">Mozilla Bug 514437</a>
 and
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633913">Mozilla Bug 633913</a>
 <p id="display"></p>
-<iframe name="submit_frame" onload="onFormSubmission();" style="visibility: hidden;"></iframe>
+<iframe name="submit_frame" style="visibility: hidden;"></iframe>
 <div id="content" style="visibility: hidden;">
   <form id='f' method='get' target='submit_frame' action='foo'>
     <progress id='p'></progress>
   </form>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
@@ -250,32 +250,32 @@ function checkNotResetableAndFormSubmiss
   input.name = 'a';
   input.value = 'tulip';
   form.appendChild(input);
 
   // Setting values.
   aElement.value = 42.0;
   aElement.max = 100.0;
 
-  // This is going to call onFormSubmission().
-  form.submit();
-}
+  document.getElementsByName('submit_frame')[0].addEventListener("load", function() {
+    document.getElementsByName('submit_frame')[0].removeEventListener("load", arguments.callee, false);
 
-function onFormSubmission()
-{
-  /**
-   * All elements values have been set just before the submission.
-   * The input element value should be in the submit url but the progress
-   * element value should not appear.
-   */
-  is(frames['submit_frame'].location.href,
-    'http://mochi.test:8888/tests/content/html/content/test/foo?a=tulip',
-     "The progress element value should not be submitted");
+    /**
+     * All elements values have been set just before the submission.
+     * The input element value should be in the submit url but the progress
+     * element value should not appear.
+     */
+    is(frames['submit_frame'].location.href,
+      'http://mochi.test:8888/tests/content/html/content/test/foo?a=tulip',
+       "The progress element value should not be submitted");
 
-  checkNotResetable();
+    checkNotResetable();
+  }, false);
+
+  form.submit();
 }
 
 function checkNotResetable()
 {
   // Try to reset the form.
   var form = document.forms[0];
   var element = document.getElementById('p');
 
--- a/content/html/content/test/test_bug596350.html
+++ b/content/html/content/test/test_bug596350.html
@@ -7,17 +7,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 596350</title>
   <script type="application/javascript" src="/MochiKit/packed.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=596350">Mozilla Bug 596350</a>
 <p id="display"></p>
-<div id="content" style="display: none">
+<div id="content">
   <object></object>
   <object data="iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMsALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg=="></object>
   <object data="data:text/html,foo"></object>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 596350 **/
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug598833-1.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=598833
+-->
+<head>
+  <title>Test for Bug 598833</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=598833">Mozilla Bug 598833</a>
+<p id="display">
+  <fieldset disabled>
+    <select id="s" multiple required>
+      <option>one</option>
+    </select>
+  </fieldset>
+</p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 598833 **/
+var s = $("s");
+is(s.mozMatchesSelector(":invalid"), false, "Disabled select should not be invalid");
+is(s.mozMatchesSelector(":valid"), false, "Disabled select should not be valid");
+var p = s.parentNode;
+p.removeChild(s);
+is(s.mozMatchesSelector(":invalid"), true,
+   "Required valueless select not in tree should be invalid");
+is(s.mozMatchesSelector(":valid"), false,
+   "Required valueless select not in tree should not be valid");
+p.appendChild(s);
+p.disabled = false;
+is(s.mozMatchesSelector(":invalid"), true,
+   "Required valueless select should be invalid");
+is(s.mozMatchesSelector(":valid"), false,
+   "Required valueless select should not be valid");
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug660663.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=660663
+-->
+<head>
+  <title>Test for Bug 660663</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script 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=660663">Mozilla Bug 660663</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 660663 **/
+reflectLimitedEnumerated(document.createElement("div"),
+                         "dir",
+                         ["ltr", "rtl"],
+                         ["auto"]);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_restore_from_parser_fragment.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=644959
+-->
+<head>
+  <title>Test for Bug 644959</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=644959">Mozilla Bug 644959</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 644959 **/
+
+var content = document.getElementById('content');
+
+function appendHTML(aParent, aElementString)
+{
+  aParent.innerHTML = "<form>" + aElementString + "</form>";
+}
+
+function clearHTML(aParent)
+{
+  aParent.innerHTML = "";
+}
+
+var tests = [
+  [  "button", "<button></button>" ],
+  [  "input", "<input>" ],
+  [  "textarea", "<textarea></textarea>" ],
+  [  "select", "<select></select>" ],
+];
+
+var element = null;
+
+for each (var test in tests) {
+  appendHTML(content, test[1]);
+  element = content.getElementsByTagName(test[0])[0];
+  is(element.disabled, false, "element shouldn't be disabled");
+  element.disabled = true;
+  is(element.disabled, true, "element should be disabled");
+
+  clearHTML(content);
+
+  appendHTML(content, test[1]);
+  element = content.getElementsByTagName(test[0])[0];
+  is(element.disabled, false, "element shouldn't be disabled");
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -986,17 +986,17 @@ nsHTMLDocument::StopDocumentLoad()
     if (mWriteState == eDocumentOpened) {
       NS_ASSERTION(IsHTML(), "document.open()ed doc is not HTML?");
 
       // Marking the document as closed, since pending scripts will be
       // stopped by nsDocument::StopDocumentLoad() below
       mWriteState = eDocumentClosed;
 
       // Remove the wyciwyg channel request from the document load group
-      // that we added in OpenCommon().
+      // that we added in Open().
       NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
                    "Trying to remove nonexistent wyciwyg channel!");
       RemoveWyciwygChannel();
       NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
                    "nsIWyciwygChannel could not be removed!");
     }
     nsDocument::StopDocumentLoad();
     UnblockOnload(PR_FALSE);
@@ -1511,45 +1511,62 @@ nsHTMLDocument::SetCookie(const nsAStrin
 
     NS_LossyConvertUTF16toASCII cookie(aCookie);
     service->SetCookieString(codebaseURI, prompt, cookie.get(), mChannel);
   }
 
   return NS_OK;
 }
 
-nsresult
-nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
-                           PRBool aReplace)
+NS_IMETHODIMP
+nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
+                     const nsAString& aReplaceOrName,
+                     const nsAString& aFeatures,
+                     JSContext* cx, PRUint8 aOptionalArgCount,
+                     nsISupports** aReturn)
 {
+  NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
+               "XOW should have caught this!");
+
+  // When called with 3 or more arguments, document.open() calls window.open().
+  if (aOptionalArgCount > 2) {
+    nsCOMPtr<nsIDOMWindowInternal> window = GetWindowInternal();
+    if (!window) {
+      return NS_OK;
+    }
+    nsCOMPtr<nsIDOMWindow> newWindow;
+    nsresult rv = window->Open(aContentTypeOrUrl, aReplaceOrName, aFeatures,
+                               getter_AddRefs(newWindow));
+    *aReturn = newWindow.forget().get();
+    return rv;
+  }
+
   if (!IsHTML() || mDisableDocWrite) {
     // No calling document.open() on XHTML
-
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
-  PRBool loadAsHtml5 = nsHtml5Module::sEnabled;
-
-  nsresult rv = NS_OK;
+  nsCAutoString contentType;
+  contentType.AssignLiteral("text/html");
+  if (aOptionalArgCount > 0) {
+    nsAutoString type;
+    ToLowerCase(aContentTypeOrUrl, type);
+    nsCAutoString actualType, dummy;
+    NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
+    if (!actualType.EqualsLiteral("text/html") &&
+        !type.EqualsLiteral("replace")) {
+      contentType.AssignLiteral("text/plain");
+    }
+  }
 
   // If we already have a parser we ignore the document.open call.
   if (mParser) {
-
     return NS_OK;
   }
 
-  NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
-               "XOW should have caught this!");
-
-  if (!aContentType.EqualsLiteral("text/html") &&
-      !aContentType.EqualsLiteral("text/plain")) {
-    NS_WARNING("Unsupported type; fix the caller");
-    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-  }
-
   // check whether we're in the middle of unload.  If so, ignore this call.
   nsCOMPtr<nsIDocShell> shell = do_QueryReferent(mDocumentContainer);
   if (!shell) {
     // We won't be able to create a parser anyway.
     return NS_OK;
   }
 
   PRBool inUnload;
@@ -1597,32 +1614,30 @@ nsHTMLDocument::OpenCommon(JSContext* cx
     nsCAutoString callerSpec;
     nsCAutoString thisSpec;
     if (callerDocURI) {
       callerDocURI->GetSpec(callerSpec);
     }
     if (thisURI) {
       thisURI->GetSpec(thisSpec);
     }
-    printf("nsHTMLDocument::OpenCommon callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
+    printf("nsHTMLDocument::Open callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
 #endif
 
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // Stop current loads targeted at the window this document is in.
   if (mScriptGlobalObject) {
     nsCOMPtr<nsIContentViewer> cv;
     shell->GetContentViewer(getter_AddRefs(cv));
 
     if (cv) {
       PRBool okToUnload;
-      rv = cv->PermitUnload(PR_FALSE, &okToUnload);
-
-      if (NS_SUCCEEDED(rv) && !okToUnload) {
+      if (NS_SUCCEEDED(cv->PermitUnload(PR_FALSE, &okToUnload)) && !okToUnload) {
         // We don't want to unload, so stop here, but don't throw an
         // exception.
         return NS_OK;
       }
     }
 
     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell));
     webnav->Stop(nsIWebNavigation::STOP_NETWORK);
@@ -1634,17 +1649,17 @@ nsHTMLDocument::OpenCommon(JSContext* cx
     EnsureOnloadBlocker();
   }
 
   // The open occurred after the document finished loading.
   // So we reset the document and create a new one.
   nsCOMPtr<nsIChannel> channel;
   nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
 
-  rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, group);
+  nsresult rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, group);
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // We can't depend on channels implementing property bags, so do our
   // base URI manually after reset.
 
@@ -1695,25 +1710,26 @@ nsHTMLDocument::OpenCommon(JSContext* cx
   if (baseURI) {
     mDocumentBaseURI = baseURI;
   }
 
   // Store the security info of the caller now that we're done
   // resetting the document.
   mSecurityInfo = securityInfo;
 
+  PRBool loadAsHtml5 = nsHtml5Module::sEnabled;
   if (loadAsHtml5) {
     mParser = nsHtml5Module::NewHtml5Parser();
     rv = NS_OK;
   } else {
     mParser = do_CreateInstance(kCParserCID, &rv);  
   }
 
   // This will be propagated to the parser when someone actually calls write()
-  SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType));
+  SetContentTypeInternal(contentType);
 
   mWriteState = eDocumentOpened;
 
   if (NS_SUCCEEDED(rv)) {
     if (loadAsHtml5) {
       nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
     } else {
       nsCOMPtr<nsIHTMLContent