Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Tue, 03 Apr 2012 17:54:29 -0700
changeset 112381 ec53c5d4c3dd2d794c2b7a64b2377c7bd4558dbf
parent 112380 7b2c14a9fde2fed11d8834889753f224b5959e7a (current diff)
parent 94220 25ec8b71e8ce98d1434b361a55faa3fa827d8de5 (diff)
child 112382 4a9f1b21e58c21aa04644b46655fa87876373674
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.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 from mozilla-central.
accessible/src/base/AccEvent.cpp
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/base/nsApplicationAccessible.cpp
accessible/src/base/nsApplicationAccessible.h
accessible/src/base/nsRootAccessible.cpp
accessible/src/base/nsTextEquivUtils.cpp
accessible/src/mac/mozTextAccessible.mm
accessible/src/mac/nsAccessibleWrap.h
accessible/src/mac/nsAccessibleWrap.mm
accessible/src/msaa/CAccessibleAction.cpp
accessible/src/msaa/CAccessibleAction.h
accessible/src/xul/nsXULTreeAccessible.cpp
accessible/src/xul/nsXULTreeAccessible.h
browser/base/content/nsContextMenu.js
browser/components/shell/src/nsGNOMEShellService.cpp
browser/components/shell/src/nsMacShellService.cpp
browser/components/shell/src/nsWindowsShellService.cpp
caps/src/nsScriptSecurityManager.cpp
content/base/public/nsContentUtils.h
content/base/public/nsIDocument.h
content/base/public/nsIMutationObserver2.h
content/base/public/nsINode.h
content/base/src/Makefile.in
content/base/src/nsCCUncollectableMarker.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsCopySupport.cpp
content/base/src/nsDOMAttribute.cpp
content/base/src/nsDOMAttribute.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsDocumentEncoder.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/base/src/nsGkAtomList.h
content/base/src/nsHTMLContentSerializer.cpp
content/base/src/nsNodeIterator.cpp
content/base/src/nsNodeIterator.h
content/base/src/nsNodeUtils.cpp
content/base/src/nsNodeUtils.h
content/base/src/nsRange.cpp
content/base/src/nsScriptLoader.cpp
content/base/src/nsTextNode.cpp
content/base/src/nsTextNode.h
content/base/src/nsTreeWalker.cpp
content/base/src/nsXMLHttpRequest.cpp
content/base/src/nsXMLHttpRequest.h
content/base/test/Makefile.in
content/base/test/test_bug431701.html
content/base/test/test_bug590771.html
content/base/test/test_bug598877.html
content/base/test/test_bug600466.html
content/base/test/test_bug600468.html
content/base/test/test_bug600471.html
content/canvas/src/WebGLContextValidate.cpp
content/events/src/nsDOMEventTargetHelper.h
content/events/src/nsEventListenerManager.cpp
content/html/content/public/nsHTMLMediaElement.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/document/src/nsHTMLDocument.cpp
content/media/nsMediaCache.cpp
content/xbl/src/nsXBLDocumentInfo.cpp
content/xbl/src/nsXBLProtoImplField.cpp
content/xml/document/src/nsXMLDocument.cpp
content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/document/src/nsXULCommandDispatcher.cpp
content/xul/document/src/nsXULContentSink.cpp
content/xul/document/src/nsXULDocument.cpp
content/xul/document/src/nsXULPrototypeDocument.cpp
docshell/base/nsDocShell.cpp
dom/Makefile.in
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMClassInfoClasses.h
dom/base/nsDOMScriptObjectFactory.cpp
dom/base/nsDOMScriptObjectHolder.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsDOMWindowUtils.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIScriptContext.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
dom/base/nsJSTimeoutHandler.cpp
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsScriptNameSpaceManager.h
dom/base/nsWrapperCache.h
dom/interfaces/core/Makefile.in
dom/interfaces/events/nsIDOMEventTarget.idl
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPlugin.h
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginHost.cpp
dom/src/events/nsJSEventListener.cpp
dom/src/geolocation/nsGeolocation.cpp
dom/tests/mochitest/dom-level1-core/exclusions.js
dom/wifi/libcutils.js
dom/wifi/network_worker.js
dom/workers/Exceptions.cpp
dom/workers/ListenerManager.cpp
dom/workers/ListenerManager.h
dom/workers/RuntimeService.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerScope.cpp
dom/workers/XMLHttpRequest.cpp
dom/workers/XMLHttpRequestPrivate.cpp
dom/workers/XMLHttpRequestPrivate.h
embedding/android/GeckoAppShell.java
gfx/layers/basic/BasicLayers.cpp
gfx/thebes/gfxASurface.cpp
gfx/thebes/gfxContext.h
gfx/thebes/gfxFT2Fonts.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFontconfigUtils.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxOS2Fonts.cpp
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxUniscribeShaper.cpp
image/src/RasterImage.cpp
js/src/frontend/Parser.cpp
js/src/gc/Statistics.h
js/src/ion/IonFrames.h
js/src/jsanalyze.cpp
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdbgapi.cpp
js/src/jsfriendapi.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsgcmark.cpp
js/src/jsgcmark.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsutil.h
js/src/jsweakmap.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/vm/Debugger.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCMaps.cpp
js/xpconnect/src/XPCMaps.h
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCThreadContext.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/dom_quickstubs.qsconf
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
layout/base/FramePropertyTable.cpp
layout/base/nsDocumentViewer.cpp
layout/base/nsPresContext.cpp
layout/base/nsRefreshDriver.cpp
layout/build/nsLayoutModule.cpp
layout/build/nsLayoutStatics.cpp
layout/generic/nsFrame.cpp
layout/generic/nsTextRunTransformations.cpp
layout/inspector/src/inDOMUtils.cpp
layout/mathml/nsMathMLChar.cpp
layout/svg/base/src/nsSVGLeafFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableFrame.cpp
layout/tables/nsTableOuterFrame.cpp
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
memory/jemalloc/jemalloc.c
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoConnectivityReceiver.java
mobile/android/base/Makefile.in
mobile/android/base/gfx/GLThread.java
mobile/android/base/gfx/PlaceholderLayerClient.java
modules/libpref/src/init/all.js
netwerk/cache/nsDiskCacheDeviceSQL.cpp
netwerk/cache/nsDiskCacheDeviceSQL.h
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpPipeline.cpp
parser/html/nsHtml5Module.cpp
parser/html/nsHtml5Module.h
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
security/manager/ssl/src/nsNSSComponent.cpp
testing/mochitest/specialpowers/content/specialpowers.js
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/places/AsyncFaviconHelpers.cpp
toolkit/components/places/nsNavBookmarks.cpp
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
toolkit/xre/nsAppRunner.cpp
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
uriloader/prefetch/nsOfflineCacheUpdateService.cpp
view/src/nsView.cpp
widget/android/AndroidBridge.cpp
widget/xpwidgets/GfxInfoX11.cpp
widget/xpwidgets/GfxInfoX11.h
widget/xpwidgets/nsBaseWidget.cpp
xpcom/build/nsXULAppAPI.h
xpcom/ds/nsExpirationTracker.h
xpcom/glue/nsStringAPI.h
xpcom/string/src/nsSubstring.cpp
--- a/Makefile.in
+++ b/Makefile.in
@@ -75,16 +75,17 @@ endif
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 tier_base_dirs += \
   other-licenses/android \
   $(NULL)
 endif
 
 ifdef MOZ_MEMORY
 tier_base_dirs += memory/jemalloc
+tier_base_dirs += memory/build
 endif
 tier_base_dirs += \
   mozglue \
   memory/mozalloc \
   $(NULL)
 endif
 
 ifdef COMPILE_ENVIRONMENT
--- a/accessible/public/nsIAccessible.idl
+++ b/accessible/public/nsIAccessible.idl
@@ -54,17 +54,17 @@ interface nsIAccessibleRelation;
  * accessibility APIs like MSAA and ATK. Contains the sum of what's needed
  * to support IAccessible as well as ATK's generic accessibility objects.
  * Can also be used by in-process accessibility clients to get information
  * about objects in the accessible tree. The accessible tree is a subset of 
  * nodes in the DOM tree -- such as documents, focusable elements and text.
  * Mozilla creates the implementations of nsIAccessible on demand.
  * See http://www.mozilla.org/projects/ui/accessibility for more information.
  */
-[scriptable, uuid(e7c44e0d-736e-4ead-afee-b51f4b574020)]
+[scriptable, uuid(46d422d1-c92f-4536-bdef-f77bc8350ec7)]
 interface nsIAccessible : nsISupports
 {
   /**
    * Parent node in accessible tree.
    */
   readonly attribute nsIAccessible parent;
 
   /**
@@ -99,23 +99,16 @@ interface nsIAccessible : nsISupports
 
   /**
    * The 0-based index of this accessible in its parent's list of children,
    * or -1 if this accessible does not have a parent.
    */
   readonly attribute long indexInParent;
 
   /**
-   * The innerHTML for the HTML element associated with this accessible if applicable.
-   * This is a text string of all the markup inside the DOM
-   * node, not including the start and end tag for the node.
-   */
-  readonly attribute DOMString innerHTML;
-
-  /**
    * The DOM node this nsIAccessible is associated with.
    */
   readonly attribute nsIDOMNode DOMNode;
 
   /**
    * The document accessible that this access node resides in.
    */
   readonly attribute nsIAccessibleDocument document;
--- a/accessible/src/atk/nsRootAccessibleWrap.cpp
+++ b/accessible/src/atk/nsRootAccessibleWrap.cpp
@@ -39,17 +39,21 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsMai.h"
 #include "nsRootAccessibleWrap.h"
 
 nsNativeRootAccessibleWrap::nsNativeRootAccessibleWrap(AtkObject *aAccessible):
     nsRootAccessible(nsnull, nsnull, nsnull)
 {
-    g_object_ref(aAccessible);
-    mAtkObject = aAccessible;
+  // XXX: mark the object as defunct to ensure no single internal method is
+  // running on it.
+  mFlags |= eIsDefunct;
+
+  g_object_ref(aAccessible);
+  mAtkObject = aAccessible;
 }
 
 nsNativeRootAccessibleWrap::~nsNativeRootAccessibleWrap()
 {
     g_object_unref(mAtkObject);
     mAtkObject = nsnull;
 }
--- a/accessible/src/base/AccEvent.cpp
+++ b/accessible/src/base/AccEvent.cpp
@@ -96,17 +96,20 @@ AccEvent::GetNode()
     mNode = mAccessible->GetNode();
 
   return mNode;
 }
 
 nsDocAccessible*
 AccEvent::GetDocAccessible()
 {
-  nsINode *node = GetNode();
+  if (mAccessible)
+    return mAccessible->Document();
+
+  nsINode* node = GetNode();
   if (node)
     return GetAccService()->GetDocAccessible(node->OwnerDoc());
 
   return nsnull;
 }
 
 already_AddRefed<nsAccEvent>
 AccEvent::CreateXPCOMObject()
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -592,16 +592,32 @@ nsAccessibilityService::UpdateText(nsIPr
                                    nsIContent* aContent)
 {
   nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
   if (document)
     document->UpdateText(aContent);
 }
 
 void
+nsAccessibilityService::TreeViewChanged(nsIPresShell* aPresShell,
+                                        nsIContent* aContent,
+                                        nsITreeView* aView)
+{
+  nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
+  if (document) {
+    nsAccessible* accessible = document->GetAccessible(aContent);
+    if (accessible) {
+      nsXULTreeAccessible* treeAcc = accessible->AsXULTree();
+      if (treeAcc) 
+        treeAcc->TreeViewChanged(aView);
+    }
+  }
+}
+
+void
 nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell,
                                          nsIContent* aHTMLListItemContent,
                                          bool aHasBullet)
 {
   nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
   if (document) {
     nsAccessible* accessible = document->GetAccessible(aHTMLListItemContent);
     if (accessible) {
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -44,16 +44,17 @@
 #include "a11yGeneric.h"
 #include "nsAccDocManager.h"
 
 #include "mozilla/a11y/FocusManager.h"
 
 #include "nsIObserver.h"
 
 class nsImageFrame;
+class nsITreeView;
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * Return focus manager.
  */
 FocusManager* FocusMgr();
@@ -148,16 +149,22 @@ public:
                                     nsIContent* aEndChild);
 
   virtual void ContentRemoved(nsIPresShell* aPresShell, nsIContent* aContainer,
                               nsIContent* aChild);
 
   virtual void UpdateText(nsIPresShell* aPresShell, nsIContent* aContent);
 
   /**
+   * Update XUL:tree accessible tree when treeview is changed.
+   */
+  void TreeViewChanged(nsIPresShell* aPresShell, nsIContent* aContent,
+                       nsITreeView* aView);
+
+  /**
    * Update list bullet accessible.
    */
   virtual void UpdateListBullet(nsIPresShell* aPresShell,
                                 nsIContent* aHTMLListItemContent,
                                 bool aHasBullet);
 
   /**
    * Update the image map.
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -259,27 +259,16 @@ nsAccessible::GetRootDocument(nsIAccessi
   NS_ENSURE_ARG_POINTER(aRootDocument);
 
   nsRootAccessible* rootDocument = RootAccessible();
   NS_IF_ADDREF(*aRootDocument = rootDocument);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsAccessible::GetInnerHTML(nsAString& aInnerHTML)
-{
-  aInnerHTML.Truncate();
-
-  nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(mContent);
-  NS_ENSURE_TRUE(htmlElement, NS_ERROR_NULL_POINTER);
-
-  return htmlElement->GetInnerHTML(aInnerHTML);
-}
-
-NS_IMETHODIMP
 nsAccessible::GetLanguage(nsAString& aLanguage)
 {
   Language(aLanguage);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetName(nsAString& aName)
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -67,16 +67,17 @@ class nsHTMLLIAccessible;
 struct nsRoleMapEntry;
 class Relation;
 namespace mozilla {
 namespace a11y {
 class TableAccessible;
 }
 }
 class nsTextAccessible;
+class nsXULTreeAccessible;
 
 struct nsRect;
 class nsIContent;
 class nsIFrame;
 class nsIAtom;
 class nsIView;
 
 typedef nsRefPtrHashtable<nsPtrHashKey<const void>, nsAccessible>
@@ -462,16 +463,19 @@ public:
   nsHTMLLIAccessible* AsHTMLListItem();
 
   inline bool IsImageAccessible() const { return mFlags & eImageAccessible; }
   nsHTMLImageAccessible* AsImage();
 
   bool IsImageMapAccessible() const { return mFlags & eImageMapAccessible; }
   nsHTMLImageMapAccessible* AsImageMap();
 
+  inline bool IsXULTree() const { return mFlags & eXULTreeAccessible; }
+  nsXULTreeAccessible* AsXULTree();
+
   inline bool IsListControl() const { return mFlags & eListControlAccessible; }
 
   inline bool IsMenuButton() const { return mFlags & eMenuButtonAccessible; }
 
   inline bool IsMenuPopup() const { return mFlags & eMenuPopupAccessible; }
 
   inline bool IsRoot() const { return mFlags & eRootAccessible; }
   nsRootAccessible* AsRoot();
@@ -713,17 +717,18 @@ protected:
     eHTMLFileInputAccessible = 1 << 9,
     eHTMLListItemAccessible = 1 << 10,
     eImageAccessible = 1 << 11,
     eImageMapAccessible = 1 << 12,
     eListControlAccessible = 1 << 13,
     eMenuButtonAccessible = 1 << 14,
     eMenuPopupAccessible = 1 << 15,
     eRootAccessible = 1 << 16,
-    eTextLeafAccessible = 1 << 17
+    eTextLeafAccessible = 1 << 17,
+    eXULTreeAccessible = 1 << 18
   };
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous helpers
 
   /**
    * Return ARIA role (helper method).
    */
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -437,23 +437,16 @@ NS_IMETHODIMP
 nsApplicationAccessible::GetRootDocument(nsIAccessibleDocument **aRootDocument)
 {
   NS_ENSURE_ARG_POINTER(aRootDocument);
   *aRootDocument = nsnull;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsApplicationAccessible::GetInnerHTML(nsAString &aInnerHTML)
-{
-  aInnerHTML.Truncate();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsApplicationAccessible::ScrollTo(PRUint32 aScrollType)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsApplicationAccessible::ScrollToPoint(PRUint32 aCoordinateType,
                                        PRInt32 aX, PRInt32 aY)
--- a/accessible/src/base/nsApplicationAccessible.h
+++ b/accessible/src/base/nsApplicationAccessible.h
@@ -68,17 +68,16 @@ public:
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessible
   NS_SCRIPTABLE NS_IMETHOD GetDOMNode(nsIDOMNode** aDOMNode);
   NS_SCRIPTABLE NS_IMETHOD GetDocument(nsIAccessibleDocument** aDocument);
   NS_SCRIPTABLE NS_IMETHOD GetRootDocument(nsIAccessibleDocument** aRootDocument);
-  NS_SCRIPTABLE NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
   NS_SCRIPTABLE NS_IMETHOD ScrollTo(PRUint32 aScrollType);
   NS_SCRIPTABLE NS_IMETHOD ScrollToPoint(PRUint32 aCoordinateType, PRInt32 aX, PRInt32 aY);
   NS_SCRIPTABLE NS_IMETHOD GetLanguage(nsAString& aLanguage);
   NS_IMETHOD GetParent(nsIAccessible **aParent);
   NS_IMETHOD GetNextSibling(nsIAccessible **aNextSibling);
   NS_IMETHOD GetPreviousSibling(nsIAccessible **aPreviousSibling);
   NS_IMETHOD GetName(nsAString &aName);
   NS_IMETHOD GetValue(nsAString &aValue);
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -224,18 +224,16 @@ const char* const docEvents[] = {
   "mouseover",
 #endif
   // capture Form change events 
   "select",
   // capture ValueChange events (fired whenever value changes, immediately after, whether focus moves or not)
   "ValueChange",
   // capture AlertActive events (fired whenever alert pops up)
   "AlertActive",
-  // add ourself as a TreeViewChanged listener (custom event fired in nsTreeBodyFrame.cpp)
-  "TreeViewChanged",
   "TreeRowCountChanged",
   "TreeInvalidated",
   // add ourself as a OpenStateChange listener (custom event fired in tree.xml)
   "OpenStateChange",
   // add ourself as a CheckboxStateChange listener (custom event fired in nsHTMLInputElement.cpp)
   "CheckboxStateChange",
   // add ourself as a RadioStateChange Listener ( custom event fired in in nsHTMLInputElement.cpp  & radio.xml)
   "RadioStateChange",
@@ -383,36 +381,26 @@ nsRootAccessible::ProcessDOMEvent(nsIDOM
   nsAccessible* accessible = 
     targetDocument->GetAccessibleOrContainer(origTargetNode);
   if (!accessible)
     return;
 
   nsINode* targetNode = accessible->GetNode();
 
 #ifdef MOZ_XUL
-  nsRefPtr<nsXULTreeAccessible> treeAcc;
-  if (targetNode->IsElement() &&
-      targetNode->AsElement()->NodeInfo()->Equals(nsGkAtoms::tree,
-                                                  kNameSpaceID_XUL)) {
-    treeAcc = do_QueryObject(accessible);
-    if (treeAcc) {
-      if (eventType.EqualsLiteral("TreeViewChanged")) {
-        treeAcc->TreeViewChanged();
-        return;
-      }
+  nsXULTreeAccessible* treeAcc = accessible->AsXULTree();
+  if (treeAcc) {
+    if (eventType.EqualsLiteral("TreeRowCountChanged")) {
+      HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
+      return;
+    }
 
-      if (eventType.EqualsLiteral("TreeRowCountChanged")) {
-        HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
-        return;
-      }
-
-      if (eventType.EqualsLiteral("TreeInvalidated")) {
-        HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
-        return;
-      }
+    if (eventType.EqualsLiteral("TreeInvalidated")) {
+      HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
+      return;
     }
   }
 #endif
 
   if (eventType.EqualsLiteral("RadioStateChange")) {
     PRUint64 state = accessible->State();
 
     // radiogroup in prefWindow is exposed as a list,
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -113,35 +113,28 @@ nsTextEquivUtils::AppendTextEquivFromCon
                                              nsAString *aString)
 {
   // Prevent recursion which can cause infinite loops.
   if (gInitiatorAcc)
     return NS_OK;
 
   gInitiatorAcc = aInitiatorAcc;
 
-  nsIPresShell* shell = nsCoreUtils::GetPresShellFor(aContent);
-  if (!shell) {
-    NS_ASSERTION(true, "There is no presshell!");
-    gInitiatorAcc = nsnull;
-    return NS_ERROR_UNEXPECTED;
-  }
-
   // If the given content is not visible or isn't accessible then go down
   // through the DOM subtree otherwise go down through accessible subtree and
   // calculate the flat string.
   nsIFrame *frame = aContent->GetPrimaryFrame();
   bool isVisible = frame && frame->GetStyleVisibility()->IsVisible();
 
   nsresult rv = NS_ERROR_FAILURE;
   bool goThroughDOMSubtree = true;
 
   if (isVisible) {
     nsAccessible* accessible =
-      GetAccService()->GetAccessible(aContent, shell);
+      gInitiatorAcc->Document()->GetAccessible(aContent);
     if (accessible) {
       rv = AppendFromAccessible(accessible, aString);
       goThroughDOMSubtree = false;
     }
   }
 
   if (goThroughDOMSubtree)
     rv = AppendFromDOMNode(aContent, aString);
--- a/accessible/src/mac/mozAccessible.h
+++ b/accessible/src/mac/mozAccessible.h
@@ -131,16 +131,17 @@ GetObjectOrRepresentedView(id <mozAccess
 - (BOOL)canBeFocused;
 
 // returns NO if for some reason we were unable to focus the element.
 - (BOOL)focus;
 
 // notifications sent out to listening accessible providers.
 - (void)didReceiveFocus;
 - (void)valueDidChange;
+- (void)selectedTextDidChange;
 
 #pragma mark -
 
 // invalidates and removes all our children from our cached array.
 - (void)invalidateChildren;
 
 /** 
  * Append a child if they are already cached.
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -352,17 +352,17 @@ GetNativeFromGeckoAccessible(nsIAccessib
 
 - (id <mozAccessible>)parent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   if (mParent)
     return mParent;
 
-  nsCOMPtr<nsIAccessible> accessibleParent(mGeckoAccessible->GetUnignoredParent());
+  nsAccessible* accessibleParent = mGeckoAccessible->GetUnignoredParent();
   if (accessibleParent) {
     id nativeParent = GetNativeFromGeckoAccessible(accessibleParent);
     if (nativeParent)
       return mParent = GetClosestInterestingAccessible(nativeParent);
   }
   
   // GetUnignoredParent() returns null when there is no unignored accessible all the way up to
   // the root accessible. so we'll have to return whatever native accessible is above our root accessible 
@@ -398,27 +398,25 @@ GetNativeFromGeckoAccessible(nsIAccessib
 - (NSArray*)children
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   if (mChildren || !mGeckoAccessible->AreChildrenCached())
     return mChildren;
 
   mChildren = [[NSMutableArray alloc] init];
-  
+
   // get the array of children.
-  nsTArray<nsRefPtr<nsAccessibleWrap> > childrenArray;
-  mGeckoAccessible->GetUnignoredChildren(childrenArray);
-  
+  nsAutoTArray<nsAccessible*, 10> childrenArray;
+  mGeckoAccessible->GetUnignoredChildren(&childrenArray);
+
   // now iterate through the children array, and get each native accessible.
-  int totalCount = childrenArray.Length();
-  int index = 0;
-   
-  for (; index < totalCount; index++) {
-    nsAccessibleWrap *curAccessible = childrenArray.ElementAt(index);
+  PRUint32 totalCount = childrenArray.Length();
+  for (PRUint32 idx = 0; idx < totalCount; idx++) {
+    nsAccessible* curAccessible = childrenArray.ElementAt(idx);
     if (curAccessible) {
       mozAccessible *curNative = GetNativeFromGeckoAccessible(curAccessible);
       if (curNative)
         [mChildren addObject:GetObjectOrRepresentedView(curNative)];
     }
   }
   
 #ifdef DEBUG_hakan
@@ -513,16 +511,21 @@ GetNativeFromGeckoAccessible(nsIAccessib
   NSLog(@"%@'s value changed!", self);
 #endif
   // sending out a notification is expensive, so we don't do it other than for really important objects,
   // like mozTextAccessible.
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+- (void)selectedTextDidChange
+{
+  // Do nothing. mozTextAccessible will.
+}
+
 - (NSString*)customDescription
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   if (mGeckoAccessible->IsDefunct())
     return nil;
 
   nsAutoString desc;
--- a/accessible/src/mac/mozTextAccessible.mm
+++ b/accessible/src/mac/mozTextAccessible.mm
@@ -4,24 +4,51 @@
 
 #include "nsCocoaUtils.h"
 #include "nsObjCExceptions.h"
 
 #import "mozTextAccessible.h"
 
 using namespace mozilla::a11y;
 
-@interface mozTextAccessible (Private)
+inline bool
+ToNSRange(id aValue, NSRange* aRange)
+{
+  NS_PRECONDITION(aRange, "aRange is nil");
+
+  if ([aValue isKindOfClass:[NSValue class]] && 
+      strcmp([(NSValue*)aValue objCType], @encode(NSRange)) == 0) {
+    *aRange = [aValue rangeValue];
+    return true;
+  }
+
+  return false;
+}
+
+inline NSString*
+ToNSString(id aValue)
+{
+  if ([aValue isKindOfClass:[NSString class]]) {
+    return aValue;
+  }
+
+  return nil;
+}
+
+@interface mozTextAccessible ()
 - (NSString*)subrole;
 - (NSString*)selectedText;
 - (NSValue*)selectedTextRange;
+- (NSValue*)visibleCharacterRange;
 - (long)textLength;
 - (BOOL)isReadOnly;
+- (NSNumber*)caretLineNumber;
 - (void)setText:(NSString*)newText;
 - (NSString*)text;
+- (NSString*)stringFromRange:(NSRange*)range;
 @end
 
 @implementation mozTextAccessible
 
 - (id)initWithAccessible:(nsAccessibleWrap*)accessible
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
@@ -38,91 +65,230 @@ using namespace mozilla::a11y;
 {
   return mIsExpired;
 }
 
 - (NSArray*)accessibilityAttributeNames
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
-  static NSArray *supportedAttributes = nil;
+  static NSMutableArray* supportedAttributes = nil;
   if (!supportedAttributes) {
-    // standard attributes that are shared and supported by all generic elements.
-    supportedAttributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required
-                                                           NSAccessibilityRoleAttribute,   // required
-                                                           NSAccessibilityTitleAttribute,
-                                                           NSAccessibilityValueAttribute, // required
-                                                           NSAccessibilitySubroleAttribute,
-                                                           NSAccessibilityRoleDescriptionAttribute,
-                                                           NSAccessibilityPositionAttribute, // required
-                                                           NSAccessibilitySizeAttribute, // required
-                                                           NSAccessibilityWindowAttribute, // required
-                                                           NSAccessibilityFocusedAttribute, // required
-                                                           NSAccessibilityEnabledAttribute, // required
-                                                           NSAccessibilityTopLevelUIElementAttribute, // required
-                                                           NSAccessibilityDescriptionAttribute, // required
-                                                           /* text-specific attributes */
-                                                           NSAccessibilitySelectedTextAttribute, // required
-                                                           NSAccessibilitySelectedTextRangeAttribute, // required
-                                                           NSAccessibilityNumberOfCharactersAttribute, // required
-                                                           // TODO: NSAccessibilityVisibleCharacterRangeAttribute, // required
-                                                           // TODO: NSAccessibilityInsertionPointLineNumberAttribute
-#if DEBUG
-                                                           @"AXMozDescription",
-#endif
-                                                           nil];
+    // text-specific attributes to supplement the standard one
+    supportedAttributes = [[NSMutableArray alloc] initWithObjects:
+      NSAccessibilitySelectedTextAttribute, // required
+      NSAccessibilitySelectedTextRangeAttribute, // required
+      NSAccessibilityNumberOfCharactersAttribute, // required
+      NSAccessibilityVisibleCharacterRangeAttribute, // required
+      NSAccessibilityInsertionPointLineNumberAttribute,
+      nil
+    ];
+    [supportedAttributes addObjectsFromArray:[super accessibilityAttributeNames]];
   }
   return supportedAttributes;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (id)accessibilityAttributeValue:(NSString*)attribute
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   if ([attribute isEqualToString:NSAccessibilityNumberOfCharactersAttribute])
     return [NSNumber numberWithInt:[self textLength]];
+
+  if ([attribute isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute])
+    return [self caretLineNumber];
+
   if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute])
     return [self selectedTextRange];
+
   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute])
     return [self selectedText];
-  // Apple's SpeechSynthesisServer expects AXValue to return an AXStaticText
-  // object's AXSelectedText attribute.  See bug 674612.
-  // Also if there is no selected text, we return the full text.See bug 369710
-  if ([attribute isEqualToString:NSAccessibilityValueAttribute])
-    return [self selectedText] ? : [self text];
+
+  if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+    // Apple's SpeechSynthesisServer expects AXValue to return an AXStaticText
+    // object's AXSelectedText attribute. See bug 674612 for details.
+    // Also if there is no selected text, we return the full text. 
+    // See bug 369710 for details.
+    if ([[self role] isEqualToString:NSAccessibilityStaticTextRole])
+      return [self selectedText] ? : [self text];
+
+    return [self text];
+  }
+
+  if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute])
+    return [self visibleCharacterRange];
 
   // let mozAccessible handle all other attributes
   return [super accessibilityAttributeValue:attribute];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
+- (NSArray*)accessibilityParameterizedAttributeNames
+{
+  static NSArray* supportedParametrizedAttributes = nil;
+  // text specific parametrized attributes
+  if (!supportedParametrizedAttributes) {
+    supportedParametrizedAttributes = [[NSArray alloc] initWithObjects:
+      NSAccessibilityStringForRangeParameterizedAttribute,
+      NSAccessibilityLineForIndexParameterizedAttribute,
+      NSAccessibilityRangeForLineParameterizedAttribute,
+      NSAccessibilityAttributedStringForRangeParameterizedAttribute,
+      NSAccessibilityBoundsForRangeParameterizedAttribute,
+#if DEBUG
+      NSAccessibilityRangeForPositionParameterizedAttribute,
+      NSAccessibilityRangeForIndexParameterizedAttribute,
+      NSAccessibilityRTFForRangeParameterizedAttribute,
+      NSAccessibilityStyleRangeForIndexParameterizedAttribute,
+#endif
+      nil
+    ];
+  }
+  return supportedParametrizedAttributes;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
+{
+  if (!mGeckoTextAccessible)
+    return nil;
+
+  if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
+    NSRange range;
+    if (!ToNSRange(parameter, &range)) {
+#if DEBUG
+      NSLog(@"%@: range not set", attribute);
+#endif
+      return @"";
+    }
+
+    return [self stringFromRange:&range];
+  }
+
+  if ([attribute isEqualToString:NSAccessibilityRangeForLineParameterizedAttribute]) {
+    // XXX: actually get the integer value for the line #
+    return [NSValue valueWithRange:NSMakeRange(0, [self textLength])];
+  }
+
+  if ([attribute isEqualToString:NSAccessibilityAttributedStringForRangeParameterizedAttribute]) {
+    NSRange range;
+    if (!ToNSRange(parameter, &range)) {
+#if DEBUG
+      NSLog(@"%@: range not set", attribute);
+#endif
+      return @"";
+    }
+
+    return [[[NSAttributedString alloc] initWithString:[self stringFromRange:&range]] autorelease];
+  }
+
+  if ([attribute isEqualToString:NSAccessibilityLineForIndexParameterizedAttribute]) {
+    // XXX: actually return the line #
+    return [NSNumber numberWithInt:0];
+  }
+
+  if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
+    NSRange range;
+    if (!ToNSRange(parameter, &range)) {
+#if DEBUG
+      NSLog(@"%@:no range", attribute);
+#endif
+      return nil;
+    }
+    
+    PRInt32 start = range.location;
+    PRInt32 end = start + range.length;
+    nsIntRect bounds = mGeckoTextAccessible->GetTextBounds(start, end);
+
+    return [NSValue valueWithRect:nsCocoaUtils::GeckoRectToCocoaRect(bounds)];
+  }
+
+#if DEBUG
+  NSLog(@"unhandled attribute:%@ forParameter:%@", attribute, parameter);
+#endif
+
+  return nil;
+}
+
 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   if ([attribute isEqualToString:NSAccessibilityValueAttribute])
     return [self isReadOnly];
   
+  if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute] ||
+      [attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute] ||
+      [attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute])
+    return YES;
+
   return [super accessibilityIsAttributeSettable:attribute];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
 - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
+  if (!mGeckoTextAccessible)
+    return;
+
   if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
-    if ([value isKindOfClass:[NSString class]])
-      [self setText:(NSString*)value];
-  } else
-    [super accessibilitySetValue:value forAttribute:attribute];
+    [self setText:ToNSString(value)];
+    
+    return;
+  }
+
+  if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
+    NSString* stringValue = ToNSString(value);
+    if (!stringValue)
+      return;
+
+    PRInt32 start = 0;
+    PRInt32 end = 0;
+
+    nsresult rv = mGeckoTextAccessible->GetSelectionBounds(0, &start, &end);
+    NS_ENSURE_SUCCESS(rv,);
+    
+    rv = mGeckoTextAccessible->DeleteText(start, end - start);
+    NS_ENSURE_SUCCESS(rv,);
+
+    nsString text;
+    nsCocoaUtils::GetStringForNSString(stringValue, text);
+    rv = mGeckoTextAccessible->InsertText(text, start);
+    NS_ENSURE_SUCCESS(rv,);
+
+    return;
+  }
+
+  if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
+    NSRange range;
+    if (!ToNSRange(value, &range))
+      return;
+
+    nsresult rv = mGeckoTextAccessible->SetSelectionBounds(0, range.location, 
+                                                           range.location + range.length);
+    NS_ENSURE_SUCCESS(rv,);
+
+    return;
+  }
+
+  if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) {
+    NSRange range;
+    if (!ToNSRange(value, &range))
+      return;
+
+    mGeckoTextAccessible->ScrollSubstringTo(range.location, range.location + range.length,
+                                            nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
+    return;
+  } 
+
+  [super accessibilitySetValue:value forAttribute:attribute];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (NSString*)subrole
 {
   // TODO: text accessibles have two different subroles in Cocoa: secure textfield (passwords) and search field
   return nil;
@@ -151,16 +317,24 @@ using namespace mozilla::a11y;
   if (mGeckoEditableTextAccessible)
     return (mGeckoAccessible->State() & states::READONLY) == 0;
 
   return NO;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
+- (NSNumber*)caretLineNumber
+{
+  PRInt32 lineNumber = mGeckoTextAccessible ?
+    mGeckoTextAccessible->CaretLineNumber() - 1 : -1;
+
+  return (lineNumber >= 0) ? [NSNumber numberWithInt:lineNumber] : nil;
+}
+
 - (void)setText:(NSString*)newString
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (mGeckoEditableTextAccessible) {
     mGeckoEditableTextAccessible->SetTextContents(NS_ConvertUTF8toUTF16([newString UTF8String]));
   }
 
@@ -192,17 +366,19 @@ using namespace mozilla::a11y;
 
 - (long)selectedTextLength
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   if (mGeckoTextAccessible) {
     PRInt32 start, end;
     start = end = 0;
-    mGeckoTextAccessible->GetSelectionBounds(0, &start, &end);
+    nsresult rv = mGeckoTextAccessible->GetSelectionBounds(0, &start, &end);
+    NS_ENSURE_SUCCESS(rv, 0);
+
     return (end - start);
   }
   return 0;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
 }
 
 - (NSString*)selectedText
@@ -224,31 +400,68 @@ using namespace mozilla::a11y;
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (NSValue*)selectedTextRange
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   if (mGeckoTextAccessible) {
-    PRInt32 start, end;
-    start = end = 0;
-    mGeckoTextAccessible->GetSelectionBounds(0, &start, &end);
-    return [NSValue valueWithRange:NSMakeRange(start, start-end)];
+    PRInt32 start = 0;
+    PRInt32 end = 0;
+    PRInt32 count = 0;
+
+    nsresult rv = mGeckoTextAccessible->GetSelectionCount(&count);
+    NS_ENSURE_SUCCESS(rv, nil);
+
+    if (count) {
+      rv = mGeckoTextAccessible->GetSelectionBounds(0, &start, &end);
+      NS_ENSURE_SUCCESS(rv, nil);
+
+      return [NSValue valueWithRange:NSMakeRange(start, end - start)];
+    }
+
+    rv = mGeckoTextAccessible->GetCaretOffset(&start);
+    NS_ENSURE_SUCCESS(rv, nil);
+    
+    return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)]; 
   }
-  return nil;
+  return [NSValue valueWithRange:NSMakeRange(0, 0)];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
-#pragma mark -
+- (NSValue*)visibleCharacterRange
+{
+  // XXX this won't work with Textarea and such as we actually don't give
+  // the visible character range.
+  return [NSValue valueWithRange:
+    NSMakeRange(0, mGeckoTextAccessible ? 
+                mGeckoTextAccessible->CharacterCount() : 0)];
+}
 
 - (void)valueDidChange
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   NSAccessibilityPostNotification(GetObjectOrRepresentedView(self),
                                   NSAccessibilityValueChangedNotification);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+- (void)selectedTextDidChange
+{
+  NSAccessibilityPostNotification(GetObjectOrRepresentedView(self),
+                                  NSAccessibilitySelectedTextChangedNotification);
+}
+
+- (NSString*)stringFromRange:(NSRange*)range
+{
+  NS_PRECONDITION(mGeckoTextAccessible && range, "no Gecko text accessible or range");
+
+  nsAutoString text;
+  mGeckoTextAccessible->GetText(range->location, 
+                                range->location + range->length, text);
+  return nsCocoaUtils::ToNSString(text);
+}
+
 @end
--- a/accessible/src/mac/nsAccessibleWrap.h
+++ b/accessible/src/mac/nsAccessibleWrap.h
@@ -94,18 +94,18 @@ public: // construction, destruction
   
   inline bool HasPopup () 
     { return (NativeState() & mozilla::a11y::states::HASPOPUP); }
   
   /**
    * Returns this accessible's all children, adhering to "flat" accessibles by 
    * not returning their children.
    */
-  void GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> >& aChildrenArray);
-  virtual already_AddRefed<nsIAccessible> GetUnignoredParent();
+  void GetUnignoredChildren(nsTArray<nsAccessible*>* aChildrenArray);
+  nsAccessible* GetUnignoredParent() const;
     
 protected:
 
   virtual nsresult FirePlatformEvent(AccEvent* aEvent);
 
   /**
    * Return true if the parent doesn't have children to expose to AT.
    */
--- a/accessible/src/mac/nsAccessibleWrap.mm
+++ b/accessible/src/mac/nsAccessibleWrap.mm
@@ -174,19 +174,22 @@ nsAccessibleWrap::HandleAccEvent(AccEven
 
 nsresult
 nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   PRUint32 eventType = aEvent->GetEventType();
 
-  // ignore everything but focus-changed and value-changed events for now.
+  // ignore everything but focus-changed, value-changed, caret and selection
+  // events for now.
   if (eventType != nsIAccessibleEvent::EVENT_FOCUS &&
-      eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE)
+      eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
+      eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
+      eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED)
     return NS_OK;
 
   nsAccessible *accessible = aEvent->GetAccessible();
   NS_ENSURE_STATE(accessible);
 
   mozAccessible *nativeAcc = nil;
   accessible->GetNativeInterface((void**)&nativeAcc);
   if (!nativeAcc)
@@ -194,16 +197,20 @@ nsAccessibleWrap::FirePlatformEvent(AccE
 
   switch (eventType) {
     case nsIAccessibleEvent::EVENT_FOCUS:
       [nativeAcc didReceiveFocus];
       break;
     case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
       [nativeAcc valueDidChange];
       break;
+    case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
+    case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
+      [nativeAcc selectedTextDidChange];
+      break;
   }
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 void
@@ -249,58 +256,46 @@ nsAccessibleWrap::IsIgnored()
   
   mozAccessible* nativeObject = GetNativeObject();
   return (!nativeObject) || [nativeObject accessibilityIsIgnored];
   
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
 }
 
 void
-nsAccessibleWrap::GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> > &aChildrenArray)
+nsAccessibleWrap::GetUnignoredChildren(nsTArray<nsAccessible*>* aChildrenArray)
 {
   // we're flat; there are no children.
   if (nsAccUtils::MustPrune(this))
     return;
 
   PRInt32 childCount = GetChildCount();
   for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
     nsAccessibleWrap *childAcc =
       static_cast<nsAccessibleWrap*>(GetChildAt(childIdx));
 
+    // If element is ignored, then add its children as substitutes.
     if (childAcc->IsIgnored()) {
-      // element is ignored, so try adding its children as substitutes, if it has any.
-      if (!nsAccUtils::MustPrune(childAcc)) {
-        nsTArray<nsRefPtr<nsAccessibleWrap> > children;
-        childAcc->GetUnignoredChildren(children);
-        if (!children.IsEmpty()) {
-          // add the found unignored descendants to the array.
-          aChildrenArray.AppendElements(children);
-        }
-      }
-    } else
-      // simply add the element, since it's not ignored.
-      aChildrenArray.AppendElement(childAcc);
+      childAcc->GetUnignoredChildren(aChildrenArray);
+      continue;
+    }
+
+    aChildrenArray->AppendElement(childAcc);
   }
 }
 
-already_AddRefed<nsIAccessible>
-nsAccessibleWrap::GetUnignoredParent()
+nsAccessible*
+nsAccessibleWrap::GetUnignoredParent() const
 {
+  // Go up the chain to find a parent that is not ignored.
   nsAccessibleWrap* parentWrap = static_cast<nsAccessibleWrap*>(Parent());
-  if (!parentWrap)
-    return nsnull;
+  while (parentWrap && parentWrap->IsIgnored()) 
+    parentWrap = static_cast<nsAccessibleWrap*>(parentWrap->Parent());
     
-  // recursively return the parent, until we find one that is not ignored.
-  if (parentWrap->IsIgnored())
-    return parentWrap->GetUnignoredParent();
-  
-  nsIAccessible *outValue = nsnull;
-  NS_IF_ADDREF(outValue = parentWrap);
-  
-  return outValue;
+  return parentWrap;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibleWrap protected
 
 bool
 nsAccessibleWrap::AncestorIsFlat()
 {
--- a/accessible/src/mac/nsRoleMap.h
+++ b/accessible/src/mac/nsRoleMap.h
@@ -37,136 +37,136 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #import <Cocoa/Cocoa.h>
 
 #include "nsIAccessible.h"
 
 static const NSString* AXRoles [] = {
-  NSAccessibilityUnknownRole,                   // ROLE_NOTHING
-  NSAccessibilityUnknownRole,                   // ROLE_TITLEBAR. (irrelevant on OS X; windows are always native.)
-  NSAccessibilityMenuBarRole,                   // ROLE_MENUBAR. (irrelevant on OS X; the menubar will always be native and on the top of the screen.)
-  NSAccessibilityScrollBarRole,                 // ROLE_SCROLLBAR. we might need to make this its own mozAccessible, to support the children objects (valueindicator, down/up buttons).
-  NSAccessibilitySplitterRole,                  // ROLE_GRIP
-  NSAccessibilityUnknownRole,                   // ROLE_SOUND. unused on OS X
-  NSAccessibilityUnknownRole,                   // ROLE_CURSOR. unused on OS X
-  NSAccessibilityUnknownRole,                   // ROLE_CARET. unused on OS X
-  NSAccessibilityWindowRole,                    // ROLE_ALERT
-  NSAccessibilityWindowRole,                    // ROLE_WINDOW. irrelevant on OS X; all window a11y is handled by the system.
-  NSAccessibilityScrollAreaRole,                // ROLE_INTERNAL_FRAME
-  NSAccessibilityMenuRole,                      // ROLE_MENUPOPUP. the parent of menuitems
-  NSAccessibilityMenuItemRole,                  // ROLE_MENUITEM.
-  @"AXHelpTag",                                 // ROLE_TOOLTIP. 10.4+ only, so we re-define the constant.
-  NSAccessibilityGroupRole,                     // ROLE_APPLICATION. unused on OS X. the system will take care of this.
-  @"AXWebArea",                                 // ROLE_DOCUMENT
-  NSAccessibilityGroupRole,                     // ROLE_PANE
-  NSAccessibilityUnknownRole,                   // ROLE_CHART
-  NSAccessibilityWindowRole,                    // ROLE_DIALOG. there's a dialog subrole.
-  NSAccessibilityUnknownRole,                   // ROLE_BORDER. unused on OS X
-  NSAccessibilityGroupRole,                     // ROLE_GROUPING
-  NSAccessibilityUnknownRole,                   // ROLE_SEPARATOR
-  NSAccessibilityToolbarRole,                   // ROLE_TOOLBAR
-  NSAccessibilityUnknownRole,                   // ROLE_STATUSBAR. doesn't exist on OS X (a status bar is its parts; a progressbar, a label, etc.)
-  NSAccessibilityGroupRole,                     // ROLE_TABLE
-  NSAccessibilityGroupRole,                     // ROLE_COLUMNHEADER
-  NSAccessibilityGroupRole,                     // ROLE_ROWHEADER
-  NSAccessibilityColumnRole,                    // ROLE_COLUMN
-  NSAccessibilityRowRole,                       // ROLE_ROW
-  NSAccessibilityGroupRole,                     // ROLE_CELL
-  @"AXLink",                                    // ROLE_LINK. 10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
-  @"AXHelpTag",                                 // ROLE_HELPBALLOON
-  NSAccessibilityUnknownRole,                   // ROLE_CHARACTER. unused on OS X
-  NSAccessibilityListRole,                      // ROLE_LIST
-  NSAccessibilityRowRole,                       // ROLE_LISTITEM
-  NSAccessibilityOutlineRole,                   // ROLE_OUTLINE
-  NSAccessibilityRowRole,                       // ROLE_OUTLINEITEM. XXX: use OutlineRow as subrole.
-  NSAccessibilityRadioButtonRole,               // ROLE_PAGETAB
-  NSAccessibilityGroupRole,                     // ROLE_PROPERTYPAGE
-  NSAccessibilityUnknownRole,                   // ROLE_INDICATOR
-  NSAccessibilityImageRole,                     // ROLE_GRAPHIC
-  NSAccessibilityStaticTextRole,                // ROLE_STATICTEXT
-  NSAccessibilityStaticTextRole,                // ROLE_TEXT_LEAF
-  NSAccessibilityButtonRole,                    // ROLE_PUSHBUTTON
-  NSAccessibilityCheckBoxRole,                  // ROLE_CHECKBUTTON
-  NSAccessibilityRadioButtonRole,               // ROLE_RADIOBUTTON
-  NSAccessibilityPopUpButtonRole,               // ROLE_COMBOBOX
-  NSAccessibilityPopUpButtonRole,               // ROLE_DROPLIST.
-  NSAccessibilityProgressIndicatorRole,         // ROLE_PROGRESSBAR
-  NSAccessibilityUnknownRole,                   // ROLE_DIAL
-  NSAccessibilityUnknownRole,                   // ROLE_HOTKEYFIELD
-  NSAccessibilitySliderRole,                    // ROLE_SLIDER
-  NSAccessibilityIncrementorRole,               // ROLE_SPINBUTTON. subroles: Increment/Decrement.
-  NSAccessibilityUnknownRole,                   // ROLE_DIAGRAM
-  NSAccessibilityUnknownRole,                   // ROLE_ANIMATION
-  NSAccessibilityUnknownRole,                   // ROLE_EQUATION
-  NSAccessibilityPopUpButtonRole,               // ROLE_BUTTONDROPDOWN.
-  NSAccessibilityMenuButtonRole,                // ROLE_BUTTONMENU
-  NSAccessibilityGroupRole,                     // ROLE_BUTTONDROPDOWNGRID
-  NSAccessibilityUnknownRole,                   // ROLE_WHITESPACE
-  NSAccessibilityTabGroupRole,                  // ROLE_PAGETABLIST
-  NSAccessibilityUnknownRole,                   // ROLE_CLOCK. unused on OS X
-  NSAccessibilityButtonRole,                    // ROLE_SPLITBUTTON
-  NSAccessibilityUnknownRole,                   // ROLE_IPADDRESS
-  NSAccessibilityStaticTextRole,                // ROLE_ACCEL_LABEL
-  NSAccessibilityUnknownRole,                   // ROLE_ARROW
-  NSAccessibilityImageRole,                     // ROLE_CANVAS
-  NSAccessibilityMenuItemRole,                  // ROLE_CHECK_MENU_ITEM
-  NSAccessibilityColorWellRole,                 // ROLE_COLOR_CHOOSER
-  NSAccessibilityUnknownRole,                   // ROLE_DATE_EDITOR
-  NSAccessibilityImageRole,                     // ROLE_DESKTOP_ICON
-  NSAccessibilityUnknownRole,                   // ROLE_DESKTOP_FRAME
-  NSAccessibilityBrowserRole,                   // ROLE_DIRECTORY_PANE
-  NSAccessibilityUnknownRole,                   // ROLE_FILE_CHOOSER. unused on OS X
-  NSAccessibilityUnknownRole,                   // ROLE_FONT_CHOOSER
-  NSAccessibilityUnknownRole,                   // ROLE_CHROME_WINDOW. unused on OS X
-  NSAccessibilityGroupRole,                     // ROLE_GLASS_PANE
-  NSAccessibilityUnknownRole,                   // ROLE_HTML_CONTAINER
-  NSAccessibilityImageRole,                     // ROLE_ICON
-  NSAccessibilityStaticTextRole,                // ROLE_LABEL
-  NSAccessibilityGroupRole,                     // ROLE_LAYERED_PANE
-  NSAccessibilityGroupRole,                     // ROLE_OPTION_PANE
-  NSAccessibilityTextFieldRole,                 // ROLE_PASSWORD_TEXT
-  NSAccessibilityUnknownRole,                   // ROLE_POPUP_MENU. unused
-  NSAccessibilityMenuItemRole,                  // ROLE_RADIO_MENU_ITEM
-  NSAccessibilityGroupRole,                     // ROLE_ROOT_PANE
-  NSAccessibilityScrollAreaRole,                // ROLE_SCROLL_PANE
-  NSAccessibilitySplitGroupRole,                // ROLE_SPLIT_PANE
-  NSAccessibilityUnknownRole,                   // ROLE_TABLE_COLUMN_HEADER
-  NSAccessibilityUnknownRole,                   // ROLE_TABLE_ROW_HEADER
-  NSAccessibilityMenuItemRole,                  // ROLE_TEAR_OFF_MENU_ITEM
-  NSAccessibilityUnknownRole,                   // ROLE_TERMINAL
-  NSAccessibilityGroupRole,                     // ROLE_TEXT_CONTAINER
-  NSAccessibilityButtonRole,                    // ROLE_TOGGLE_BUTTON
-  NSAccessibilityTableRole,                     // ROLE_TREE_TABLE
-  NSAccessibilityUnknownRole,                   // ROLE_VIEWPORT
-  NSAccessibilityGroupRole,                     // ROLE_HEADER
-  NSAccessibilityGroupRole,                     // ROLE_FOOTER
-  NSAccessibilityGroupRole,                     // ROLE_PARAGRAPH
-  @"AXRuler",                                   // ROLE_RULER. 10.4+ only, so we re-define the constant.
-  NSAccessibilityUnknownRole,                   // ROLE_AUTOCOMPLETE
-  NSAccessibilityTextFieldRole,                 // ROLE_EDITBAR
-  NSAccessibilityTextFieldRole,                 // ROLE_ENTRY
-  NSAccessibilityStaticTextRole,                // ROLE_CAPTION
-  NSAccessibilityScrollAreaRole,                // ROLE_DOCUMENT_FRAME
-  @"AXHeading",                                 // ROLE_HEADING
-  NSAccessibilityGroupRole,                     // ROLE_PAG
-  NSAccessibilityGroupRole,                     // ROLE_SECTION
-  NSAccessibilityUnknownRole,                   // ROLE_REDUNDANT_OBJECT
-  NSAccessibilityGroupRole,                     // ROLE_FORM
-  NSAccessibilityUnknownRole,                   // ROLE_IME
-  NSAccessibilityUnknownRole,                   // ROLE_APP_ROOT. unused on OS X
-  NSAccessibilityMenuItemRole,                  // ROLE_PARENT_MENUITEM
-  NSAccessibilityGroupRole,                     // ROLE_CALENDAR
-  NSAccessibilityMenuRole,                      // ROLE_COMBOBOX_LIST
-  NSAccessibilityMenuItemRole,                  // ROLE_COMBOBOX_OPTION
-  NSAccessibilityImageRole,                     // ROLE_IMAGE_MAP
-  NSAccessibilityRowRole,                       // ROLE_OPTION
-  NSAccessibilityRowRole,                       // ROLE_RICH_OPTION
-  NSAccessibilityListRole,                      // ROLE_LISTBOX
-  NSAccessibilityUnknownRole,                   // ROLE_FLAT_EQUATION
-  NSAccessibilityGroupRole,                     // ROLE_GRID_CELL
-  NSAccessibilityGroupRole,                     // ROLE_EMBEDDED_OBJECT
-  NSAccessibilityGroupRole,                     // ROLE_NOTE
-  NSAccessibilityGroupRole,                     // ROLE_FIGURE
-  NSAccessibilityCheckBoxRole,                  // ROLE_CHECK_RICH_OPTION
-  @"ROLE_LAST_ENTRY"                            // ROLE_LAST_ENTRY. bogus role that will never be shown (just marks the end of this array)!
+  NSAccessibilityUnknownRole,                   // roles::NOTHING              0
+  NSAccessibilityUnknownRole,                   // roles::TITLEBAR             1      Irrelevant on OS X; windows are always native.
+  NSAccessibilityScrollBarRole,                 // roles::SCROLLBAR            3      We might need to make this its own mozAccessible, to support the children objects (valueindicator, down/up buttons).
+  NSAccessibilityMenuBarRole,                   // roles::MENUBAR              2      Irrelevant on OS X; the menubar will always be native and on the top of the screen.
+  NSAccessibilitySplitterRole,                  // roles::GRIP                 4
+  NSAccessibilityUnknownRole,                   // roles::SOUND                5      Unused on OS X.
+  NSAccessibilityUnknownRole,                   // roles::CURSOR               6      Unused on OS X.
+  NSAccessibilityUnknownRole,                   // roles::CARET                7      Unused on OS X.
+  NSAccessibilityWindowRole,                    // roles::ALERT                8
+  NSAccessibilityWindowRole,                    // roles::WINDOW               9      Irrelevant on OS X; all window a11y is handled by the system.
+  NSAccessibilityScrollAreaRole,                // roles::INTERNAL_FRAME       10
+  NSAccessibilityMenuRole,                      // roles::MENUPOPUP            11     The parent of menuitems.
+  NSAccessibilityMenuItemRole,                  // roles::MENUITEM             12
+  @"AXHelpTag",                                 // roles::TOOLTIP              13     10.4+ only, so we re-define the constant.
+  NSAccessibilityGroupRole,                     // roles::APPLICATION          14     Unused on OS X. the system will take care of this.
+  @"AXWebArea",                                 // roles::DOCUMENT             15
+  NSAccessibilityGroupRole,                     // roles::PANE                 16
+  NSAccessibilityUnknownRole,                   // roles::CHART                17
+  NSAccessibilityWindowRole,                    // roles::DIALOG               18     There's a dialog subrole.
+  NSAccessibilityUnknownRole,                   // roles::BORDER               19     Unused on OS X.
+  NSAccessibilityGroupRole,                     // roles::GROUPING             20
+  NSAccessibilityUnknownRole,                   // roles::SEPARATOR            21
+  NSAccessibilityToolbarRole,                   // roles::TOOLBAR              22
+  NSAccessibilityUnknownRole,                   // roles::STATUSBAR            23     Doesn't exist on OS X (a status bar is its parts; a progressbar, a label, etc.)
+  NSAccessibilityGroupRole,                     // roles::TABLE                24
+  NSAccessibilityGroupRole,                     // roles::COLUMNHEADER         25
+  NSAccessibilityGroupRole,                     // roles::ROWHEADER            26
+  NSAccessibilityColumnRole,                    // roles::COLUMN               27
+  NSAccessibilityRowRole,                       // roles::ROW                  28
+  NSAccessibilityGroupRole,                     // roles::CELL                 29
+  @"AXLink",                                    // roles::LINK                 30     10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
+  @"AXHelpTag",                                 // roles::HELPBALLOON          31
+  NSAccessibilityUnknownRole,                   // roles::CHARACTER            32     Unused on OS X.
+  NSAccessibilityListRole,                      // roles::LIST                 33
+  NSAccessibilityRowRole,                       // roles::LISTITEM             34
+  NSAccessibilityOutlineRole,                   // roles::OUTLINE              35
+  NSAccessibilityRowRole,                       // roles::OUTLINEITEM          36     XXX: use OutlineRow as subrole.
+  NSAccessibilityRadioButtonRole,               // roles::PAGETAB              37
+  NSAccessibilityGroupRole,                     // roles::PROPERTYPAGE         38
+  NSAccessibilityUnknownRole,                   // roles::INDICATOR            39
+  NSAccessibilityImageRole,                     // roles::GRAPHIC              40
+  NSAccessibilityStaticTextRole,                // roles::STATICTEXT           41
+  NSAccessibilityStaticTextRole,                // roles::TEXT_LEAF            42
+  NSAccessibilityButtonRole,                    // roles::PUSHBUTTON           43
+  NSAccessibilityCheckBoxRole,                  // roles::CHECKBUTTON          44
+  NSAccessibilityRadioButtonRole,               // roles::RADIOBUTTON          45
+  NSAccessibilityPopUpButtonRole,               // roles::COMBOBOX             46
+  NSAccessibilityPopUpButtonRole,               // roles::DROPLIST             47
+  NSAccessibilityProgressIndicatorRole,         // roles::PROGRESSBAR          48
+  NSAccessibilityUnknownRole,                   // roles::DIAL                 49
+  NSAccessibilityUnknownRole,                   // roles::HOTKEYFIELD          50
+  NSAccessibilitySliderRole,                    // roles::SLIDER               51
+  NSAccessibilityIncrementorRole,               // roles::SPINBUTTON           52     Subroles: Increment/Decrement.
+  NSAccessibilityUnknownRole,                   // roles::DIAGRAM              53
+  NSAccessibilityUnknownRole,                   // roles::ANIMATION            54
+  NSAccessibilityUnknownRole,                   // roles::EQUATION             55
+  NSAccessibilityPopUpButtonRole,               // roles::BUTTONDROPDOWN       56
+  NSAccessibilityMenuButtonRole,                // roles::BUTTONMENU           57
+  NSAccessibilityGroupRole,                     // roles::BUTTONDROPDOWNGRID   58
+  NSAccessibilityUnknownRole,                   // roles::WHITESPACE           59
+  NSAccessibilityTabGroupRole,                  // roles::PAGETABLIST          60
+  NSAccessibilityUnknownRole,                   // roles::CLOCK                61     Unused on OS X
+  NSAccessibilityButtonRole,                    // roles::SPLITBUTTON          62
+  NSAccessibilityUnknownRole,                   // roles::IPADDRESS            63
+  NSAccessibilityStaticTextRole,                // roles::ACCEL_LABEL          64
+  NSAccessibilityUnknownRole,                   // roles::ARROW                65
+  NSAccessibilityImageRole,                     // roles::CANVAS               66
+  NSAccessibilityMenuItemRole,                  // roles::CHECK_MENU_ITEM      67
+  NSAccessibilityColorWellRole,                 // roles::COLOR_CHOOSER        68
+  NSAccessibilityUnknownRole,                   // roles::DATE_EDITOR          69 
+  NSAccessibilityImageRole,                     // roles::DESKTOP_ICON         70
+  NSAccessibilityUnknownRole,                   // roles::DESKTOP_FRAME        71
+  NSAccessibilityBrowserRole,                   // roles::DIRECTORY_PANE       72
+  NSAccessibilityUnknownRole,                   // roles::FILE_CHOOSER         73     Unused on OS X
+  NSAccessibilityUnknownRole,                   // roles::FONT_CHOOSER         74
+  NSAccessibilityUnknownRole,                   // roles::CHROME_WINDOW        75     Unused on OS X
+  NSAccessibilityGroupRole,                     // roles::GLASS_PANE           76
+  NSAccessibilityUnknownRole,                   // roles::HTML_CONTAINER       77
+  NSAccessibilityImageRole,                     // roles::ICON                 78
+  NSAccessibilityStaticTextRole,                // roles::LABEL                79
+  NSAccessibilityGroupRole,                     // roles::LAYERED_PANE         80
+  NSAccessibilityGroupRole,                     // roles::OPTION_PANE          81
+  NSAccessibilityTextFieldRole,                 // roles::PASSWORD_TEXT        82
+  NSAccessibilityUnknownRole,                   // roles::POPUP_MENU           83     Unused
+  NSAccessibilityMenuItemRole,                  // roles::RADIO_MENU_ITEM      84
+  NSAccessibilityGroupRole,                     // roles::ROOT_PANE            85
+  NSAccessibilityScrollAreaRole,                // roles::SCROLL_PANE          86
+  NSAccessibilitySplitGroupRole,                // roles::SPLIT_PANE           87
+  NSAccessibilityUnknownRole,                   // roles::TABLE_COLUMN_HEADER  88
+  NSAccessibilityUnknownRole,                   // roles::TABLE_ROW_HEADER     89
+  NSAccessibilityMenuItemRole,                  // roles::TEAR_OFF_MENU_ITEM   90
+  NSAccessibilityUnknownRole,                   // roles::TERMINAL             91
+  NSAccessibilityGroupRole,                     // roles::TEXT_CONTAINER       92
+  NSAccessibilityButtonRole,                    // roles::TOGGLE_BUTTON        93
+  NSAccessibilityTableRole,                     // roles::TREE_TABLE           94
+  NSAccessibilityUnknownRole,                   // roles::VIEWPORT             95
+  NSAccessibilityGroupRole,                     // roles::HEADER               96
+  NSAccessibilityGroupRole,                     // roles::FOOTER               97
+  NSAccessibilityGroupRole,                     // roles::PARAGRAPH            98
+  @"AXRuler",                                   // roles::RULER                99     10.4+ only, so we re-define the constant.
+  NSAccessibilityComboBoxRole,                  // roles::AUTOCOMPLETE         100
+  NSAccessibilityTextFieldRole,                 // roles::EDITBAR              101
+  NSAccessibilityTextFieldRole,                 // roles::ENTRY                102
+  NSAccessibilityStaticTextRole,                // roles::CAPTION              103
+  NSAccessibilityScrollAreaRole,                // roles::DOCUMENT_FRAME       104
+  @"AXHeading",                                 // roles::HEADING              105
+  NSAccessibilityGroupRole,                     // roles::PAGE                 106
+  NSAccessibilityGroupRole,                     // roles::SECTION              107
+  NSAccessibilityUnknownRole,                   // roles::REDUNDANT_OBJECT     108
+  NSAccessibilityGroupRole,                     // roles::FORM                 109
+  NSAccessibilityUnknownRole,                   // roles::IME                  110
+  NSAccessibilityUnknownRole,                   // roles::APP_ROOT             111    Unused on OS X
+  NSAccessibilityMenuItemRole,                  // roles::PARENT_MENUITEM      112
+  NSAccessibilityGroupRole,                     // roles::CALENDAR             113
+  NSAccessibilityMenuRole,                      // roles::COMBOBOX_LIST        114
+  NSAccessibilityMenuItemRole,                  // roles::COMBOBOX_OPTION      115
+  NSAccessibilityImageRole,                     // roles::IMAGE_MAP            116
+  NSAccessibilityRowRole,                       // roles::OPTION               117
+  NSAccessibilityRowRole,                       // roles::RICH_OPTION          118
+  NSAccessibilityListRole,                      // roles::LISTBOX              119
+  NSAccessibilityUnknownRole,                   // roles::FLAT_EQUATION        120
+  NSAccessibilityGroupRole,                     // roles::GRID_CELL            121
+  NSAccessibilityGroupRole,                     // roles::EMBEDDED_OBJECT      122
+  NSAccessibilityGroupRole,                     // roles::NOTE                 123
+  NSAccessibilityGroupRole,                     // roles::FIGURE               124
+  NSAccessibilityCheckBoxRole,                  // roles::CHECK_RICH_OPTION    125
+  @"ROLE_LAST_ENTRY"                            // roles::LAST_ENTRY                  Bogus role that will never be shown (just marks the end of this array)!
 };
--- a/accessible/src/msaa/CAccessibleHyperlink.cpp
+++ b/accessible/src/msaa/CAccessibleHyperlink.cpp
@@ -59,17 +59,17 @@ CAccessibleHyperlink::QueryInterface(REF
     if (!thisObj->IsLink())
       return E_NOINTERFACE;
 
     *ppv = static_cast<IAccessibleHyperlink*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
-  return CAccessibleAction::QueryInterface(iid, ppv);
+  return ia2AccessibleAction::QueryInterface(iid, ppv);
 }
 
 // IAccessibleHyperlink
 
 STDMETHODIMP
 CAccessibleHyperlink::get_anchor(long aIndex, VARIANT *aAnchor)
 {
 __try {
--- a/accessible/src/msaa/CAccessibleHyperlink.h
+++ b/accessible/src/msaa/CAccessibleHyperlink.h
@@ -38,29 +38,29 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _ACCESSIBLE_HYPERLINK_H
 #define _ACCESSIBLE_HYPERLINK_H
 
 #include "nsISupports.h"
 
-#include "CAccessibleAction.h"
+#include "ia2AccessibleAction.h"
 #include "AccessibleHyperlink.h"
 
-class CAccessibleHyperlink: public CAccessibleAction,
+class CAccessibleHyperlink: public ia2AccessibleAction,
                             public IAccessibleHyperlink
 {
 public:
 
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessibleAction
-  FORWARD_IACCESSIBLEACTION(CAccessibleAction)
+  FORWARD_IACCESSIBLEACTION(ia2AccessibleAction)
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchor(
       /* [in] */ long index,
       /* [retval][out] */ VARIANT *anchor);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_anchorTarget(
       /* [in] */ long index,
       /* [retval][out] */ VARIANT *anchorTarget);
--- a/accessible/src/msaa/Makefile.in
+++ b/accessible/src/msaa/Makefile.in
@@ -58,17 +58,17 @@ CPPSRCS = \
   nsXULMenuAccessibleWrap.cpp \
   nsXULListboxAccessibleWrap.cpp \
   nsXULTreeGridAccessibleWrap.cpp \
   nsHyperTextAccessibleWrap.cpp \
   nsHTMLImageAccessibleWrap.cpp \
   nsHTMLTableAccessibleWrap.cpp \
   nsApplicationAccessibleWrap.cpp \
   nsWinUtils.cpp \
-  CAccessibleAction.cpp \
+  ia2AccessibleAction.cpp \
   CAccessibleImage.cpp \
   CAccessibleComponent.cpp \
   CAccessibleText.cpp \
   CAccessibleEditableText.cpp \
   CAccessibleHyperlink.cpp \
   CAccessibleHypertext.cpp \
   ia2AccessibleRelation.cpp \
   CAccessibleTable.cpp \
@@ -87,17 +87,17 @@ EXPORTS = \
   nsARIAGridAccessibleWrap.h \
   nsXULMenuAccessibleWrap.h \
   nsXULListboxAccessibleWrap.h \
   nsXULTreeGridAccessibleWrap.h \
   nsHyperTextAccessibleWrap.h \
   nsHTMLImageAccessibleWrap.h \
   nsHTMLTableAccessibleWrap.h \
   nsApplicationAccessibleWrap.h \
-  CAccessibleAction.h \
+  ia2AccessibleAction.h \
   CAccessibleImage.h \
   CAccessibleComponent.h \
   CAccessibleText.h \
   CAccessibleEditableText.h \
   CAccessibleHyperlink.h \
   CAccessibleHypertext.h \
   CAccessibleTable.h \
   CAccessibleTableCell.h \
rename from accessible/src/msaa/CAccessibleAction.cpp
rename to accessible/src/msaa/ia2AccessibleAction.cpp
--- a/accessible/src/msaa/CAccessibleAction.cpp
+++ b/accessible/src/msaa/ia2AccessibleAction.cpp
@@ -33,84 +33,84 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "CAccessibleAction.h"
+#include "ia2AccessibleAction.h"
 
 #include "AccessibleAction_i.c"
 
-#include "nsAccessible.h"
+#include "nsAccessibleWrap.h"
 
 // IUnknown
 
 STDMETHODIMP
-CAccessibleAction::QueryInterface(REFIID iid, void** ppv)
+ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv)
 {
   *ppv = NULL;
 
   if (IID_IAccessibleAction == iid) {
     *ppv = static_cast<IAccessibleAction*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
   return E_NOINTERFACE;
 }
 
 // IAccessibleAction
 
 STDMETHODIMP
-CAccessibleAction::nActions(long* aActionCount)
+ia2AccessibleAction::nActions(long* aActionCount)
 {
 __try {
   if (!aActionCount)
     return E_INVALIDARG;
 
   *aActionCount = 0;
 
-  nsRefPtr<nsAccessible> acc(do_QueryObject(this));
-  if (!acc || acc->IsDefunct())
+  nsAccessibleWrap* acc = static_cast<nsAccessibleWrap*>(this);
+  if (acc->IsDefunct())
     return E_FAIL;
 
   *aActionCount = acc->ActionCount();
   return S_OK;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-CAccessibleAction::doAction(long aActionIndex)
+ia2AccessibleAction::doAction(long aActionIndex)
 {
 __try {
-  nsCOMPtr<nsIAccessible> acc(do_QueryObject(this));
-  if (!acc)
+  nsAccessibleWrap* acc = static_cast<nsAccessibleWrap*>(this);
+  if (acc->IsDefunct())
     return E_FAIL;
 
   PRUint8 index = static_cast<PRUint8>(aActionIndex);
   nsresult rv = acc->DoAction(index);
   return GetHRESULT(rv);
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-CAccessibleAction::get_description(long aActionIndex, BSTR *aDescription)
+ia2AccessibleAction::get_description(long aActionIndex, BSTR *aDescription)
 {
 __try {
   *aDescription = NULL;
 
-  nsCOMPtr<nsIAccessible> acc(do_QueryObject(this));
-  if (!acc)
+  nsAccessibleWrap* acc = static_cast<nsAccessibleWrap*>(this);
+  if (acc->IsDefunct())
     return E_FAIL;
 
   nsAutoString description;
   PRUint8 index = static_cast<PRUint8>(aActionIndex);
   nsresult rv = acc->GetActionDescription(index, description);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
@@ -121,34 +121,34 @@ CAccessibleAction::get_description(long 
                                       description.Length());
   return *aDescription ? S_OK : E_OUTOFMEMORY;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-CAccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding,
+ia2AccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding,
                                   BSTR **aKeyBinding,
                                   long *aNumBinding)
 {
 __try {
   if (!aKeyBinding)
     return E_INVALIDARG;
   *aKeyBinding = NULL;
 
   if (!aNumBinding)
     return E_INVALIDARG;
   *aNumBinding = 0;
 
   if (aActionIndex != 0 || aNumMaxBinding < 1)
     return E_INVALIDARG;
 
-  nsRefPtr<nsAccessible> acc(do_QueryObject(this));
-  if (!acc || acc->IsDefunct())
+  nsAccessibleWrap* acc = static_cast<nsAccessibleWrap*>(this);
+  if (acc->IsDefunct())
     return E_FAIL;
 
   // Expose keyboard shortcut if it's not exposed via MSAA keyboard shortcut.
   KeyBinding keyBinding = acc->AccessKey();
   if (keyBinding.IsEmpty())
     return S_FALSE;
 
   keyBinding = acc->KeyboardShortcut();
@@ -171,23 +171,23 @@ CAccessibleAction::get_keyBinding(long a
   *aNumBinding = 1;
   return S_OK;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-CAccessibleAction::get_name(long aActionIndex, BSTR *aName)
+ia2AccessibleAction::get_name(long aActionIndex, BSTR *aName)
 {
 __try {
   *aName = NULL;
 
-  nsCOMPtr<nsIAccessible> acc(do_QueryObject(this));
-  if (!acc)
+  nsAccessibleWrap* acc = static_cast<nsAccessibleWrap*>(this);
+  if (acc->IsDefunct())
     return E_FAIL;
 
   nsAutoString name;
   PRUint8 index = static_cast<PRUint8>(aActionIndex);
   nsresult rv = acc->GetActionName(index, name);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
@@ -197,17 +197,17 @@ CAccessibleAction::get_name(long aAction
   *aName = ::SysAllocStringLen(name.get(), name.Length());
   return *aName ? S_OK : E_OUTOFMEMORY;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-CAccessibleAction::get_localizedName(long aActionIndex, BSTR *aLocalizedName)
+ia2AccessibleAction::get_localizedName(long aActionIndex, BSTR *aLocalizedName)
 {
 __try {
   *aLocalizedName = NULL;
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return E_NOTIMPL;
 }
 
rename from accessible/src/msaa/CAccessibleAction.h
rename to accessible/src/msaa/ia2AccessibleAction.h
--- a/accessible/src/msaa/CAccessibleAction.h
+++ b/accessible/src/msaa/ia2AccessibleAction.h
@@ -40,17 +40,17 @@
 
 #ifndef _ACCESSIBLE_ACTION_H
 #define _ACCESSIBLE_ACTION_H
 
 #include "nsISupports.h"
 
 #include "AccessibleAction.h"
 
-class CAccessibleAction: public IAccessibleAction
+class ia2AccessibleAction: public IAccessibleAction
 {
 public:
 
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessibleAction
   virtual HRESULT STDMETHODCALLTYPE nActions(
@@ -72,19 +72,16 @@ public:
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_name(
       /* [in] */ long actionIndex,
       /* [retval][out] */ BSTR *name);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedName(
       /* [in] */ long actionIndex,
       /* [retval][out] */ BSTR *localizedName);
 
-  // nsISupports
-  NS_IMETHOD QueryInterface(const nsIID& uuid, void** result) = 0;
-
 };
 
 
 #define FORWARD_IACCESSIBLEACTION(Class)                                       \
 virtual HRESULT STDMETHODCALLTYPE nActions(long *nActions)                     \
 {                                                                              \
   return Class::nActions(nActions);                                            \
 }                                                                              \
--- a/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp
+++ b/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp
@@ -96,16 +96,20 @@ nsHTMLWin32ObjectOwnerAccessible::CacheC
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLWin32ObjectAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLWin32ObjectAccessible::nsHTMLWin32ObjectAccessible(void* aHwnd):
 nsLeafAccessible(nsnull, nsnull)
 {
+  // XXX: Mark it as defunct to make sure no single nsAccessible method is
+  // running on it. We need to allow accessible without DOM nodes.
+  mFlags |= eIsDefunct;
+
   mHwnd = aHwnd;
   if (mHwnd) {
     // The plugin is not windowless. In this situation we use 
     // use its inner child owned by the plugin so that we don't get
     // in an infinite loop, where the WM_GETOBJECT's get forwarded
     // back to us and create another nsHTMLWin32ObjectAccessible
     HWND childWnd = ::GetWindow((HWND)aHwnd, GW_CHILD);
     if (childWnd) {
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -63,16 +63,18 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULTreeAccessible::
   nsXULTreeAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
   nsAccessibleWrap(aContent, aDoc)
 {
+  mFlags |= eXULTreeAccessible;
+
   mTree = nsCoreUtils::GetTreeBoxObject(aContent);
   if (mTree)
     mTree->GetView(getter_AddRefs(mTreeView));
 
   NS_ASSERTION(mTree && mTreeView, "Can't get mTree or mTreeView!\n");
 
   nsIContent* parentContent = mContent->GetParent();
   if (parentContent) {
@@ -683,33 +685,33 @@ nsXULTreeAccessible::TreeViewInvalidated
       NS_ASSERTION(treeitemAcc, "Wrong accessible at the given key!");
 
       treeitemAcc->RowInvalidated(aStartCol, endCol);
     }
   }
 }
 
 void
-nsXULTreeAccessible::TreeViewChanged()
+nsXULTreeAccessible::TreeViewChanged(nsITreeView* aView)
 {
   if (IsDefunct())
     return;
 
   // Fire reorder event on tree accessible on accessible tree (do not fire
   // show/hide events on tree items because it can be expensive to fire them for
   // each tree item.
   nsRefPtr<AccEvent> reorderEvent =
     new AccEvent(nsIAccessibleEvent::EVENT_REORDER, this, eAutoDetect,
                  AccEvent::eCoalesceFromSameSubtree);
   if (reorderEvent)
     Document()->FireDelayedAccessibleEvent(reorderEvent);
 
   // Clear cache.
   ClearCache(mAccessibleCache);
-  mTree->GetView(getter_AddRefs(mTreeView));
+  mTreeView = aView;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible: protected implementation
 
 already_AddRefed<nsAccessible>
 nsXULTreeAccessible::CreateTreeItemAccessible(PRInt32 aRow)
 {
@@ -858,17 +860,17 @@ nsXULTreeItemAccessibleBase::RelationByT
 
   PRInt32 parentIndex = -1;
   if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex)))
     return Relation();
 
   if (parentIndex == -1)
     return Relation(mParent);
 
-  nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
+  nsXULTreeAccessible* treeAcc = mParent->AsXULTree();
   return Relation(treeAcc->GetTreeItemAccessible(parentIndex));
 }
 
 PRUint8
 nsXULTreeItemAccessibleBase::ActionCount()
 {
   // "activate" action is available for all treeitems, "expand/collapse" action
   // is avaible for treeitem which is container.
@@ -1278,17 +1280,17 @@ nsXULTreeColumnsAccessible::GetSiblingAt
   nsCOMPtr<nsITreeBoxObject> tree = nsCoreUtils::GetTreeBoxObject(mContent);
   if (tree) {
     nsCOMPtr<nsITreeView> treeView;
     tree->GetView(getter_AddRefs(treeView));
     if (treeView) {
       PRInt32 rowCount = 0;
       treeView->GetRowCount(&rowCount);
       if (rowCount > 0 && aOffset <= rowCount) {
-        nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(Parent());
+        nsXULTreeAccessible* treeAcc = Parent()->AsXULTree();
 
         if (treeAcc)
           return treeAcc->GetTreeItemAccessible(aOffset - 1);
       }
     }
   }
 
   return nsnull;
--- a/accessible/src/xul/nsXULTreeAccessible.h
+++ b/accessible/src/xul/nsXULTreeAccessible.h
@@ -141,17 +141,17 @@ public:
    *                    index
    */
   void TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
                            PRInt32 aStartCol, PRInt32 aEndCol);
 
   /**
    * Invalidates children created for previous tree view.
    */
-  void TreeViewChanged();
+  void TreeViewChanged(nsITreeView* aView);
 
 protected:
   /**
    * Creates tree item accessible for the given row index.
    */
   virtual already_AddRefed<nsAccessible> CreateTreeItemAccessible(PRInt32 aRow);
 
   nsCOMPtr<nsITreeBoxObject> mTree;
@@ -315,9 +315,19 @@ public:
 
 protected:
 
   // nsAccessible
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
                                            nsresult *aError = nsnull) const;
 };
 
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessible downcasting method
+
+inline nsXULTreeAccessible*
+nsAccessible::AsXULTree()
+{
+  return IsXULTree() ?
+    static_cast<nsXULTreeAccessible*>(this) : nsnull;
+}
+
 #endif
--- a/accessible/tests/mochitest/events/test_tree.xul
+++ b/accessible/tests/mochitest/events/test_tree.xul
@@ -1,20 +1,15 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
                  type="text/css"?>
 
-<!--
-  Bug 368835 - fire TreeViewChanged/TreeRowCountChanged events.
-  Bug 308564 - no accessibility events when data in a tree row changes.
--->
-
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        title="DOM TreeViewChanged/TreeRowCountChanged and a11y name change events.">
+        title="DOM TreeRowCountChanged and a11y name change events.">
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 
   <script type="application/javascript"
           src="../treeview.js" />
 
   <script type="application/javascript"
@@ -24,30 +19,16 @@
 
   <script type="application/javascript">
   <![CDATA[
 
     ////////////////////////////////////////////////////////////////////////////
     // Invoker's checkers
 
     /**
-     * Check TreeViewChanged event and run through accessible tree to ensure
-     * it's created.
-     */
-    function treeViewChangedChecker(aMsg)
-    {
-      this.type = "TreeViewChanged";
-      this.target = gTree;
-      this.getID = function getID()
-      {
-        return "TreeViewChanged";
-      }
-    }
-
-    /**
      * Check TreeRowCountChanged event.
      */
     function rowCountChangedChecker(aMsg, aIdx, aCount)
     {
       this.type = "TreeRowCountChanged";
       this.target = gTree;
       this.check = function check(aEvent)
       {
@@ -115,29 +96,28 @@
         return aMsg + "name changed";
       }
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Invokers
 
     /**
-     * Set tree view and process TreeViewChanged handler.
+     * Set tree view.
      */
     function setTreeView()
     {
       this.invoke = function setTreeView_invoke()
       {
         gTreeBox.view = gView;
       }
 
       this.getID = function setTreeView_getID() { return "set tree view"; }
 
       this.eventSeq = [
-        new treeViewChangedChecker(),
         new invokerChecker(EVENT_REORDER, gTree)
       ];
     };
 
     /**
      * Insert row at 0 index and checks TreeRowCountChanged and TreeInvalidated
      * event.
      */
@@ -293,16 +273,21 @@
          title="Fire TreeViewChanged/TreeRowCountChanged events.">
         Mozilla Bug 368835
       </a><br/>
       <a target="_blank"
          href="https://bugzilla.mozilla.org/show_bug.cgi?id=308564"
          title="No accessibility events when data in a tree row changes.">
         Mozilla Bug 308564
       </a>
+      <a target="_blank"
+         href="https://bugzilla.mozilla.org/show_bug.cgi?id=739524"
+         title="replace TreeViewChanged DOM event on direct call from XUL tree.">
+        Mozilla Bug 739524
+      </a>
       <p id="display"></p>
       <div id="content" style="display: none">
       </div>
       <pre id="test">
       </pre>
     </body>
 
     <vbox id="debug"/>
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -83,16 +83,17 @@ if [ ! "$LIBXUL_SDK" ]; then
   add_makefiles "
     memory/mozalloc/Makefile
     mozglue/Makefile
     mozglue/build/Makefile
   "
   if [ "$MOZ_MEMORY" ]; then
     add_makefiles "
       memory/jemalloc/Makefile
+      memory/build/Makefile
     "
   fi
   if [ "$MOZ_WIDGET_TOOLKIT" = "android" ]; then
     add_makefiles "
       other-licenses/android/Makefile
       other-licenses/skia-npapi/Makefile
       mozglue/android/Makefile
     "
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -301,20 +301,39 @@ var shell = {
           screen.mozEnabled = false;
         }
       } else {
         screen.mozEnabled = true;
       }
     }
   }
   let idleTimeout = Services.prefs.getIntPref("power.screen.timeout");
-  if (idleTimeout) {
-    Services.idle.addIdleObserver(idleHandler, idleTimeout);
-    power.addWakeLockListener(wakeLockHandler);
+  let request = navigator.mozSettings.getLock().get("power.screen.timeout");
+  request.onsuccess = function onSuccess() {
+    idleTimeout = request.result["power.screen.timeout"] || idleTimeout;
+    if (idleTimeout) {
+      Services.idle.addIdleObserver(idleHandler, idleTimeout);
+      power.addWakeLockListener(wakeLockHandler);
+    }
   }
+  request.onerror = function onError() {
+    if (idleTimeout) {
+      Services.idle.addIdleObserver(idleHandler, idleTimeout);
+      power.addWakeLockListener(wakeLockHandler);
+    }
+  }
+  // XXX We may override other's callback here, but this is the only
+  // user of mozSettings in shell.js at this moment.
+  navigator.mozSettings.onsettingchange = function onSettingChange(e) {
+    if (e.settingName == "power.screen.timeout" && e.settingValue) {
+      Services.idle.removeIdleObserver(idleHandler, idleTimeout);
+      idleTimeout = e.settingValue;
+      Services.idle.addIdleObserver(idleHandler, idleTimeout);
+    }
+  };
 })();
 
 function nsBrowserAccess() {
 }
 
 nsBrowserAccess.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow]),
 
--- a/b2g/installer/removed-files.in
+++ b/b2g/installer/removed-files.in
@@ -1,2 +1,3 @@
 README.txt
 @DLL_PREFIX@mozutils@DLL_SUFFIX@
+jssubloader/
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1332452348000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1332870813000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -80,16 +80,20 @@
       <emItem  blockID="i53" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
                         <versionRange  minVersion="2.0.3" maxVersion="2.0.3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i59" id="ghostviewer@youtube2.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i78" id="socialnetworktools@mozilla.doslash.org">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i70" id="psid-vhvxQHMZBOzUZA@jetpack">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i68" id="flashupdate@adobe.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
@@ -106,16 +110,18 @@
       <emItem  blockID="i56" id="flash@adobe.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i55" id="youtube@youtube7.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i47" id="youtube@youtube2.com">
+                        </emItem>
       <emItem  blockID="i22" id="ShopperReports@ShopperReports.com">
                         <versionRange  minVersion="3.1.22.0" maxVersion="3.1.22.0">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i44" id="sigma@labs.mozilla">
                         </emItem>
       <emItem  blockID="i5" id="support@daemon-tools.cc">
                         <versionRange  minVersion=" " maxVersion="1.0.0.5">
@@ -138,18 +144,20 @@
       <emItem  blockID="i20" id="{AB2CE124-6272-4b12-94A9-7303C7397BD1}">
                         <versionRange  minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i76" id="crossriderapp3924@crossrider.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i47" id="youtube@youtube2.com">
-                        </emItem>
+      <emItem  blockID="i79" id="GifBlock@facebook.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i62" id="jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
                         <versionRange  minVersion="2.2" maxVersion="2.2">
                     </versionRange>
                   </emItem>
@@ -188,42 +196,21 @@
           </pluginItem>
       <pluginItem  blockID="p33">
       <match name="name" exp="[0-6]\.0\.[01]\d{2}\.\d+" />            <match name="filename" exp="npdeploytk.dll" />              <versionRange  severity="1">
                   </versionRange>
           </pluginItem>
     </pluginItems>
 
   <gfxItems>
-    <gfxBlacklistEntry  blockID="g35">
-      <os>WINNT 6.1</os>
-      <vendor>0x10de</vendor>
-              <devices>
+    <gfxBlacklistEntry  blockID="g35">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
-            <feature>DIRECT2D</feature>
-      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>
-      <driverVersion>8.17.12.5896</driverVersion>
-      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry  blockID="g36">
-      <os>WINNT 6.1</os>
-      <vendor>0x10de</vendor>
-              <devices>
+            <feature>DIRECT2D</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
+    <gfxBlacklistEntry  blockID="g36">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
-            <feature>DIRECT3D_9_LAYERS</feature>
-      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>
-      <driverVersion>8.17.12.5896</driverVersion>
-      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry  blockID="g37">
-      <os>WINNT 5.1</os>
-      <vendor>0x10de</vendor>
-            <feature>DIRECT3D_9_LAYERS</feature>
-      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>
-      <driverVersion>7.0.0.0</driverVersion>
-      <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator>
-    </gfxBlacklistEntry>
+            <feature>DIRECT3D_9_LAYERS</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
+    <gfxBlacklistEntry  blockID="g37">      <os>WINNT 5.1</os>      <vendor>0x10de</vendor>            <feature>DIRECT3D_9_LAYERS</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>7.0.0.0</driverVersion>      <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     </gfxItems>
 
 
 </blocklist>
\ No newline at end of file
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -262,17 +262,17 @@ nsContextMenu.prototype = {
 
     // Set as Desktop background depends on whether an image was clicked on,
     // and only works if we have a shell service.
     var haveSetDesktopBackground = false;
 #ifdef HAVE_SHELL_SERVICE
     // Only enable Set as Desktop Background if we can get the shell service.
     var shell = getShellService();
     if (shell)
-      haveSetDesktopBackground = true;
+      haveSetDesktopBackground = shell.canSetDesktopBackground;
 #endif
     this.showItem("context-setDesktopBackground",
                   haveSetDesktopBackground && this.onLoadedImage);
 
     if (haveSetDesktopBackground && this.onLoadedImage) {
       document.getElementById("context-setDesktopBackground")
               .disabled = this.disableSetDesktopBackground();
     }
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -19,17 +19,17 @@ USE_STATIC_LIBS = 1
 endif
 
 EXPORTS = nsBrowserCompsCID.h
 
 CPPSRCS = nsModule.cpp \
           $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
-OS_LIBS	+= $(call EXPAND_LIBNAME,ole32 shell32)
+OS_LIBS	+= $(call EXPAND_LIBNAME,ole32 shell32 shlwapi)
 endif
 
 LOCAL_INCLUDES = \
 	-I$(srcdir)/../shell/src \
 	-I$(srcdir)/../feeds/src \
 	-I$(srcdir)/../privatebrowsing/src \
 	-I$(srcdir)/../about \
 	-I$(srcdir)/../dirprovider \
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -49,17 +49,17 @@ PlacesViewBase.prototype = {
     result.addObserver(this, false);
     return val;
   },
 
   _result: null,
   get result() this._result,
   set result(val) {
     if (this._result == val)
-      return;
+      return val;
 
     if (this._result) {
       this._result.removeObserver(this);
       this._resultNode.containerOpen = false;
     }
 
     if (this._rootElt.localName == "menupopup")
       this._rootElt._built = false;
@@ -1673,17 +1673,17 @@ PlacesToolbar.prototype = {
       aEvent.preventDefault();
       return;
     }
 
     let parent = aEvent.target.parentNode;
     if (parent.localName == "toolbarbutton")
       this._openedMenuButton = parent;
 
-    return PlacesViewBase.prototype._onPopupShowing.apply(this, arguments);
+    PlacesViewBase.prototype._onPopupShowing.apply(this, arguments);
   },
 
   _onPopupHidden: function PT__onPopupHidden(aEvent) {
     let popup = aEvent.target;
     let placesNode = popup._placesNode;
     // Avoid handling popuphidden of inner views
     if (placesNode && PlacesUIUtils.getViewForNode(popup) == this) {
       // UI performance: folder queries are cheap, keep the resultnode open
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -1510,17 +1510,17 @@ let PlacesControllerDragHelper = {
     let doCopy = ["copy", "link"].indexOf(dt.dropEffect) != -1;
 
     let transactions = [];
     let dropCount = dt.mozItemCount;
     let movedCount = 0;
     for (let i = 0; i < dropCount; ++i) {
       let flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
       if (!flavor)
-        return false;
+        return;
 
       let data = dt.mozGetDataAt(flavor, i);
       let unwrapped;
       if (flavor != TAB_DROP_TYPE) {
         // There's only ever one in the D&D case.
         unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
       }
       else if (data instanceof XULElement && data.localName == "tab" &&
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -257,17 +257,17 @@ PlacesTreeView.prototype = {
    *
    * @return the number of rows which were inserted.
    */
   _buildVisibleSection:
   function PTV__buildVisibleSection(aContainer, aFirstChildRow, aToOpen)
   {
     // There's nothing to do if the container is closed.
     if (!aContainer.containerOpen)
-      return;
+      return 0;
 
     // Inserting the new elements into the rows array in one shot (by
     // Array.concat) is faster than resizing the array (by splice) on each loop
     // iteration.
     let cc = aContainer.childCount;
     let newElements = new Array(cc);
     this._rows = this._rows.splice(0, aFirstChildRow)
                      .concat(newElements, this._rows);
--- a/browser/components/shell/public/nsIShellService.idl
+++ b/browser/components/shell/public/nsIShellService.idl
@@ -69,16 +69,25 @@ interface nsIShellService : nsISupports
   /** 
    * Used to determine whether or not to show a "Set Default Browser"
    * query dialog. This attribute is true if the application is starting
    * up and "browser.shell.checkDefaultBrowser" is true, otherwise it
    * is false.
    */
   attribute boolean shouldCheckDefaultBrowser;
 
+  /**
+   * Used to determine whether or not to offer "Set as desktop background"
+   * functionality. Even if shell service is available it is not
+   * guaranteed that it is able to set the background for every desktop
+   * which is especially true for Linux with its many different desktop
+   * environments.
+   */
+  readonly attribute boolean canSetDesktopBackground;
+
   /** 
    * Flags for positioning/sizing of the Desktop Background image.
    */
   const long BACKGROUND_TILE      = 1;
   const long BACKGROUND_STRETCH   = 2;
   const long BACKGROUND_CENTER    = 3;
   const long BACKGROUND_FILL      = 4;
   const long BACKGROUND_FIT       = 5;
--- a/browser/components/shell/src/nsGNOMEShellService.cpp
+++ b/browser/components/shell/src/nsGNOMEShellService.cpp
@@ -377,16 +377,31 @@ nsGNOMEShellService::SetShouldCheckDefau
     pserve->GetBranch("", getter_AddRefs(prefs));
 
   if (prefs)
     prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsGNOMEShellService::GetCanSetDesktopBackground(bool* aResult)
+{
+  // setting desktop background is currently only supported
+  // for Gnome or desktops using the same GSettings and GConf keys
+  const char* gnomeSession = getenv("GNOME_DESKTOP_SESSION_ID");
+  if (gnomeSession) {
+    *aResult = true;
+  } else {
+    *aResult = false;
+  }
+
+  return NS_OK;
+}
+
 static nsresult
 WriteImage(const nsCString& aPath, imgIContainer* aImage)
 {
 #ifndef MOZ_WIDGET_GTK2
   return NS_ERROR_NOT_AVAILABLE;
 #else
   nsCOMPtr<nsIImageToPixbuf> imgToPixbuf =
     do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1");
--- a/browser/components/shell/src/nsMacShellService.cpp
+++ b/browser/components/shell/src/nsMacShellService.cpp
@@ -152,16 +152,23 @@ nsMacShellService::SetShouldCheckDefault
     pserve->GetBranch("", getter_AddRefs(prefs));
 
   prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsMacShellService::GetCanSetDesktopBackground(bool* aResult)
+{
+  *aResult = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsMacShellService::SetDesktopBackground(nsIDOMElement* aElement, 
                                         PRInt32 aPosition)
 {
   // Note: We don't support aPosition on OS X.
 
   // Get the image URI:
   nsresult rv;
   nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement,
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -72,18 +72,16 @@
 
 #ifdef _WIN32_WINNT
 #undef _WIN32_WINNT
 #endif
 #define _WIN32_WINNT 0x0600
 #define INITGUID
 #include <shlobj.h>
 
-#pragma comment(lib, "shlwapi.lib") // for SHDeleteKeyW
-
 #include <mbstring.h>
 #include <shlwapi.h>
 
 #ifndef MAX_BUF
 #define MAX_BUF 4096
 #endif
 
 #define REG_SUCCEEDED(val) \
@@ -559,16 +557,23 @@ nsWindowsShellService::IsDefaultBrowser(
       *aIsDefaultBrowser = false;
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsWindowsShellService::GetCanSetDesktopBackground(bool* aResult)
+{
+  *aResult = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
 {
   nsAutoString appHelperPath;
   if (NS_FAILED(GetHelperPath(appHelperPath)))
     return NS_ERROR_FAILURE;
 
   if (aForAllUsers) {
     appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1470,8 +1470,9 @@ extensions/inspector@mozilla.org/compone
 extensions/inspector@mozilla.org/chrome/icons/default/winInspectorMain.ico
 components/nsPlacesTransactionsService.js
 components/browserplaces.xpt
 components/nsPlacesDBFlush.js
 #ifndef MOZ_MAINTENANCE_SERVICE
 maintenanceservice.exe
 maintenanceservice_installer.exe
 #endif
+jssubloader/
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -150,17 +150,18 @@ def build_one_stage_aux(stage_dir, is_st
                    "--with-gmp=%s" % lib_inst_dir,
                    "--with-mpfr=%s" % lib_inst_dir])
 
     tool_inst_dir = stage_dir + '/inst'
     build_linux_headers(tool_inst_dir)
 
     binutils_build_dir = stage_dir + '/binutils'
     build_package(binutils_source_dir, binutils_build_dir,
-                  ["--prefix=%s" % tool_inst_dir])
+                  ["--prefix=%s" % tool_inst_dir,
+                   "--without-zlib"])
 
     # During stage one we have to build gcc first, this glibc doesn't even
     # build with gcc 4.6. During stage two, we have to build glibc first.
     # The problem is that libstdc++ is built with xgcc and if glibc has
     # not been built yet xgcc will use the system one.
     if is_stage_one:
         build_gcc(stage_dir, is_stage_one)
         build_glibc({"CC"  : tool_inst_dir + "/bin/gcc",
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -89,18 +89,20 @@
 #include "nsAboutProtocolUtils.h"
 #include "nsIClassInfo.h"
 #include "nsIURIFixup.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIChromeRegistry.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/bindings/Utils.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nsnull;
 nsIXPConnect    *nsScriptSecurityManager::sXPConnect = nsnull;
 nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
 JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
@@ -2440,19 +2442,27 @@ nsScriptSecurityManager::doGetObjectPrin
                                               aAllowShortCircuit
 #else
                                               true
 #endif
                                               );
             if (result) {
                 break;
             }
-        } else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
-                                        JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
-            nsISupports *priv = (nsISupports *) js::GetObjectPrivate(aObj);
+        } else {
+            nsISupports *priv;
+            if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
+                                     JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
+                priv = (nsISupports *) js::GetObjectPrivate(aObj);
+            } else if ((jsClass->flags & JSCLASS_IS_DOMJSCLASS) &&
+                       bindings::DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
+                priv = bindings::UnwrapDOMObject<nsISupports>(aObj, jsClass);
+            } else {
+                priv = nsnull;
+            }
 
 #ifdef DEBUG
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
                              !strcmp(jsClass->name, "XPCNativeWrapper"),
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/741163-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+
+var xhr = new XMLHttpRequest();
+xhr.onreadystatechange;
+
+</script>
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -101,8 +101,9 @@ load 698974-1.html
 load 700090-1.html
 load 700090-2.html
 load 700512.html
 load xhr_html_nullresponse.html
 load 709384.html
 load 713417.html
 load 713417-2.html
 load 715056.html
+load 741163-1.html
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -52,17 +52,16 @@ nsIAttribute.h \
 nsIContentIterator.h \
 nsContentErrors.h \
 nsContentPolicyUtils.h \
 nsContentUtils.h \
 nsIDocument.h \
 nsDeprecatedOperationList.h \
 nsIDocumentObserver.h \
 nsIMutationObserver.h \
-nsIMutationObserver2.h \
 nsINameSpaceManager.h \
 nsINode.h \
 nsINodeInfo.h \
 nsINodeList.h \
 nsIScriptElement.h \
 nsIStyleSheetLinkingElement.h \
 nsIContentSerializer.h \
 nsIXPathEvaluatorInternal.h \
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -246,30 +246,16 @@ public:
   static nsresult Init();
 
   /**
    * Get a JSContext from the document's scope object.
    */
   static JSContext* GetContextFromDocument(nsIDocument *aDocument);
 
   /**
-   * Get a scope from aNewDocument. Also get a context through the scope of one
-   * of the documents, from the stack or the safe context.
-   *
-   * @param aOldDocument The document to try to get a context from. May be null.
-   * @param aNewDocument The document to get aNewScope from.
-   * @param aCx [out] Context gotten through one of the scopes, from the stack
-   *                  or the safe context.
-   * @param aNewScope [out] Scope gotten from aNewDocument.
-   */
-  static nsresult GetContextAndScope(nsIDocument *aOldDocument,
-                                     nsIDocument *aNewDocument,
-                                     JSContext **aCx, JSObject **aNewScope);
-
-  /**
    * When a document's scope changes (e.g., from document.open(), call this
    * function to move all content wrappers from the old scope to the new one.
    */
   static nsresult ReparentContentWrappersInScope(JSContext *cx,
                                                  nsIScriptGlobalObject *aOldScope,
                                                  nsIScriptGlobalObject *aNewScope);
 
   static bool     IsCallerChrome();
@@ -463,16 +449,18 @@ public:
 
   static void Shutdown();
 
   /**
    * Checks whether two nodes come from the same origin.
    */
   static nsresult CheckSameOrigin(nsINode* aTrustedNode,
                                   nsIDOMNode* aUnTrustedNode);
+  static nsresult CheckSameOrigin(nsINode* aTrustedNode,
+                                  nsINode* unTrustedNode);
 
   // Check if the (JS) caller can access aNode.
   static bool CanCallerAccess(nsIDOMNode *aNode);
 
   // Check if the (JS) caller can access aWindow.
   // aWindow can be either outer or inner window.
   static bool CanCallerAccess(nsPIDOMWindow* aWindow);
 
@@ -1547,16 +1535,25 @@ public:
    * which places the viewport information in the document header instead
    * of returning it directly.
    *
    * NOTE: If the site is optimized for mobile (via the doctype), this
    * will return viewport information that specifies default information.
    */
   static ViewportInfo GetViewportInfo(nsIDocument* aDocument);
 
+  // Call EnterMicroTask when you're entering JS execution.
+  // Usually the best way to do this is to use nsAutoMicroTask.
+  static void EnterMicroTask() { ++sMicroTaskLevel; }
+  static void LeaveMicroTask();
+
+  static bool IsInMicroTask() { return sMicroTaskLevel != 0; }
+  static PRUint32 MicroTaskLevel() { return sMicroTaskLevel; }
+  static void SetMicroTaskLevel(PRUint32 aLevel) { sMicroTaskLevel = aLevel; }
+
   /* Process viewport META data. This gives us information for the scale
    * and zoom of a page on mobile devices. We stick the information in
    * the document header and use it later on after rendering.
    *
    * See Bug #436083
    */
   static nsresult ProcessViewportInfo(nsIDocument *aDocument,
                                       const nsAString &viewportInfo);
@@ -1628,17 +1625,20 @@ public:
   // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
   static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
   static nsIInterfaceRequestor* GetSameOriginChecker();
 
   static nsIThreadJSContextStack* ThreadJSContextStack()
   {
     return sThreadJSContextStack;
   }
-  
+
+  // Trace the safe JS context of the ThreadJSContextStack.
+  static void TraceSafeJSContext(JSTracer* aTrc);
+
 
   /**
    * Get the Origin of the passed in nsIPrincipal or nsIURI. If the passed in
    * nsIURI or the URI of the passed in nsIPrincipal does not have a host, the
    * origin is set to 'null'.
    *
    * The ASCII versions return a ASCII strings that are puny-code encoded,
    * suitable for, for example, header values. The UTF versions return strings
@@ -1948,16 +1948,23 @@ public:
                                 bool aSetUpForAboutBlank);
 
   static nsresult Btoa(const nsAString& aBinaryData,
                        nsAString& aAsciiBase64String);
 
   static nsresult Atob(const nsAString& aAsciiString,
                        nsAString& aBinaryData);
 
+  /** If aJSArray is a Javascript array, this method iterates over its
+   *  elements and appends values to aRetVal as nsIAtoms.
+   *  @throw NS_ERROR_ILLEGAL_VALUE if aJSArray isn't a JS array.
+   */ 
+  static nsresult JSArrayToAtomArray(JSContext* aCx, const JS::Value& aJSArray,
+                                     nsCOMArray<nsIAtom>& aRetVal);
+
   /**
    * Returns whether the input element passed in parameter has the autocomplete
    * functionnality enabled. It is taking into account the form owner.
    * NOTE: the caller has to make sure autocomplete makes sense for the
    * element's type.
    *
    * @param aInput the input element to check. NOTE: aInput can't be null.
    * @return whether the input element has autocomplete enabled.
@@ -2074,16 +2081,17 @@ private:
   static nsIBidiKeyboard* sBidiKeyboard;
 #endif
 
   static bool sInitialized;
   static PRUint32 sScriptBlockerCount;
 #ifdef DEBUG
   static PRUint32 sDOMNodeRemovedSuppressCount;
 #endif
+  static PRUint32 sMicroTaskLevel;
   // Not an nsCOMArray because removing elements from those is slower
   static nsTArray< nsCOMPtr<nsIRunnable> >* sBlockedScriptRunners;
   static PRUint32 sRunnersCountAtFirstBlocker;
   static PRUint32 sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static bool sIsHandlingKeyBoardEvent;
@@ -2176,16 +2184,29 @@ public:
   }
   ~nsAutoScriptBlockerSuppressNodeRemoved() {
 #ifdef DEBUG
     --nsContentUtils::sDOMNodeRemovedSuppressCount;
 #endif
   }
 };
 
+class NS_STACK_CLASS nsAutoMicroTask
+{
+public:
+  nsAutoMicroTask()
+  {
+    nsContentUtils::EnterMicroTask();
+  }
+  ~nsAutoMicroTask()
+  {
+    nsContentUtils::LeaveMicroTask();
+  }
+};
+
 #define NS_INTERFACE_MAP_ENTRY_TEAROFF(_interface, _allocator)                \
   if (aIID.Equals(NS_GET_IID(_interface))) {                                  \
     foundInterface = static_cast<_interface *>(_allocator);                   \
     if (!foundInterface) {                                                    \
       *aInstancePtr = nsnull;                                                 \
       return NS_ERROR_OUT_OF_MEMORY;                                          \
     }                                                                         \
   } else
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -120,18 +120,18 @@ class Loader;
 
 namespace dom {
 class Link;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0x283ec27d, 0x5b23, 0x49b2, \
-  { 0x94, 0xd9, 0x9, 0xb5, 0xdb, 0x45, 0x30, 0x73 } }
+{ 0x8e51e6d9, 0x914d, 0x46ba, \
+  { 0xb3, 0x11, 0x2f, 0x27, 0x3d, 0xe6, 0x0d, 0x19 } }
 
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
@@ -178,19 +178,20 @@ public:
       mPartID(0)
   {
     SetInDocument();
   }
 #endif
   
   /**
    * Let the document know that we're starting to load data into it.
-   * @param aCommand The parser command
+   * @param aCommand The parser command. Must not be null.
    *                 XXXbz It's odd to have that here.
-   * @param aChannel The channel the data will come from
+   * @param aChannel The channel the data will come from. The channel must be
+   *                 able to report its Content-Type.
    * @param aLoadGroup The loadgroup this document should use from now on.
    *                   Note that the document might not be the only thing using
    *                   this loadgroup.
    * @param aContainer The container this document is in.  This may be null.
    *                   XXXbz maybe we should make it more explicit (eg make the
    *                   container an nsIWebNavigation or nsIDocShell or
    *                   something)?
    * @param [out] aDocListener the listener to pump data from the channel into.
@@ -199,16 +200,19 @@ public:
    *                           documents.
    * @param aReset whether the document should call Reset() on itself.  If this
    *               is false, the document will NOT set its principal to the
    *               channel's owner, will not clear any event listeners that are
    *               already set on it, etc.
    * @param aSink The content sink to use for the data.  If this is null and
    *              the document needs a content sink, it will create one based
    *              on whatever it knows about the data it's going to load.
+   *              This MUST be null if the underlying document is an HTML
+   *              document. Even in the XML case, please don't add new calls
+   *              with non-null sink.
    *
    * Once this has been called, the document will return false for
    * MayStartLayout() until SetMayStartLayout(true) is called on it.  Making
    * sure this happens is the responsibility of the caller of
    * StartDocumentLoad().
    */  
   virtual nsresult StartDocumentLoad(const char* aCommand,
                                      nsIChannel* aChannel,
@@ -1633,16 +1637,40 @@ public:
   // only appear at the top of the DOM tree, we have a specialized measurement
   // function which returns multiple sizes.
   virtual void DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const;
   // DocSizeOfIncludingThis doesn't need to be overridden by sub-classes
   // because nsIDocument inherits from nsINode;  see the comment above the
   // declaration of nsINode::SizeOfIncludingThis.
   virtual void DocSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;
 
+  PRBool MayHaveDOMMutationObservers()
+  {
+    return mMayHaveDOMMutationObservers;
+  }
+
+  void SetMayHaveDOMMutationObservers()
+  {
+    mMayHaveDOMMutationObservers = true;
+  }
+
+  bool IsInSyncOperation()
+  {
+    return mInSyncOperationCount != 0;
+  }
+
+  void SetIsInSyncOperation(bool aSync)
+  {
+    if (aSync) {
+      ++mInSyncOperationCount;
+    } else {
+      --mInSyncOperationCount;
+    }
+  }
+
 private:
   PRUint64 mWarnedAbout;
 
 protected:
   ~nsIDocument()
   {
     // XXX The cleanup of mNodeInfoManager (calling DropDocumentReference and
     //     releasing it) happens in the nsDocument destructor. We'd prefer to
@@ -1804,16 +1832,19 @@ protected:
   bool mHasLinksToUpdate;
 
   // True if a layout flush might not be a no-op
   bool mNeedLayoutFlush;
 
   // True if a style flush might not be a no-op
   bool mNeedStyleFlush;
 
+  // True if a DOMMutationObserver is perhaps attached to a node in the document.
+  bool mMayHaveDOMMutationObservers;
+
   // The document's script global object, the object from which the
   // document can get its script context and scope. This is the
   // *inner* window object.
   nsCOMPtr<nsIScriptGlobalObject> mScriptGlobalObject;
 
   // If mIsStaticDocument is true, mOriginalDocument points to the original
   // document.
   nsCOMPtr<nsIDocument> mOriginalDocument;
@@ -1899,16 +1930,18 @@ protected:
 
   // Our base target.
   nsString mBaseTarget;
 
   nsCOMPtr<nsIStructuredCloneContainer> mStateObjectContainer;
   nsCOMPtr<nsIVariant> mStateObjectCached;
 
   PRUint8 mDefaultElementType;
+
+  PRUint32 mInSyncOperationCount;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
 /**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
@@ -1945,16 +1978,26 @@ public:
     }
   }
 
 private:
   nsCOMPtr<nsINode>     mTarget;
   nsCOMPtr<nsIDocument> mSubtreeOwner;
 };
 
+class NS_STACK_CLASS nsAutoSyncOperation
+{
+public:
+  nsAutoSyncOperation(nsIDocument* aDocument);
+  ~nsAutoSyncOperation();
+private:
+  nsCOMArray<nsIDocument> mDocuments;
+  PRUint32                mMicroTaskLevel;
+};
+
 // XXX These belong somewhere else
 nsresult
 NS_NewHTMLDocument(nsIDocument** aInstancePtrResult);
 
 nsresult
 NS_NewXMLDocument(nsIDocument** aInstancePtrResult);
 
 nsresult
--- a/content/base/public/nsIDocumentEncoder.idl
+++ b/content/base/public/nsIDocumentEncoder.idl
@@ -233,16 +233,22 @@ interface nsIDocumentEncoder : nsISuppor
   /**
    * Output for delsp=yes (RFC 3676). This is used with OutputFormatFlowed
    * when converting to text for mail sending.
    * PlainText output only.
    */
   const unsigned long OutputFormatDelSp  = (1 << 20);
  
   /**
+   * Drop <br> elements considered "invisible" by the editor. OutputPreformatted
+   * implies this flag.
+   */
+  const unsigned long OutputDropInvisibleBreak = (1 << 21);
+
+  /**
    * Initialize with a pointer to the document and the mime type.
    * @param aDocument Document to encode.
    * @param aMimeType MimeType to use. May also be set by SetMimeType.
    * @param aFlags Flags to use while encoding. May also be set by SetFlags.
    */
   void init(in nsIDOMDocument aDocument,
             in AString aMimeType,
             in unsigned long aFlags);
deleted file mode 100644
--- a/content/base/public/nsIMutationObserver2.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Mounir Lamouri <mounir.lamouri@mozilla.com> (Original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsIMutationObserver2_h___
-#define nsIMutationObserver2_h___
-
-#include "nsIMutationObserver.h"
-
-class nsIContent;
-class nsINode;
-
-#define NS_IMUTATION_OBSERVER_2_IID \
-{0x61ac1cfd, 0xf3ef, 0x4408, \
-  {0x8a, 0x72, 0xee, 0xf0, 0x41, 0xbe, 0xc7, 0xe9 } }
-
-/**
- * Mutation observer interface 2 is adding AttributeChildRemoved to
- * nsIMutationObserver.
- *
- * @see nsIMutationObserver.
- */
-class nsIMutationObserver2 : public nsIMutationObserver
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMUTATION_OBSERVER_2_IID)
-
-  /**
-   * Notification that an attribute's child has been removed.
-   *
-   * @param aContainer The attribute that had its child removed.
-   * @param aChild     The child that was removed.
-   *
-   * @note Attributes can't have more than one child so it will be always the
-   *       first one being removed.
-   */
-  virtual void AttributeChildRemoved(nsINode* aAttribute,
-                                     nsIContent* aChild) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver2, NS_IMUTATION_OBSERVER_2_IID)
-
-#define NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED                \
-    virtual void AttributeChildRemoved(nsINode* aAttribute,               \
-                                       nsIContent* aChild);
-
-#define NS_DECL_NSIMUTATIONOBSERVER2                                      \
-    NS_DECL_NSIMUTATIONOBSERVER                                           \
-    NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED
-
-#define NS_IMPL_NSIMUTATIONOBSERVER2_CONTENT(_class)                      \
-NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(_class)                               \
-void                                                                      \
-_class::AttributeChildRemoved(nsINode* aAttribute, nsIContent *aChild)    \
-{                                                                         \
-}
-
-
-#endif /* nsIMutationObserver2_h___ */
-
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -173,36 +173,20 @@ enum {
   NODE_HAS_ACCESSKEY           = 0x00020000U,
 
   // Set if the node is handling a click.
   NODE_HANDLING_CLICK          = 0x00040000U,
 
   // Set if the node has had :hover selectors matched against it
   NODE_HAS_RELEVANT_HOVER_RULES = 0x00080000U,
 
-  // Two bits for the script-type ID.  Not enough to represent all
-  // nsIProgrammingLanguage values, but we don't care.  In practice,
-  // we can represent the ones we want, and we can fail the others at
-  // runtime.
-  NODE_SCRIPT_TYPE_OFFSET =               20,
-
-  NODE_SCRIPT_TYPE_SIZE =                  2,
-
-  NODE_SCRIPT_TYPE_MASK =  (1 << NODE_SCRIPT_TYPE_SIZE) - 1,
-
   // Remaining bits are node type specific.
-  NODE_TYPE_SPECIFIC_BITS_OFFSET =
-    NODE_SCRIPT_TYPE_OFFSET + NODE_SCRIPT_TYPE_SIZE
+  NODE_TYPE_SPECIFIC_BITS_OFFSET =        20
 };
 
-PR_STATIC_ASSERT(PRUint32(nsIProgrammingLanguage::JAVASCRIPT) <=
-                   PRUint32(NODE_SCRIPT_TYPE_MASK));
-PR_STATIC_ASSERT(PRUint32(nsIProgrammingLanguage::PYTHON) <=
-                   PRUint32(NODE_SCRIPT_TYPE_MASK));
-
 // Useful inline function for getting a node given an nsIContent and an
 // nsIDocument.  Returns the first argument cast to nsINode if it is non-null,
 // otherwise returns the second (which may be null).  We use type variables
 // instead of nsIContent* and nsIDocument* because the actual types must be
 // known for the cast to work.
 template<class C, class D>
 inline nsINode* NODE_FROM(C& aContent, D& aDocument)
 {
@@ -286,18 +270,18 @@ private:
 // Categories of node properties
 // 0 is global.
 #define DOM_USER_DATA         1
 #define DOM_USER_DATA_HANDLER 2
 #define SMIL_MAPPED_ATTR_ANIMVAL 3
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0x458300ed, 0xe418, 0x4577, \
-  { 0x89, 0xd7, 0xfe, 0xf1, 0x34, 0xf3, 0x52, 0x19 } }
+{ 0x772e7e52, 0xfadf, 0x4962, \
+  { 0x8d, 0x96, 0x58, 0xfe, 0x75, 0x68, 0xaf, 0xa8 } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public nsIDOMEventTarget,
                 public nsWrapperCache
@@ -1038,32 +1022,16 @@ public:
   }
 
   /**
    * Implementation is in nsIDocument.h, because it needs to cast from
    * nsIDocument* to nsINode*.
    */
   nsIDocument* GetOwnerDocument() const;
 
-  /**
-   * The default script type (language) ID for this node.
-   * All nodes must support fetching the default script language.
-   */
-  virtual PRUint32 GetScriptTypeID() const
-  { return nsIProgrammingLanguage::JAVASCRIPT; }
-
-  /**
-   * Not all nodes support setting a new default language.
-   */
-  NS_IMETHOD SetScriptTypeID(PRUint32 aLang)
-  {
-    NS_NOTREACHED("SetScriptTypeID not implemented");
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-
   nsresult Normalize();
 
   /**
    * Get the base URI for any relative URIs within this piece of
    * content. Generally, this is the document's base URI, but certain
    * content carries a local base for backward compatibility, and XML
    * supports setting a per-node base URI.
    *
@@ -1322,16 +1290,18 @@ private:
     NodeIsCCBlackTree,
     // Maybe set if the node is a root of a subtree 
     // which needs to be kept in the purple buffer.
     NodeIsPurpleRoot,
     // Set if the node has an explicit base URI stored
     NodeHasExplicitBaseURI,
     // Set if the element has some style states locked
     ElementHasLockedStyleStates,
+    // Set if the node may have DOMMutationObserver attached to it.
+    NodeMayHaveDOMMutationObserver,
     // Guard value
     BooleanFlagCount
   };
 
   void SetBoolFlag(BooleanFlag name, bool value) {
     PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
     mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
   }
@@ -1378,17 +1348,20 @@ public:
     { SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
   bool CCMarkedRoot() const { return GetBoolFlag(NodeIsCCMarkedRoot); }
   void SetInCCBlackTree(bool aValue)
     { SetBoolFlag(NodeIsCCBlackTree, aValue); }
   bool InCCBlackTree() const { return GetBoolFlag(NodeIsCCBlackTree); }
   void SetIsPurpleRoot(bool aValue)
     { SetBoolFlag(NodeIsPurpleRoot, aValue); }
   bool IsPurpleRoot() const { return GetBoolFlag(NodeIsPurpleRoot); }
-
+  bool MayHaveDOMMutationObserver()
+    { return GetBoolFlag(NodeMayHaveDOMMutationObserver); }
+  void SetMayHaveDOMMutationObserver()
+    { SetBoolFlag(NodeMayHaveDOMMutationObserver, true); }
   bool HasListenerManager() { return HasFlag(NODE_HAS_LISTENERMANAGER); }
 protected:
   void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
   void SetInDocument() { SetBoolFlag(IsInDocument); }
   void ClearInDocument() { ClearBoolFlag(IsInDocument); }
   void SetIsElement() { SetBoolFlag(NodeIsElement); }
   void ClearIsElement() { ClearBoolFlag(NodeIsElement); }
   void SetHasID() { SetBoolFlag(ElementHasID); }
@@ -1416,16 +1389,22 @@ protected:
   {
     mSubtreeRoot = nsnull;
   }
 
 public:
   // Optimized way to get classinfo.
   virtual nsXPCClassInfo* GetClassInfo() = 0;
 
+  // Makes nsINode object to keep aObject alive.
+  void BindObject(nsISupports* aObject);
+  // After calling UnbindObject nsINode object doesn't keep
+  // aObject alive anymore.
+  void UnbindObject(nsISupports* aObject);
+
   /**
    * Returns the length of this node, as specified at
    * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
    */
   PRUint32 Length() const;
 
 protected:
 
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -150,16 +150,17 @@ CPPSRCS		= \
 		nsXMLNameSpaceMap.cpp \
 		Link.cpp \
 		nsBlobProtocolHandler.cpp \
 		nsFrameMessageManager.cpp \
 		nsInProcessTabChildGlobal.cpp \
 		ThirdPartyUtil.cpp \
 		nsEventSource.cpp \
 		FileIOObject.cpp \
+		nsDOMMutationObserver.cpp \
 		$(NULL)
 
 # Are we targeting x86-32 or x86-64?  If so, we want to include SSE2 code for
 # nsTextFragment.cpp
 ifneq (,$(INTEL_ARCHITECTURE))
 CPPSRCS += nsTextFragmentSSE2.cpp
 endif
 
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -398,9 +398,12 @@ mozilla::dom::TraceBlackJS(JSTracer* aTr
   }
 
   // Mark globals of active windows black.
   nsGlobalWindow::WindowByIdTable* windowsById =
     nsGlobalWindow::GetWindowsTable();
   if (windowsById) {
     windowsById->Enumerate(TraceActiveWindowGlobal, aTrc);
   }
+
+  // Mark the safe context black
+  nsContentUtils::TraceSafeJSContext(aTrc);
 }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -203,16 +203,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #endif
 #include "nsDOMTouchEvent.h"
 #include "nsIScriptElement.h"
 #include "nsIContentViewer.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsCCUncollectableMarker.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Preferences.h"
+#include "nsDOMMutationObserver.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 
 extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
                                       const char** next, PRUnichar* result);
@@ -266,16 +267,17 @@ nsIWordBreaker *nsContentUtils::sWordBre
 PRUint32 nsContentUtils::sJSGCThingRootCount;
 #ifdef IBMBIDI
 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
 #endif
 PRUint32 nsContentUtils::sScriptBlockerCount = 0;
 #ifdef DEBUG
 PRUint32 nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
 #endif
+PRUint32 nsContentUtils::sMicroTaskLevel = 0;
 nsTArray< nsCOMPtr<nsIRunnable> >* nsContentUtils::sBlockedScriptRunners = nsnull;
 PRUint32 nsContentUtils::sRunnersCountAtFirstBlocker = 0;
 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nsnull;
 
 bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
 bool nsContentUtils::sAllowXULXBL_for_file = false;
 
 nsString* nsContentUtils::sShiftText = nsnull;
@@ -1461,35 +1463,44 @@ nsContentUtils::CallerHasUniversalXPConn
  * Never call this function with the first node provided by script, it
  * must always be known to be a 'real' node!
  */
 // static
 nsresult
 nsContentUtils::CheckSameOrigin(nsINode *aTrustedNode,
                                 nsIDOMNode *aUnTrustedNode)
 {
-  NS_PRECONDITION(aTrustedNode, "There must be a trusted node");
+  MOZ_ASSERT(aTrustedNode);
+
+  // Make sure it's a real node.
+  nsCOMPtr<nsINode> unTrustedNode = do_QueryInterface(aUnTrustedNode);
+  NS_ENSURE_TRUE(unTrustedNode, NS_ERROR_UNEXPECTED);
+  return CheckSameOrigin(aTrustedNode, unTrustedNode);
+}
+
+nsresult
+nsContentUtils::CheckSameOrigin(nsINode* aTrustedNode,
+                                nsINode* unTrustedNode)
+{
+  MOZ_ASSERT(aTrustedNode);
+  MOZ_ASSERT(unTrustedNode);
 
   bool isSystem = false;
   nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&isSystem);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (isSystem) {
     // we're running as system, grant access to the node.
 
     return NS_OK;
   }
 
   /*
    * Get hold of each node's principal
    */
-  nsCOMPtr<nsINode> unTrustedNode = do_QueryInterface(aUnTrustedNode);
-
-  // Make sure these are both real nodes
-  NS_ENSURE_TRUE(aTrustedNode && unTrustedNode, NS_ERROR_UNEXPECTED);
 
   nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal();
   nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal();
 
   if (trustedPrincipal == unTrustedPrincipal) {
     return NS_OK;
   }
 
@@ -1600,72 +1611,31 @@ nsContentUtils::GetContextFromDocument(n
   if (!scx) {
     // No context left in the scope...
     return nsnull;
   }
 
   return scx->GetNativeContext();
 }
 
-// static
-nsresult
-nsContentUtils::GetContextAndScope(nsIDocument *aOldDocument,
-                                   nsIDocument *aNewDocument, JSContext **aCx,
-                                   JSObject **aNewScope)
-{
-  *aCx = nsnull;
-  *aNewScope = nsnull;
-
-  JSObject *newScope = aNewDocument->GetWrapper();
-  JSObject *global;
-  if (!newScope) {
-    nsIScriptGlobalObject *newSGO = aNewDocument->GetScopeObject();
-    if (!newSGO || !(global = newSGO->GetGlobalJSObject())) {
-      return NS_OK;
-    }
-  }
-
-  NS_ENSURE_TRUE(sXPConnect, NS_ERROR_NOT_INITIALIZED);
-
-  JSContext *cx = aOldDocument ? GetContextFromDocument(aOldDocument) : nsnull;
+//static
+void
+nsContentUtils::TraceSafeJSContext(JSTracer* aTrc)
+{
+  if (!sThreadJSContextStack) {
+    return;
+  }
+  JSContext* cx = nsnull;
+  sThreadJSContextStack->GetSafeJSContext(&cx);
   if (!cx) {
-    cx = GetContextFromDocument(aNewDocument);
-
-    if (!cx) {
-      // No context reachable from the old or new document, use the
-      // calling context, or the safe context if no caller can be
-      // found.
-
-      sThreadJSContextStack->Peek(&cx);
-
-      if (!cx) {
-        sThreadJSContextStack->GetSafeJSContext(&cx);
-
-        if (!cx) {
-          // No safe context reachable, bail.
-          NS_WARNING("No context reachable in GetContextAndScopes()!");
-
-          return NS_ERROR_NOT_AVAILABLE;
-        }
-      }
-    }
-  }
-
-  if (!newScope && cx) {
-    jsval v;
-    nsresult rv = WrapNative(cx, global, aNewDocument, aNewDocument, &v);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    newScope = JSVAL_TO_OBJECT(v);
-  }
-
-  *aCx = cx;
-  *aNewScope = newScope;
-
-  return NS_OK;
+    return;
+  }
+  if (JSObject* global = JS_GetGlobalObject(cx)) {
+    JS_CALL_OBJECT_TRACER(aTrc, global, "safe context");
+  }
 }
 
 nsresult
 nsContentUtils::ReparentContentWrappersInScope(JSContext *cx,
                                                nsIScriptGlobalObject *aOldScope,
                                                nsIScriptGlobalObject *aNewScope)
 {
   JSObject *oldScopeObj = aOldScope->GetGlobalJSObject();
@@ -4175,16 +4145,17 @@ nsContentUtils::SetNodeTextContent(nsICo
       }
     }
   }
 
   // Might as well stick a batch around this since we're performing several
   // mutations.
   mozAutoDocUpdate updateBatch(aContent->GetCurrentDoc(),
     UPDATE_CONTENT_MODEL, true);
+  nsAutoMutationBatch mb;
 
   PRUint32 childCount = aContent->GetChildCount();
 
   if (aTryReuse && !aValue.IsEmpty()) {
     PRUint32 removeIndex = 0;
 
     for (PRUint32 i = 0; i < childCount; ++i) {
       nsIContent* child = aContent->GetChildAt(removeIndex);
@@ -4199,33 +4170,37 @@ nsContentUtils::SetNodeTextContent(nsICo
       }
     }
 
     if (removeIndex == 1) {
       return NS_OK;
     }
   }
   else {
+    mb.Init(aContent, true, false);
     for (PRUint32 i = 0; i < childCount; ++i) {
       aContent->RemoveChildAt(0, true);
     }
   }
+  mb.RemovalDone();
 
   if (aValue.IsEmpty()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIContent> textContent;
   nsresult rv = NS_NewTextNode(getter_AddRefs(textContent),
                                aContent->NodeInfo()->NodeInfoManager());
   NS_ENSURE_SUCCESS(rv, rv);
 
   textContent->SetText(aValue, true);
 
-  return aContent->AppendChildTo(textContent, true);
+  rv = aContent->AppendChildTo(textContent, true);
+  mb.NodesAdded();
+  return rv;
 }
 
 static void AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult)
 {
   for (nsIContent* child = aNode->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     if (child->IsElement()) {
@@ -4768,16 +4743,24 @@ nsContentUtils::AddScriptRunner(nsIRunna
   }
   
   nsCOMPtr<nsIRunnable> run = aRunnable;
   run->Run();
 
   return true;
 }
 
+void
+nsContentUtils::LeaveMicroTask()
+{
+  if (--sMicroTaskLevel == 0) {
+    nsDOMMutationObserver::HandleMutations();
+  }
+}
+
 /* 
  * Helper function for nsContentUtils::ProcessViewportInfo.
  *
  * Handles a single key=value pair. If it corresponds to a valid viewport
  * attribute, add it to the document header data. No validation is done on the
  * value itself (this is done at display time).
  */
 static void ProcessViewportToken(nsIDocument *aDocument, 
@@ -6558,26 +6541,27 @@ nsContentUtils::GetRootDocument(nsIDocum
 }
 
 // static
 void
 nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder,
                                nsWrapperCache* aCache)
 {
   if (aCache->PreservingWrapper()) {
+    // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
+    // can also be in the DOM expando hash, so we need to try to remove them
+    // from both here.
     JSObject* obj = aCache->GetWrapperPreserveColor();
-    if (aCache->IsDOMBinding()) {
+    if (aCache->IsDOMBinding() && obj) {
       JSCompartment *compartment = js::GetObjectCompartment(obj);
       xpc::CompartmentPrivate *priv =
         static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
       priv->RemoveDOMExpandoObject(obj);
     }
-    else {
-      DropJSObjects(aScriptObjectHolder);
-    }
+    DropJSObjects(aScriptObjectHolder);
 
     aCache->SetPreservingWrapper(false);
   }
 }
 
 // static
 void
 nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
@@ -6586,8 +6570,51 @@ nsContentUtils::TraceWrapper(nsWrapperCa
   if (aCache->PreservingWrapper()) {
     JSObject *wrapper = aCache->GetWrapperPreserveColor();
     if (wrapper) {
       aCallback(nsIProgrammingLanguage::JAVASCRIPT, wrapper,
                 "Preserved wrapper", aClosure);
     }
   }
 }
+
+nsresult
+nsContentUtils::JSArrayToAtomArray(JSContext* aCx, const JS::Value& aJSArray,
+                                   nsCOMArray<nsIAtom>& aRetVal)
+{
+  JSAutoRequest ar(aCx);
+  if (!aJSArray.isObject()) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  
+  JSObject* obj = &aJSArray.toObject();
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(aCx, obj)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  
+  PRUint32 length;
+  if (!JS_IsArrayObject(aCx, obj) || !JS_GetArrayLength(aCx, obj, &length)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  JSString* str = nsnull;
+  JS::Anchor<JSString *> deleteProtector(str);
+  for (PRUint32 i = 0; i < length; ++i) {
+    jsval v;
+    if (!JS_GetElement(aCx, obj, i, &v) ||
+        !(str = JS_ValueToString(aCx, v))) {
+      return NS_ERROR_ILLEGAL_VALUE;
+    }
+
+    nsDependentJSString depStr;
+    if (!depStr.init(aCx, str)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    nsCOMPtr<nsIAtom> a = do_GetAtom(depStr);
+    if (!a) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    aRetVal.AppendObject(a);
+  }
+  return NS_OK;
+}
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -155,35 +155,45 @@ SelectionCopyHelper(nsISelection *aSel, 
     return rv;
 
   nsAutoString buffer, parents, info, textBuffer, plaintextBuffer;
 
   rv = docEncoder->EncodeToString(textBuffer);
   if (NS_FAILED(rv)) 
     return rv;
 
-  nsCOMPtr<nsIFormatConverter> htmlConverter;
-
-  // sometimes we also need the HTML version
+  // If the selection was in a text input, in textarea or in pre, the encoder
+  // already produced plain text. Otherwise,the encoder produced HTML. In that
+  // case, we need to create an additional plain text serialization and an
+  // addition HTML serialization that encodes context.
   if (bIsHTMLCopy) {
 
-    // this string may still contain HTML formatting, so we need to remove that too.
-    htmlConverter = do_CreateInstance(kHTMLConverterCID);
-    NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE);
+    // First, create the plain text serialization
+    mimeType.AssignLiteral("text/plain");
+
+    flags =
+      nsIDocumentEncoder::OutputSelectionOnly |
+      nsIDocumentEncoder::OutputAbsoluteLinks |
+      nsIDocumentEncoder::SkipInvisibleContent |
+      nsIDocumentEncoder::OutputDropInvisibleBreak |
+      (aFlags & nsIDocumentEncoder::OutputNoScriptContent);
 
-    nsCOMPtr<nsISupportsString> plainHTML = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
-    NS_ENSURE_TRUE(plainHTML, NS_ERROR_FAILURE);
-    plainHTML->SetData(textBuffer);
+    rv = docEncoder->Init(domDoc, mimeType, flags);
+    if (NS_FAILED(rv))
+      return rv;
 
-    nsCOMPtr<nsISupportsString> ConvertedData;
-    PRUint32 ConvertedLen;
-    rv = htmlConverter->Convert(kHTMLMime, plainHTML, textBuffer.Length() * 2, kUnicodeMime, getter_AddRefs(ConvertedData), &ConvertedLen);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = docEncoder->SetSelection(aSel);
+    if (NS_FAILED(rv))
+      return rv;
 
-    ConvertedData->GetData(plaintextBuffer);
+    rv = docEncoder->EncodeToString(plaintextBuffer);
+    if (NS_FAILED(rv))
+      return rv;
+
+    // Now create the version that shows HTML context
 
     mimeType.AssignLiteral(kHTMLMime);
 
     flags = aFlags;
 
     rv = docEncoder->Init(domDoc, mimeType, flags);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -203,17 +213,20 @@ SelectionCopyHelper(nsISelection *aSel, 
       return rv;
   }
 
   if ((doPutOnClipboard && clipboard) || aTransferable != nsnull) {
     // Create a transferable for putting data on the Clipboard
     nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID);
     if (trans) {
       if (bIsHTMLCopy) {
-        // set up the data converter
+        // Set up a format converter so that clipboard flavor queries work.
+        // This converter isn't really used for conversions.
+        nsCOMPtr<nsIFormatConverter> htmlConverter =
+          do_CreateInstance(kHTMLConverterCID);
         trans->SetConverter(htmlConverter);
 
         if (!buffer.IsEmpty()) {
           // Add the html DataFlavor to the transferable
           rv = AppendString(trans, buffer, kHTMLMime);
           NS_ENSURE_SUCCESS(rv, rv);
         }
 
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -65,79 +65,51 @@
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 bool nsDOMAttribute::sInitialized;
 
 nsDOMAttribute::nsDOMAttribute(nsDOMAttributeMap *aAttrMap,
                                already_AddRefed<nsINodeInfo> aNodeInfo,
                                const nsAString   &aValue, bool aNsAware)
-  : nsIAttribute(aAttrMap, aNodeInfo, aNsAware), mValue(aValue), mChild(nsnull)
+  : nsIAttribute(aAttrMap, aNodeInfo, aNsAware), mValue(aValue)
 {
   NS_ABORT_IF_FALSE(mNodeInfo, "We must get a nodeinfo here!");
   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ATTRIBUTE_NODE,
                     "Wrong nodeType");
 
   // We don't add a reference to our content. It will tell us
   // to drop our reference when it goes away.
-
-  EnsureChildState();
-
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    content->AddMutationObserver(this);
-  }
-}
-
-nsDOMAttribute::~nsDOMAttribute()
-{
-  if (mChild) {
-    static_cast<nsTextNode*>(mChild)->UnbindFromAttribute();
-    NS_RELEASE(mChild);
-    mFirstChild = nsnull;
-  }
-
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    content->RemoveMutationObserver(this);
-  }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMAttribute)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttribute)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 
   if (!nsINode::Traverse(tmp, cb)) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
-
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mChild)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMAttribute)
   nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttribute)
   nsINode::Unlink(tmp);
-  if (tmp->mChild) {
-    static_cast<nsTextNode*>(tmp->mChild)->UnbindFromAttribute();
-    NS_RELEASE(tmp->mChild);
-    tmp->mFirstChild = nsnull;
-  }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 DOMCI_NODE_DATA(Attr, nsDOMAttribute)
 
 // QueryInterface implementation for nsDOMAttribute
 NS_INTERFACE_TABLE_HEAD(nsDOMAttribute)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_NODE_INTERFACE_TABLE5(nsDOMAttribute, nsIDOMAttr, nsIAttribute, nsIDOMNode,
-                           nsIDOMEventTarget, nsIMutationObserver)
+  NS_NODE_INTERFACE_TABLE4(nsDOMAttribute, nsIDOMAttr, nsIAttribute, nsIDOMNode,
+                           nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttribute)
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
                                  new nsNodeSupportsWeakRefTearoff(this))
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
                                  new nsNode3Tearoff(this))
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Attr)
 NS_INTERFACE_MAP_END
 
@@ -149,28 +121,17 @@ void
 nsDOMAttribute::SetMap(nsDOMAttributeMap *aMap)
 {
   if (mAttrMap && !aMap && sInitialized) {
     // We're breaking a relationship with content and not getting a new one,
     // need to locally cache value. GetValue() does that.
     GetValue(mValue);
   }
 
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    content->RemoveMutationObserver(this);
-  }
-
   mAttrMap = aMap;
-
-  // If we have a new content, we sholud start listening to it.
-  content = GetContentInternal();
-  if (content) {
-    content->AddMutationObserver(this);
-  }
 }
 
 nsIContent*
 nsDOMAttribute::GetContent() const
 {
   return GetContentInternal();
 }
 
@@ -236,41 +197,28 @@ nsDOMAttribute::GetValue(nsAString& aVal
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::SetValue(const nsAString& aValue)
 {
-  nsresult rv = NS_OK;
   nsIContent* content = GetContentInternal();
-  if (content) {
-    nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
-    rv = content->SetAttr(mNodeInfo->NamespaceID(),
+  if (!content) {
+    mValue = aValue;
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
+  return content->SetAttr(mNodeInfo->NamespaceID(),
                           nameAtom,
                           mNodeInfo->GetPrefixAtom(),
                           aValue,
                           true);
-  }
-  else {
-    mValue = aValue;
-
-    if (mChild) {
-      if (mValue.IsEmpty()) {
-        doRemoveChild(true);
-      } else {
-        mChild->SetText(mValue, false);
-      }
-    } else {
-      EnsureChildState();
-    }
-  }
-
-  return rv;
 }
 
 
 NS_IMETHODIMP
 nsDOMAttribute::GetSpecified(bool* aSpecified)
 {
   NS_ENSURE_ARG_POINTER(aSpecified);
   OwnerDoc()->WarnOnceAbout(nsIDocument::eSpecified);
@@ -354,17 +302,17 @@ nsDOMAttribute::GetChildNodes(nsIDOMNode
   return nsINode::GetChildNodes(aChildNodes);
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::HasChildNodes(bool* aHasChildNodes)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eHasChildNodes);
 
-  *aHasChildNodes = mFirstChild != nsnull;
+  *aHasChildNodes = false;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::HasAttributes(bool* aHasAttributes)
 {
   NS_ENSURE_ARG_POINTER(aHasAttributes);
@@ -377,20 +325,16 @@ nsDOMAttribute::HasAttributes(bool* aHas
 
 NS_IMETHODIMP
 nsDOMAttribute::GetFirstChild(nsIDOMNode** aFirstChild)
 {
   *aFirstChild = nsnull;
 
   OwnerDoc()->WarnOnceAbout(nsIDocument::eFirstChild);
 
-  if (mFirstChild) {
-    CallQueryInterface(mFirstChild, aFirstChild);
-  }
-  
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::GetLastChild(nsIDOMNode** aLastChild)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eLastChild);
 
@@ -653,40 +597,36 @@ bool
 nsDOMAttribute::IsNodeOfType(PRUint32 aFlags) const
 {
     return !(aFlags & ~eATTRIBUTE);
 }
 
 PRUint32
 nsDOMAttribute::GetChildCount() const
 {
-  return mFirstChild ? 1 : 0;
+  return 0;
 }
 
 nsIContent *
 nsDOMAttribute::GetChildAt(PRUint32 aIndex) const
 {
-  return aIndex == 0 ? mFirstChild : nsnull;
+  return nsnull;
 }
 
 nsIContent * const *
 nsDOMAttribute::GetChildArray(PRUint32* aChildCount) const
 {
-  *aChildCount = GetChildCount();
-  return &mFirstChild;
+  *aChildCount = 0;
+  return NULL;
 }
 
 PRInt32
 nsDOMAttribute::IndexOf(nsINode* aPossibleChild) const
 {
-  if (!aPossibleChild || aPossibleChild != mFirstChild) {
-    return -1;
-  }
-
-  return 0;
+  return -1;
 }
 
 nsresult
 nsDOMAttribute::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                               bool aNotify)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
@@ -695,106 +635,28 @@ nsresult
 nsDOMAttribute::AppendChildTo(nsIContent* aKid, bool aNotify)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void
 nsDOMAttribute::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
-  if (aIndex != 0 || !mChild) {
-    return;
-  }
-
-  doRemoveChild(aNotify);
-
-  nsString nullString;
-  SetDOMStringToNull(nullString);
-  SetValue(nullString);
 }
 
 nsresult
 nsDOMAttribute::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   return NS_OK;
 }
 
 void
-nsDOMAttribute::EnsureChildState()
-{
-  NS_PRECONDITION(!mChild, "Someone screwed up");
-
-  nsAutoString value;
-  GetValue(value);
-
-  if (!value.IsEmpty()) {
-    NS_NewTextNode(&mChild, mNodeInfo->NodeInfoManager());
-
-    static_cast<nsTextNode*>(mChild)->BindToAttribute(this);
-    mFirstChild = mChild;
-
-    mChild->SetText(value, false);
-  }
-}
-
-void
-nsDOMAttribute::AttributeChanged(nsIDocument* aDocument,
-                                 Element* aElement,
-                                 PRInt32 aNameSpaceID,
-                                 nsIAtom* aAttribute,
-                                 PRInt32 aModType)
-{
-  nsIContent* content = GetContentInternal();
-  if (aElement != content) {
-    return;
-  }
-
-  if (aNameSpaceID != mNodeInfo->NamespaceID()) {
-    return;
-  }
-
-  nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
-  if (nameAtom != aAttribute) {
-    return;
-  }
-
-  nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
-  
-  // Just blow away our mChild and recreate it if needed
-  if (mChild) {
-    doRemoveChild(true);
-  }
-  EnsureChildState();
-}
-
-void
 nsDOMAttribute::Initialize()
 {
   sInitialized = true;
 }
 
 void
 nsDOMAttribute::Shutdown()
 {
   sInitialized = false;
 }
-
-void
-nsDOMAttribute::doRemoveChild(bool aNotify)
-{
-  NS_ASSERTION(mChild && mFirstChild, "Why are we here?");
-  NS_ASSERTION(mChild == mFirstChild, "Something got out of sync!");
-
-  nsRefPtr<nsTextNode> child = static_cast<nsTextNode*>(mChild);
-  nsMutationGuard::DidMutate();
-  mozAutoDocUpdate updateBatch(OwnerDoc(), UPDATE_CONTENT_MODEL, aNotify);
-
-  NS_RELEASE(mChild);
-  mFirstChild = nsnull;
-
-  if (aNotify) {
-    nsNodeUtils::AttributeChildRemoved(this, child);
-  }
-
-  child->UnbindFromAttribute();
-}
-
--- a/content/base/src/nsDOMAttribute.h
+++ b/content/base/src/nsDOMAttribute.h
@@ -51,25 +51,24 @@
 #include "nsINodeInfo.h"
 #include "nsDOMAttributeMap.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsStubMutationObserver.h"
 
 // Attribute helper class used to wrap up an attribute with a dom
 // object that implements nsIDOMAttr and nsIDOMNode
 class nsDOMAttribute : public nsIAttribute,
-                       public nsIDOMAttr,
-                       public nsStubMutationObserver
+                       public nsIDOMAttr
 {
 public:
   nsDOMAttribute(nsDOMAttributeMap* aAttrMap,
                  already_AddRefed<nsINodeInfo> aNodeInfo,
                  const nsAString& aValue,
                  bool aNsAware);
-  virtual ~nsDOMAttribute();
+  virtual ~nsDOMAttribute() {}
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   // nsIDOMNode interface
   NS_DECL_NSIDOMNODE
 
   // nsIDOMAttr interface
   NS_DECL_NSIDOMATTR
@@ -95,43 +94,29 @@ public:
   virtual already_AddRefed<nsIURI> GetBaseURI() const;
 
   static void Initialize();
   static void Shutdown();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDOMAttribute,
                                                          nsIAttribute)
 
-  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
-
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   virtual mozilla::dom::Element* GetNameSpaceElement()
   {
     return GetContentInternal();
   }
 
   static bool sInitialized;
 
 private:
   already_AddRefed<nsIAtom> GetNameAtom(nsIContent* aContent);
-
-  void EnsureChildState();
-
-  /**
-   * Really removing the attribute child (unbind and release).
-   */
-  void doRemoveChild(bool aNotify);
-
-  nsString mValue;
-  // XXX For now, there's only a single child - a text element
-  // representing the value.  This is strong ref, but we use a raw
-  // pointer so we can implement GetChildArray().
-  nsIContent* mChild;
-
   mozilla::dom::Element *GetContentInternal() const
   {
     return mAttrMap ? mAttrMap->GetContent() : nsnull;
   }
+
+  nsString mValue;
 };
 
 
 #endif /* nsDOMAttribute_h___ */
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -0,0 +1,844 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDOMMutationObserver.h"        
+#include "nsDOMClassInfoID.h"
+#include "nsIClassInfo.h"
+#include "nsIXPCScriptable.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsContentUtils.h"
+#include "nsThreadUtils.h"
+#include "nsIDOMMutationEvent.h"
+#include "nsTextFragment.h"
+#include "jsapi.h"
+#include "nsServiceManagerUtils.h"
+#include "DictionaryHelpers.h"
+
+nsCOMArray<nsIDOMMozMutationObserver>*
+  nsDOMMutationObserver::sScheduledMutationObservers = nsnull;
+
+nsIDOMMozMutationObserver* nsDOMMutationObserver::sCurrentObserver = nsnull;
+
+PRUint32 nsDOMMutationObserver::sMutationLevel = 0;
+PRUint64 nsDOMMutationObserver::sCount = 0;
+
+nsAutoTArray<nsCOMArray<nsIDOMMozMutationObserver>, 4>*
+nsDOMMutationObserver::sCurrentlyHandlingObservers = nsnull;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationRecord)
+
+DOMCI_DATA(MutationRecord, nsDOMMutationRecord)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationRecord)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMutationRecord)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MutationRecord)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationRecord)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationRecord)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMutationRecord)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTarget)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPreviousSibling)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNextSibling)
+  tmp->mAddedNodes = nsnull;
+  tmp->mRemovedNodes = nsnull;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationRecord)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTarget)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPreviousSibling)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNextSibling)
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAddedNodes");
+  cb.NoteXPCOMChild(static_cast<nsIDOMNodeList*>(tmp->mAddedNodes));
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRemovedNodes");
+  cb.NoteXPCOMChild(static_cast<nsIDOMNodeList*>(tmp->mRemovedNodes));
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetType(nsAString& aType)
+{
+  aType = mType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetTarget(nsIDOMNode** aTarget)
+{
+  nsCOMPtr<nsIDOMNode> n = do_QueryInterface(mTarget);
+  n.forget(aTarget);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetAddedNodes(nsIDOMNodeList** aAddedNodes)
+{
+  if (!mAddedNodes && mTarget) {
+    mAddedNodes = new nsSimpleContentList(mTarget);
+  }
+  NS_IF_ADDREF(*aAddedNodes = mAddedNodes);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetRemovedNodes(nsIDOMNodeList** aRemovedNodes)
+{
+  if (!mRemovedNodes && mTarget) {
+    mRemovedNodes = new nsSimpleContentList(mTarget);
+  }
+  NS_IF_ADDREF(*aRemovedNodes = mRemovedNodes);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetPreviousSibling(nsIDOMNode** aPreviousSibling)
+{
+  nsCOMPtr<nsIDOMNode> n = do_QueryInterface(mPreviousSibling);
+  *aPreviousSibling = n.forget().get();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetNextSibling(nsIDOMNode** aNextSibling)
+{
+  nsCOMPtr<nsIDOMNode> n = do_QueryInterface(mNextSibling);
+  *aNextSibling = n.forget().get();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetAttributeName(nsAString& aAttrName)
+{
+  aAttrName = mAttrName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetAttributeNamespace(nsAString& aAttrNamespace)
+{
+  aAttrNamespace = mAttrNamespace;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationRecord::GetOldValue(nsAString& aPrevValue)
+{
+  aPrevValue = mPrevValue;
+  return NS_OK;
+}
+
+// Observer
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsMutationReceiver)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMutationReceiver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMutationReceiver)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMutationReceiver)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+  NS_INTERFACE_MAP_ENTRY(nsMutationReceiver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsMutationReceiver)
+  tmp->Disconnect();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsMutationReceiver)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+
+void
+nsMutationReceiver::AttributeWillChange(nsIDocument* aDocument,
+                                        mozilla::dom::Element* aElement,
+                                        PRInt32 aNameSpaceID,
+                                        nsIAtom* aAttribute,
+                                        PRInt32 aModType)
+{
+  if (nsAutoMutationBatch::IsBatching() ||
+      !ObservesAttr(aElement, aNameSpaceID, aAttribute) ||
+      aElement->IsInNativeAnonymousSubtree()) {
+    return;
+  }
+
+  nsDOMMutationRecord* m =
+    Observer()->CurrentRecord(NS_LITERAL_STRING("attributes"));
+
+  NS_ASSERTION(!m->mTarget || m->mTarget == aElement,
+               "Wrong target!");
+  NS_ASSERTION(m->mAttrName.IsVoid() ||
+               m->mAttrName.Equals(nsDependentAtomString(aAttribute)),
+               "Wrong attribute!");
+  if (!m->mTarget) {
+    m->mTarget = aElement;
+    m->mAttrName = nsAtomString(aAttribute);
+    if (aNameSpaceID == kNameSpaceID_None) {
+      m->mAttrNamespace.SetIsVoid(true);
+    } else {
+      nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID,
+                                                          m->mAttrNamespace);
+    }
+  }
+
+  if (AttributeOldValue() && m->mPrevValue.IsVoid()) {
+    if (!aElement->GetAttr(aNameSpaceID, aAttribute, m->mPrevValue)) {
+      m->mPrevValue.SetIsVoid(true);
+    }
+  }
+}
+
+void
+nsMutationReceiver::CharacterDataWillChange(nsIDocument *aDocument,
+                                            nsIContent* aContent,
+                                            CharacterDataChangeInfo* aInfo)
+{
+  if (nsAutoMutationBatch::IsBatching() ||
+      !CharacterData() || !(Subtree() || aContent == Target()) ||
+      aContent->IsInNativeAnonymousSubtree()) {
+    return;
+  }
+  
+  nsDOMMutationRecord* m =
+    Observer()->CurrentRecord(NS_LITERAL_STRING("characterData"));
+ 
+  NS_ASSERTION(!m->mTarget || m->mTarget == aContent,
+               "Wrong target!");
+
+  if (!m->mTarget) {
+    m->mTarget = aContent;
+  }
+  if (CharacterDataOldValue() && m->mPrevValue.IsVoid()) { 
+    aContent->GetText()->AppendTo(m->mPrevValue);
+  }
+}
+
+void
+nsMutationReceiver::ContentAppended(nsIDocument* aDocument,
+                                    nsIContent* aContainer,
+                                    nsIContent* aFirstNewContent,
+                                    PRInt32 aNewIndexInContainer)
+{
+  nsINode* parent = NODE_FROM(aContainer, aDocument);
+  bool wantsChildList = ChildList() && (Subtree() || parent == Target());
+  if (!wantsChildList || aFirstNewContent->IsInNativeAnonymousSubtree()) {
+    return;
+  }
+
+  if (nsAutoMutationBatch::IsBatching()) {
+    if (parent == nsAutoMutationBatch::GetBatchTarget()) {
+      nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList);
+    }
+    return;
+  }
+
+  nsDOMMutationRecord* m =
+    Observer()->CurrentRecord(NS_LITERAL_STRING("childList"));
+  NS_ASSERTION(!m->mTarget || m->mTarget == parent,
+               "Wrong target!");
+  if (m->mTarget) {
+    // Already handled case.
+    return;
+  }
+  m->mTarget = parent;
+  m->mAddedNodes = new nsSimpleContentList(parent);
+
+  nsINode* n = aFirstNewContent;
+  while (n) {
+    m->mAddedNodes->AppendElement(static_cast<nsIContent*>(n));
+    n = n->GetNextSibling();
+  }
+  m->mPreviousSibling = aFirstNewContent->GetPreviousSibling();
+}
+
+void
+nsMutationReceiver::ContentInserted(nsIDocument* aDocument,
+                                    nsIContent* aContainer,
+                                    nsIContent* aChild,
+                                    PRInt32 aIndexInContainer)
+{
+  nsINode* parent = NODE_FROM(aContainer, aDocument);
+  bool wantsChildList = ChildList() && (Subtree() || parent == Target());
+  if (!wantsChildList || aChild->IsInNativeAnonymousSubtree()) {
+    return;
+  }
+
+  if (nsAutoMutationBatch::IsBatching()) {
+    if (parent == nsAutoMutationBatch::GetBatchTarget()) {
+      nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList);
+    }
+    return;
+  }
+
+  nsDOMMutationRecord* m =
+    Observer()->CurrentRecord(NS_LITERAL_STRING("childList"));
+  if (m->mTarget) {
+    // Already handled case.
+    return;  
+  }
+  m->mTarget = parent;
+  m->mAddedNodes = new nsSimpleContentList(parent);
+  m->mAddedNodes->AppendElement(aChild);
+  m->mPreviousSibling = aChild->GetPreviousSibling();
+  m->mNextSibling = aChild->GetNextSibling();
+}
+
+void
+nsMutationReceiver::ContentRemoved(nsIDocument* aDocument,
+                                   nsIContent* aContainer,
+                                   nsIContent* aChild,
+                                   PRInt32 aIndexInContainer,
+                                   nsIContent* aPreviousSibling)
+{
+  if (aChild->IsInNativeAnonymousSubtree()) {
+    return;
+  }
+
+  nsINode* parent = NODE_FROM(aContainer, aDocument);
+  if (nsAutoMutationBatch::IsBatching()) {
+    if (nsAutoMutationBatch::IsRemovalDone()) {
+      // This can happen for example if HTML parser parses to
+      // context node, but needs to move elements around.
+      return;
+    }
+    if (nsAutoMutationBatch::GetBatchTarget() != parent) {
+      return;
+    }
+
+    bool wantsChildList = ChildList() && (Subtree() || parent == Target());
+    if (wantsChildList || Subtree()) {
+      nsAutoMutationBatch::NodeRemoved(aChild);
+      nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList);
+    }
+
+    return;
+  }                                                                   
+
+  if (Subtree()) {
+    // Try to avoid creating transient observer if the node
+    // already has an observer observing the same set of nodes.
+    nsMutationReceiver* orig = GetParent() ? GetParent() : this;
+    if (Observer()->GetReceiverFor(aChild, false) != orig) {
+      bool transientExists = false;
+      nsCOMArray<nsMutationReceiver>* transientReceivers = nsnull;
+      Observer()->mTransientReceivers.Get(aChild, &transientReceivers);
+      if (!transientReceivers) {
+        transientReceivers = new nsCOMArray<nsMutationReceiver>();
+        Observer()->mTransientReceivers.Put(aChild, transientReceivers);
+      } else {
+        for (PRInt32 i = 0; i < transientReceivers->Count(); ++i) {
+          nsMutationReceiver* r = transientReceivers->ObjectAt(i);
+          if (r->GetParent() == orig) {
+            transientExists = true;
+          }
+        }
+      }
+      if (!transientExists) {
+        // Make sure the elements which are removed from the
+        // subtree are kept in the same observation set.
+        transientReceivers->AppendObject(new nsMutationReceiver(aChild, orig));
+      }
+    }
+  }
+
+  if (ChildList() && (Subtree() || parent == Target())) {
+    nsDOMMutationRecord* m =
+      Observer()->CurrentRecord(NS_LITERAL_STRING("childList"));
+    if (m->mTarget) {
+      // Already handled case.
+      return;
+    }
+    m->mTarget = parent;
+    m->mRemovedNodes = new nsSimpleContentList(parent);
+    m->mRemovedNodes->AppendElement(aChild);
+    m->mPreviousSibling = aPreviousSibling;
+    m->mNextSibling = parent->GetChildAt(aIndexInContainer);
+  }
+  // We need to schedule always, so that after microtask mTransientReceivers
+  // can be cleared correctly.
+  Observer()->ScheduleForRun();
+}
+
+// Observer
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationObserver)
+
+DOMCI_DATA(MozMutationObserver, nsDOMMutationObserver)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozMutationObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozMutationObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozMutationObserver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationObserver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationObserver)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMutationObserver)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
+  for (PRInt32 i = 0; i < tmp->mReceivers.Count(); ++i) {
+    tmp->mReceivers[i]->Disconnect();
+  }
+  tmp->mReceivers.Clear();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingMutations)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCallback)
+  // No need to handle mTransientReceivers
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationObserver)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mReceivers)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingMutations)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCallback)
+  // No need to handle mTransientReceivers
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+nsMutationReceiver*
+nsDOMMutationObserver::GetReceiverFor(nsINode* aNode, bool aMayCreate)
+{
+  if (!aMayCreate && !aNode->MayHaveDOMMutationObserver()) {
+    return nsnull;
+  }
+
+  for (PRInt32 i = 0; i < mReceivers.Count(); ++i) {
+    if (mReceivers[i]->Target() == aNode) {
+      return mReceivers[i];
+    }
+  }
+  if (!aMayCreate) {
+    return nsnull;
+  }
+
+  nsMutationReceiver* r = new nsMutationReceiver(aNode, this);
+  mReceivers.AppendObject(r);
+  return r;
+}
+
+void
+nsDOMMutationObserver::GetAllSubtreeObserversFor(nsINode* aNode,
+                                                 nsTArray<nsMutationReceiver*>&
+                                                   aReceivers)
+{
+  nsINode* n = aNode;
+  while (n) {
+    if (n->MayHaveDOMMutationObserver()) {
+      nsMutationReceiver* r = GetReceiverFor(n, false);
+      if (r && r->Subtree() && !aReceivers.Contains(r)) {
+        aReceivers.AppendElement(r);
+        // If we've found all the receivers the observer has,
+        // no need to search for more.
+        if (mReceivers.Count() == PRInt32(aReceivers.Length())) {
+          return;
+        }
+      }                                            
+      nsCOMArray<nsMutationReceiver>* transientReceivers = nsnull;
+      if (mTransientReceivers.Get(n, &transientReceivers) && transientReceivers) {
+        for (PRInt32 i = 0; i < transientReceivers->Count(); ++i) {
+          nsMutationReceiver* r = transientReceivers->ObjectAt(i);
+          nsMutationReceiver* parent = r->GetParent();
+          if (r->Subtree() && parent && !aReceivers.Contains(parent)) {
+            aReceivers.AppendElement(parent);
+          }
+        }
+        if (mReceivers.Count() == PRInt32(aReceivers.Length())) {
+          return;
+        }
+      }
+    }
+    n = n->GetNodeParent();
+  }
+}
+
+void
+nsDOMMutationObserver::ScheduleForRun()
+{
+  nsDOMMutationObserver::AddCurrentlyHandlingObserver(this);
+
+  if (mWaitingForRun) {
+    return;
+  }
+  mWaitingForRun = true;
+  RescheduleForRun();
+}
+
+void
+nsDOMMutationObserver::RescheduleForRun()
+{
+  if (!sScheduledMutationObservers) {
+    sScheduledMutationObservers = new nsCOMArray<nsIDOMMozMutationObserver>;
+  }
+
+  bool didInsert = false;
+  for (PRInt32 i = 0; i < sScheduledMutationObservers->Count(); ++i) {
+    if (static_cast<nsDOMMutationObserver*>((*sScheduledMutationObservers)[i])
+          ->mId > mId) {
+      sScheduledMutationObservers->InsertObjectAt(this, i);
+      didInsert = true;
+      break;
+    }
+  }
+  if (!didInsert) {
+    sScheduledMutationObservers->AppendObject(this);
+  }
+}
+
+NS_IMETHODIMP
+nsDOMMutationObserver::Observe(nsIDOMNode* aTarget,
+                               const JS::Value& aOptions,
+                               JSContext* aCx)
+{
+  nsCOMPtr<nsINode> target = do_QueryInterface(aTarget);
+  NS_ENSURE_STATE(target);
+
+  mozilla::dom::MutationObserverInit d;
+  nsresult rv = d.Init(aCx, &aOptions);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_ENSURE_TRUE(d.childList || d.attributes || d.characterData,
+                 NS_ERROR_DOM_SYNTAX_ERR);
+  NS_ENSURE_TRUE(!d.attributeOldValue || d.attributes,
+                 NS_ERROR_DOM_SYNTAX_ERR);
+  NS_ENSURE_TRUE(!d.characterDataOldValue || d.characterData,
+                 NS_ERROR_DOM_SYNTAX_ERR);
+
+  nsCOMArray<nsIAtom> filters;
+  bool allAttrs = true;
+  if (!d.attributeFilter.isUndefined()) {
+    allAttrs = false;
+    rv = nsContentUtils::JSArrayToAtomArray(aCx, d.attributeFilter, filters);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_TRUE(filters.Count() == 0 || d.attributes,
+                   NS_ERROR_DOM_SYNTAX_ERR);
+  }
+
+  nsMutationReceiver* r = GetReceiverFor(target, true);
+  r->SetChildList(d.childList);
+  r->SetAttributes(d.attributes);
+  r->SetCharacterData(d.characterData);
+  r->SetSubtree(d.subtree);
+  r->SetAttributeOldValue(d.attributeOldValue);
+  r->SetCharacterDataOldValue(d.characterDataOldValue);
+  r->SetAttributeFilter(filters);
+  r->SetAllAttributes(allAttrs);
+  r->RemoveClones();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMutationObserver::Disconnect()
+{
+  for (PRInt32 i = 0; i < mReceivers.Count(); ++i) {
+    mReceivers[i]->Disconnect();
+  }
+  mReceivers.Clear();
+  mCurrentMutations.Clear();
+  mPendingMutations.Clear();
+  return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsDOMMutationObserver::Initialize(nsISupports* aOwner, JSContext* cx,
+                                  JSObject* obj, PRUint32 argc, jsval* argv)
+{
+  mOwner = do_QueryInterface(aOwner);
+  if (!mOwner) {
+    NS_WARNING("Unexpected nsIJSNativeInitializer owner");
+    return NS_OK;
+  }
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
+  NS_ENSURE_STATE(sgo);
+  mScriptContext = sgo->GetContext();
+  NS_ENSURE_STATE(mScriptContext);
+  
+  NS_ENSURE_STATE(argc >= 1);
+  NS_ENSURE_STATE(!JSVAL_IS_PRIMITIVE(argv[0]));
+
+  nsCOMPtr<nsISupports> tmp;
+  nsContentUtils::XPConnect()->WrapJS(cx, JSVAL_TO_OBJECT(argv[0]),
+                                      NS_GET_IID(nsIMutationObserverCallback),
+                                      getter_AddRefs(tmp));
+  mCallback = do_QueryInterface(tmp);
+  NS_ENSURE_STATE(mCallback);
+  
+  return NS_OK;
+}
+
+void
+nsDOMMutationObserver::HandleMutation()
+{
+  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Whaat!");
+  NS_ASSERTION(mCurrentMutations.IsEmpty(),
+               "Still generating MutationRecords?");
+
+  mWaitingForRun = false;
+
+  for (PRInt32 i = 0; i < mReceivers.Count(); ++i) {
+    mReceivers[i]->RemoveClones();
+  }
+  mTransientReceivers.Clear();
+
+  nsPIDOMWindow* outer = mOwner->GetOuterWindow();
+  if (!mPendingMutations.Count() || !outer ||
+      outer->GetCurrentInnerWindow() != mOwner) {
+    mPendingMutations.Clear();
+    return;
+  }
+  nsCxPusher pusher;
+  nsCOMPtr<nsIDOMEventTarget> et = do_QueryInterface(mOwner);
+  if (!mCallback || !pusher.Push(et)) {
+    mPendingMutations.Clear();
+    return;
+  }
+  
+  PRInt32 len = mPendingMutations.Count();
+  nsTArray<nsIDOMMutationRecord*> mods(len);
+  for (PRInt32 i = 0; i < len; ++i) {
+    mods.AppendElement(mPendingMutations[i]);
+  }
+  
+  nsCOMPtr<nsIWritableVariant> mutations =
+    do_CreateInstance("@mozilla.org/variant;1");
+  mutations->SetAsArray(nsIDataType::VTYPE_INTERFACE,
+                        &NS_GET_IID(nsIDOMMutationRecord),
+                        mods.Length(),
+                        const_cast<void*>(
+                          static_cast<const void*>(mods.Elements())));
+  mPendingMutations.Clear();
+  nsAutoMicroTask mt;
+  sCurrentObserver = this; // For 'this' handling.
+  mCallback->HandleMutations(mutations, this);
+  sCurrentObserver = nsnull;
+}
+
+class AsyncMutationHandler : public nsRunnable
+{
+public:
+  NS_IMETHOD Run()
+  {
+    nsDOMMutationObserver::HandleMutations();
+    return NS_OK;
+  }
+};
+
+void
+nsDOMMutationObserver::HandleMutationsInternal()
+{
+  if (!nsContentUtils::IsSafeToRunScript()) {
+    nsContentUtils::AddScriptRunner(new AsyncMutationHandler());
+    return;
+  }
+  static nsRefPtr<nsDOMMutationObserver> sCurrentObserver;
+  if (sCurrentObserver && !sCurrentObserver->Suppressed()) {
+    // In normal cases sScheduledMutationObservers will be handled
+    // after previous mutations are handled. But in case some
+    // callback calls a sync API, which spins the eventloop, we need to still
+    // process other mutations happening during that sync call.
+    // This does *not* catch all cases, but should work for stuff running
+    // in separate tabs.
+    return;
+  }
+
+  nsCOMArray<nsIDOMMozMutationObserver>* suppressedObservers = nsnull;
+
+  while (sScheduledMutationObservers) {
+    nsCOMArray<nsIDOMMozMutationObserver>* observers = sScheduledMutationObservers;
+    sScheduledMutationObservers = nsnull;
+    for (PRInt32 i = 0; i < observers->Count(); ++i) {
+      sCurrentObserver = static_cast<nsDOMMutationObserver*>((*observers)[i]);
+      if (!sCurrentObserver->Suppressed()) {
+        sCurrentObserver->HandleMutation();
+      } else {
+        if (!suppressedObservers) {
+          suppressedObservers = new nsCOMArray<nsIDOMMozMutationObserver>;
+        }
+        if (suppressedObservers->IndexOf(sCurrentObserver) < 0) {
+          suppressedObservers->AppendObject(sCurrentObserver);
+        }
+      }
+    }
+    delete observers;
+  }
+
+  if (suppressedObservers) {
+    for (PRInt32 i = 0; i < suppressedObservers->Count(); ++i) {
+      static_cast<nsDOMMutationObserver*>(suppressedObservers->ObjectAt(i))->
+        RescheduleForRun();
+    }
+    delete suppressedObservers;
+    suppressedObservers = nsnull;
+  }
+  sCurrentObserver = nsnull;
+}
+
+nsDOMMutationRecord*
+nsDOMMutationObserver::CurrentRecord(const nsAString& aType)
+{
+  NS_ASSERTION(sMutationLevel > 0, "Unexpected mutation level!");
+
+  while (mCurrentMutations.Length() < sMutationLevel) {
+    mCurrentMutations.AppendElement(static_cast<nsDOMMutationRecord*>(nsnull));
+  }
+
+  PRUint32 last = sMutationLevel - 1;
+  if (!mCurrentMutations[last]) {
+    nsDOMMutationRecord* r = new nsDOMMutationRecord(aType);
+    mCurrentMutations[last] = r;
+    mPendingMutations.AppendObject(r);
+    ScheduleForRun();
+  }
+
+  NS_ASSERTION(mCurrentMutations[last]->mType.Equals(aType),
+               "Unexpected MutationRecord type!");
+
+  return mCurrentMutations[last];
+}
+
+nsDOMMutationObserver::~nsDOMMutationObserver()
+{
+  for (PRInt32 i = 0; i < mReceivers.Count(); ++i) {
+    mReceivers[i]->RemoveClones();
+  }
+}                                   
+
+void
+nsDOMMutationObserver::EnterMutationHandling()
+{
+  ++sMutationLevel;
+}
+
+// Leave the current mutation level (there can be several levels if in case
+// of nested calls to the nsIMutationObserver methods).
+// The most recent mutation record is removed from mCurrentMutations, so
+// that is doesn't get modified anymore by receivers.
+void
+nsDOMMutationObserver::LeaveMutationHandling()
+{
+  if (sCurrentlyHandlingObservers &&
+      sCurrentlyHandlingObservers->Length() == sMutationLevel) {
+    nsCOMArray<nsIDOMMozMutationObserver>& obs =
+      sCurrentlyHandlingObservers->ElementAt(sMutationLevel - 1);
+    for (PRInt32 i = 0; i < obs.Count(); ++i) {
+      nsDOMMutationObserver* o =
+        static_cast<nsDOMMutationObserver*>(obs[i]);
+      if (o->mCurrentMutations.Length() == sMutationLevel) {
+        // It is already in pending mutations.
+        o->mCurrentMutations.RemoveElementAt(sMutationLevel - 1);
+      }
+    }
+    sCurrentlyHandlingObservers->RemoveElementAt(sMutationLevel - 1);
+  }
+  --sMutationLevel;
+}
+
+void
+nsDOMMutationObserver::AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver)
+{
+  NS_ASSERTION(sMutationLevel > 0, "Unexpected mutation level!");
+
+  if (!sCurrentlyHandlingObservers) {
+    sCurrentlyHandlingObservers =
+      new nsAutoTArray<nsCOMArray<nsIDOMMozMutationObserver>, 4>;
+  }
+
+  while (sCurrentlyHandlingObservers->Length() < sMutationLevel) {
+    sCurrentlyHandlingObservers->InsertElementAt(
+      sCurrentlyHandlingObservers->Length());
+  }
+
+  PRUint32 last = sMutationLevel - 1;
+  if (sCurrentlyHandlingObservers->ElementAt(last).IndexOf(aObserver) < 0) {
+    sCurrentlyHandlingObservers->ElementAt(last).AppendObject(aObserver);
+  }
+}
+
+void
+nsDOMMutationObserver::Shutdown()
+{
+  delete sCurrentlyHandlingObservers;
+  sCurrentlyHandlingObservers = nsnull;
+  delete sScheduledMutationObservers;
+  sScheduledMutationObservers = nsnull;
+}
+
+nsAutoMutationBatch*
+nsAutoMutationBatch::sCurrentBatch = nsnull;
+
+void
+nsAutoMutationBatch::Done()
+{
+  if (sCurrentBatch != this) {
+    return;
+  }
+
+  sCurrentBatch = mPreviousBatch;
+  if (mObservers.IsEmpty()) {
+    nsDOMMutationObserver::LeaveMutationHandling();
+    // Nothing to do.
+    return;
+  }
+
+  PRUint32 len = mObservers.Length();
+  for (PRUint32 i = 0; i < len; ++i) {
+    nsDOMMutationObserver* ob = mObservers[i].mObserver;
+    bool wantsChildList = mObservers[i].mWantsChildList;
+
+    nsRefPtr<nsSimpleContentList> removedList;
+    if (wantsChildList) {
+      removedList = new nsSimpleContentList(mBatchTarget);
+    }
+
+    nsTArray<nsMutationReceiver*> allObservers;
+    ob->GetAllSubtreeObserversFor(mBatchTarget, allObservers);
+
+    PRInt32 j = mFromFirstToLast ? 0 : mRemovedNodes.Length() - 1;
+    PRInt32 end = mFromFirstToLast ? mRemovedNodes.Length() : -1;
+    for (; j != end; mFromFirstToLast ? ++j : --j) {
+      nsCOMPtr<nsIContent> removed = mRemovedNodes[j];
+      if (removedList) {
+        removedList->AppendElement(removed);
+      }
+
+      if (allObservers.Length()) {
+        nsCOMArray<nsMutationReceiver>* transientReceivers = nsnull;
+        ob->mTransientReceivers.Get(removed, &transientReceivers);
+        if (!transientReceivers) {
+          transientReceivers = new nsCOMArray<nsMutationReceiver>();
+          ob->mTransientReceivers.Put(removed, transientReceivers);
+        }
+        for (PRUint32 k = 0; k < allObservers.Length(); ++k) {
+          nsMutationReceiver* r = allObservers[k];
+          nsMutationReceiver* orig = r->GetParent() ? r->GetParent() : r;
+          if (ob->GetReceiverFor(removed, false) != orig) {
+            // Make sure the elements which are removed from the
+            // subtree are kept in the same observation set.
+            transientReceivers->AppendObject(new nsMutationReceiver(removed, orig));
+          }
+        }
+      }
+    }
+    if (wantsChildList && (mRemovedNodes.Length() || mAddedNodes.Length())) {
+      nsRefPtr<nsSimpleContentList> addedList =
+        new nsSimpleContentList(mBatchTarget);
+      for (PRUint32 i = 0; i < mAddedNodes.Length(); ++i) {
+        addedList->AppendElement(mAddedNodes[i]);
+      }
+      nsDOMMutationRecord* m =
+        new nsDOMMutationRecord(NS_LITERAL_STRING("childList"));
+      ob->mPendingMutations.AppendObject(m);
+      m->mTarget = mBatchTarget;
+      m->mRemovedNodes = removedList;
+      m->mAddedNodes = addedList;
+      m->mPreviousSibling = mPrevSibling;
+      m->mNextSibling = mNextSibling;
+      ob->ScheduleForRun();
+    }
+  }
+  nsDOMMutationObserver::LeaveMutationHandling();
+}
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsDOMMutationObserver.h
@@ -0,0 +1,533 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsDOMMutationObserver_h
+#define nsDOMMutationObserver_h
+
+#include "nsIDOMMutationObserver.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsIJSNativeInitializer.h"
+#include "nsPIDOMWindow.h"
+#include "nsIScriptContext.h"
+#include "nsStubMutationObserver.h"
+#include "nsCOMArray.h"
+#include "nsTArray.h"
+#include "nsAutoPtr.h"
+#include "nsIVariant.h"
+#include "nsContentList.h"
+#include "mozilla/dom/Element.h"
+#include "nsClassHashtable.h"
+#include "nsNodeUtils.h"
+
+class nsDOMMutationObserver;
+
+class nsDOMMutationRecord : public nsIDOMMutationRecord
+{
+public:
+  nsDOMMutationRecord(const nsAString& aType) : mType(aType)
+  {
+    mAttrName.SetIsVoid(PR_TRUE);
+    mAttrNamespace.SetIsVoid(PR_TRUE);
+    mPrevValue.SetIsVoid(PR_TRUE);
+  }
+  virtual ~nsDOMMutationRecord() {}
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMMutationRecord)
+  NS_DECL_NSIDOMMUTATIONRECORD
+
+  nsCOMPtr<nsINode>             mTarget;
+  nsString                      mType;
+  nsString                      mAttrName;
+  nsString                      mAttrNamespace;
+  nsString                      mPrevValue;
+  nsRefPtr<nsSimpleContentList> mAddedNodes;
+  nsRefPtr<nsSimpleContentList> mRemovedNodes;
+  nsCOMPtr<nsINode>             mPreviousSibling;
+  nsCOMPtr<nsINode>             mNextSibling;
+};
+ 
+// Base class just prevents direct access to
+// members to make sure we go through getters/setters.
+class nsMutationReceiverBase : public nsStubMutationObserver
+{
+public:
+  virtual ~nsMutationReceiverBase() { }
+
+  nsDOMMutationObserver* Observer();
+  nsINode* Target() { return mParent ? mParent->Target() : mTarget; }
+  nsINode* RegisterTarget() { return mRegisterTarget; }
+
+  bool Subtree() { return mParent ? mParent->Subtree() : mSubtree; }
+  void SetSubtree(bool aSubtree)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mSubtree = aSubtree;
+  }
+
+  bool ChildList() { return mParent ? mParent->ChildList() : mChildList; }
+  void SetChildList(bool aChildList)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mChildList = aChildList;
+  }
+
+  bool CharacterData()
+  {
+    return mParent ? mParent->CharacterData() : mCharacterData;
+  }
+  void SetCharacterData(bool aCharacterData)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mCharacterData = aCharacterData;
+  }
+
+  bool CharacterDataOldValue()
+  {
+    return mParent ? mParent->CharacterDataOldValue() : mCharacterDataOldValue;
+  }
+  void SetCharacterDataOldValue(bool aOldValue)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mCharacterDataOldValue = aOldValue;
+  }
+
+  bool Attributes() { return mParent ? mParent->Attributes() : mAttributes; }
+  void SetAttributes(bool aAttributes)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mAttributes = aAttributes;
+  }
+
+  bool AllAttributes()
+  {
+    return mParent ? mParent->AllAttributes()
+                   : mAllAttributes;
+  }
+  void SetAllAttributes(bool aAll)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mAllAttributes = aAll;
+  }
+
+  bool AttributeOldValue() {
+    return mParent ? mParent->AttributeOldValue()
+                   : mAttributeOldValue;
+  }
+  void SetAttributeOldValue(bool aOldValue)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mAttributeOldValue = aOldValue;
+  }
+
+  nsCOMArray<nsIAtom>& AttributeFilter() { return mAttributeFilter; }
+  void SetAttributeFilter(nsCOMArray<nsIAtom>& aFilter)
+  {
+    NS_ASSERTION(!mParent, "Shouldn't have parent");
+    mAttributeFilter.Clear();
+    mAttributeFilter.AppendObjects(aFilter);
+  }
+
+  void AddClone(nsMutationReceiverBase* aClone)
+  {
+    mTransientReceivers.AppendObject(aClone);
+  }
+
+  void RemoveClone(nsMutationReceiverBase* aClone)
+  {
+    mTransientReceivers.RemoveObject(aClone);
+  }
+  
+protected:
+  nsMutationReceiverBase(nsINode* aTarget, nsIDOMMozMutationObserver* aObserver)
+  : mTarget(aTarget), mObserver(aObserver), mRegisterTarget(aTarget)
+  {
+    mRegisterTarget->AddMutationObserver(this);
+    mRegisterTarget->SetMayHaveDOMMutationObserver();
+    mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers();
+  }
+
+  nsMutationReceiverBase(nsINode* aRegisterTarget,
+                         nsMutationReceiverBase* aParent)
+  : mObserver(nsnull), mParent(aParent), mRegisterTarget(aRegisterTarget)
+  {
+    NS_ASSERTION(mParent->Subtree(), "Should clone a non-subtree observer!");
+    mRegisterTarget->AddMutationObserver(this);
+    mRegisterTarget->SetMayHaveDOMMutationObserver();
+    mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers();
+  }
+
+  bool ObservesAttr(mozilla::dom::Element* aElement,
+                    PRInt32 aNameSpaceID,
+                    nsIAtom* aAttr)
+  {
+    if (mParent) {
+      return mParent->ObservesAttr(aElement, aNameSpaceID, aAttr);
+    }
+    if (!Attributes() || (!Subtree() && aElement != Target())) {
+      return false;
+    }
+    if (AllAttributes()) {
+      return true;
+    }
+
+    if (aNameSpaceID != kNameSpaceID_None) {
+      return false;
+    }
+
+    nsCOMArray<nsIAtom>& filters = AttributeFilter();
+    for (PRInt32 i = 0; i < filters.Count(); ++i) {         
+      if (filters[i] == aAttr) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // The target for the MutationObserver.observe() method.
+  nsINode*                           mTarget;
+  nsIDOMMozMutationObserver*         mObserver;
+  nsRefPtr<nsMutationReceiverBase>   mParent; // Cleared after microtask.
+  // The node to which Gecko-internal nsIMutationObserver was registered to.
+  // This is different than mTarget when dealing with transient observers.
+  nsINode*                           mRegisterTarget;
+  nsCOMArray<nsMutationReceiverBase> mTransientReceivers;
+  
+private:
+  bool                               mSubtree;
+  bool                               mChildList;
+  bool                               mCharacterData;
+  bool                               mCharacterDataOldValue;
+  bool                               mAttributes;
+  bool                               mAllAttributes;
+  bool                               mAttributeOldValue;
+  nsCOMArray<nsIAtom>                mAttributeFilter;
+};
+
+
+#define NS_MUTATION_OBSERVER_IID \
+{ 0xe628f313, 0x8129, 0x4f90, \
+  { 0x8e, 0xc3, 0x85, 0xe8, 0x28, 0x22, 0xe7, 0xab } }
+
+class nsMutationReceiver : public nsMutationReceiverBase
+{
+public:
+  nsMutationReceiver(nsINode* aTarget, nsIDOMMozMutationObserver* aObserver)
+  : nsMutationReceiverBase(aTarget, aObserver)
+  {
+    mTarget->BindObject(aObserver);
+  }
+
+  nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
+  : nsMutationReceiverBase(aRegisterTarget, aParent)
+  {
+    NS_ASSERTION(!static_cast<nsMutationReceiver*>(aParent)->GetParent(),
+                 "Shouldn't create deep observer hierarchies!");
+    aParent->AddClone(this);
+  }
+
+  virtual ~nsMutationReceiver() { Disconnect(); }
+
+  nsMutationReceiver* GetParent()
+  {
+    return static_cast<nsMutationReceiver*>(mParent.get());
+  }
+
+  void RemoveClones()
+  {
+    for (PRInt32 i = 0; i < mTransientReceivers.Count(); ++i) {
+      nsMutationReceiver* r =
+        static_cast<nsMutationReceiver*>(mTransientReceivers[i]);
+      r->Disconnect();
+    }
+    mTransientReceivers.Clear();
+  }
+
+  void DisconnectTransientReceivers()
+  {
+    if (mRegisterTarget) {
+      mRegisterTarget->RemoveMutationObserver(this);
+      mRegisterTarget = nsnull;
+    }
+
+    mParent = nsnull;
+  }
+
+  void Disconnect()
+  {
+    if (mRegisterTarget) {
+      mRegisterTarget->RemoveMutationObserver(this);
+      mRegisterTarget = nsnull;
+    }
+    if (mTarget && mObserver) {
+      mTarget->UnbindObject(mObserver);
+    }
+
+    mParent = nsnull;
+    mTarget = nsnull;
+    mObserver = nsnull;
+    RemoveClones();
+  }
+
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMUTATION_OBSERVER_IID)
+  NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsMutationReceiver)
+
+  virtual void AttributeWillChange(nsIDocument* aDocument,
+                                   mozilla::dom::Element* aElement,
+                                   PRInt32 aNameSpaceID,
+                                   nsIAtom* aAttribute,
+                                   PRInt32 aModType);
+  virtual void CharacterDataWillChange(nsIDocument *aDocument,
+                                       nsIContent* aContent,
+                                       CharacterDataChangeInfo* aInfo);
+  virtual void ContentAppended(nsIDocument *aDocument,
+                               nsIContent* aContainer,
+                               nsIContent* aFirstNewContent,
+                               PRInt32     aNewIndexInContainer);
+  virtual void ContentInserted(nsIDocument *aDocument,
+                               nsIContent* aContainer,
+                               nsIContent* aChild,
+                               PRInt32 aIndexInContainer);
+  virtual void ContentRemoved(nsIDocument *aDocument,
+                              nsIContent* aContainer,
+                              nsIContent* aChild,
+                              PRInt32 aIndexInContainer,
+                              nsIContent* aPreviousSibling);
+
+  virtual void NodeWillBeDestroyed(const nsINode *aNode)
+  {
+    Disconnect();
+  }
+  
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsMutationReceiver, NS_MUTATION_OBSERVER_IID)
+
+class nsDOMMutationObserver : public nsIDOMMozMutationObserver,
+                              public nsIJSNativeInitializer
+{
+public:
+  nsDOMMutationObserver() : mWaitingForRun(false), mId(++sCount)
+  {
+    mTransientReceivers.Init();
+  }
+  virtual ~nsDOMMutationObserver();
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMMutationObserver,
+                                           nsIDOMMozMutationObserver)
+  NS_DECL_NSIDOMMOZMUTATIONOBSERVER
+
+  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
+                        PRUint32 argc, jsval* argv);
+
+  void HandleMutation();
+
+  // static methods
+  static void HandleMutations()
+  {
+    if (sScheduledMutationObservers) {
+      HandleMutationsInternal();
+    }
+  }
+
+  static void EnterMutationHandling();
+  static void LeaveMutationHandling();
+
+  static nsIDOMMozMutationObserver* CurrentObserver()
+  {
+    return sCurrentObserver;
+  }
+
+  static void Shutdown();
+protected:
+  friend class nsMutationReceiver;
+  friend class nsAutoMutationBatch;
+  nsMutationReceiver* GetReceiverFor(nsINode* aNode, bool aMayCreate);
+  void GetAllSubtreeObserversFor(nsINode* aNode,
+                                 nsTArray<nsMutationReceiver*>& aObservers);
+  void ScheduleForRun();
+  void RescheduleForRun();
+
+  nsDOMMutationRecord* CurrentRecord(const nsAString& aType);
+  bool HasCurrentRecord(const nsAString& aType);
+
+  bool Suppressed()
+  {
+    if (mOwner) {
+      nsCOMPtr<nsIDocument> d = do_QueryInterface(mOwner->GetExtantDocument());
+      return d && d->IsInSyncOperation();
+    }
+    return false;
+  }
+
+  static void HandleMutationsInternal();
+
+  static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver);
+
+  nsCOMPtr<nsIScriptContext>                         mScriptContext;
+  nsCOMPtr<nsPIDOMWindow>                            mOwner;
+
+  nsCOMArray<nsMutationReceiver>                     mReceivers;
+  nsClassHashtable<nsISupportsHashKey,
+                   nsCOMArray<nsMutationReceiver> >  mTransientReceivers;  
+  // MutationRecords which are being constructed.
+  nsAutoTArray<nsDOMMutationRecord*, 4>              mCurrentMutations;
+  // MutationRecords which will be handed to the callback at the end of
+  // the microtask.
+  nsCOMArray<nsDOMMutationRecord>                    mPendingMutations;
+  nsCOMPtr<nsIMutationObserverCallback>              mCallback;
+
+  bool                                               mWaitingForRun;
+
+  PRUint64                                           mId;
+
+  static PRUint64                                    sCount;
+  static nsCOMArray<nsIDOMMozMutationObserver>*      sScheduledMutationObservers;
+  static nsIDOMMozMutationObserver*                  sCurrentObserver;
+
+  static PRUint32                                    sMutationLevel;
+  static nsAutoTArray<nsCOMArray<nsIDOMMozMutationObserver>, 4>*
+                                                     sCurrentlyHandlingObservers;
+};
+
+class nsAutoMutationBatch
+{
+public:
+  nsAutoMutationBatch()
+  : mPreviousBatch(nsnull), mBatchTarget(nsnull), mRemovalDone(false),
+    mFromFirstToLast(false), mAllowNestedBatches(false)    
+  {
+  }
+
+  nsAutoMutationBatch(nsINode* aTarget, bool aFromFirstToLast,
+                      bool aAllowNestedBatches)
+  : mPreviousBatch(nsnull), mBatchTarget(nsnull), mRemovalDone(false),
+    mFromFirstToLast(false), mAllowNestedBatches(false)
+  {
+    Init(aTarget, aFromFirstToLast, aAllowNestedBatches);
+  }
+
+  void Init(nsINode* aTarget, bool aFromFirstToLast, bool aAllowNestedBatches)
+  {
+    if (aTarget && aTarget->OwnerDoc()->MayHaveDOMMutationObservers()) {
+      if (sCurrentBatch && !sCurrentBatch->mAllowNestedBatches) {
+        return;
+      }
+      mBatchTarget = aTarget;
+      mFromFirstToLast = aFromFirstToLast;
+      mAllowNestedBatches = aAllowNestedBatches;
+      mPreviousBatch = sCurrentBatch;
+      sCurrentBatch = this;
+      nsDOMMutationObserver::EnterMutationHandling();
+    }
+  }
+
+  void RemovalDone() { mRemovalDone = true; }
+  static bool IsRemovalDone() { return sCurrentBatch->mRemovalDone; }
+
+  void SetPrevSibling(nsINode* aNode) { mPrevSibling = aNode; }
+  void SetNextSibling(nsINode* aNode) { mNextSibling = aNode; }
+
+  void Done();
+
+  ~nsAutoMutationBatch() { NodesAdded(); }
+
+  static bool IsBatching()
+  {
+    return !!sCurrentBatch;
+  }
+
+  static nsAutoMutationBatch* GetCurrentBatch()
+  {
+    return sCurrentBatch;
+  }
+
+  static void UpdateObserver(nsDOMMutationObserver* aObserver,
+                             bool aWantsChildList)
+  {
+    PRUint32 l = sCurrentBatch->mObservers.Length();
+    for (PRUint32 i = 0; i < l; ++i) {
+      if (sCurrentBatch->mObservers[i].mObserver == aObserver) {
+        if (aWantsChildList) {
+          sCurrentBatch->mObservers[i].mWantsChildList = aWantsChildList;
+        } 
+        return;
+      }
+    }
+    BatchObserver* bo = sCurrentBatch->mObservers.AppendElement(); 
+    bo->mObserver = aObserver;
+    bo->mWantsChildList = aWantsChildList;
+  }
+
+
+  static nsINode* GetBatchTarget() { return sCurrentBatch->mBatchTarget; }
+
+  // Mutation receivers notify the batch about removed child nodes.
+  static void NodeRemoved(nsIContent* aChild)
+  {
+    if (IsBatching() && !sCurrentBatch->mRemovalDone) {
+      PRUint32 len = sCurrentBatch->mRemovedNodes.Length();
+      if (!len ||
+          sCurrentBatch->mRemovedNodes[len - 1] != aChild) {
+        sCurrentBatch->mRemovedNodes.AppendElement(aChild);
+      }
+    }
+  }
+
+  // Called after new child nodes have been added to the batch target.
+  void NodesAdded()
+  {
+    if (sCurrentBatch != this) {
+      return;
+    }
+
+    nsIContent* c =
+      mPrevSibling ? mPrevSibling->GetNextSibling() :
+                     mBatchTarget->GetFirstChild();
+    for (; c != mNextSibling; c = c->GetNextSibling()) {
+      mAddedNodes.AppendElement(c);
+    }
+    Done();
+  }
+
+private:
+  struct BatchObserver
+  {
+    nsDOMMutationObserver* mObserver;
+    bool                   mWantsChildList;
+  };
+  
+  static nsAutoMutationBatch* sCurrentBatch;
+  nsAutoMutationBatch* mPreviousBatch;
+  nsAutoTArray<BatchObserver, 2> mObservers;
+  nsTArray<nsCOMPtr<nsIContent> > mRemovedNodes;
+  nsTArray<nsCOMPtr<nsIContent> > mAddedNodes;
+  nsINode* mBatchTarget;
+  bool mRemovalDone;
+  bool mFromFirstToLast;
+  bool mAllowNestedBatches;
+  nsCOMPtr<nsINode> mPrevSibling;
+  nsCOMPtr<nsINode> mNextSibling;
+};
+
+inline
+nsDOMMutationObserver*
+nsMutationReceiverBase::Observer()
+{
+  return mParent ?
+    mParent->Observer() : static_cast<nsDOMMutationObserver*>(mObserver);
+}
+
+#define NS_DOMMUTATIONOBSERVER_CID           \
+ { /* b66b9490-52f7-4f2a-b998-dbb1d59bc13e */ \
+  0xb66b9490, 0x52f7, 0x4f2a,                 \
+  { 0xb9, 0x98, 0xdb, 0xb1, 0xd5, 0x9b, 0xc1, 0x3e } }
+
+#define NS_DOMMUTATIONOBSERVER_CONTRACTID \
+  "@mozilla.org/dommutationobserver;1"
+
+#endif
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3099,32 +3099,16 @@ nsDocument::SetHeaderData(nsIAtom* aHead
       *lastPtr = new nsDocHeaderData(aHeaderField, aData);
     }
   }
 
   if (aHeaderField == nsGkAtoms::headerContentLanguage) {
     CopyUTF16toUTF8(aData, mContentLanguage);
   }
 
-  // Set the default script-type on the root element.
-  if (aHeaderField == nsGkAtoms::headerContentScriptType) {
-    Element *root = GetRootElement();
-    if (root) {
-      // Get the script-type ID for this value.
-      nsresult rv;
-      nsCOMPtr<nsIScriptRuntime> runtime;
-      rv = NS_GetScriptRuntime(aData, getter_AddRefs(runtime));
-      if (NS_FAILED(rv) || runtime == nsnull) {
-        NS_WARNING("The script-type is unknown");
-      } else {
-        root->SetScriptTypeID(runtime->GetScriptTypeID());
-      }
-    }
-  }
-
   if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
     // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
     // spec.
     if (DOMStringIsNull(mLastStyleSheetSet)) {
       // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
       // per spec.  The idea here is that we're changing our preferred set and
       // that shouldn't change the value of lastStyleSheetSet.  Also, we're
       // using the Internal version so we can update the CSSLoader and not have
@@ -4824,65 +4808,54 @@ nsDocument::GetCharacterSet(nsAString& a
 }
 
 NS_IMETHODIMP
 nsDocument::ImportNode(nsIDOMNode* aImportedNode,
                        bool aDeep,
                        PRUint8 aArgc,
                        nsIDOMNode** aResult)
 {
-  NS_ENSURE_ARG(aImportedNode);
   if (aArgc == 0) {
     aDeep = true;
   }
 
   *aResult = nsnull;
 
-  nsresult rv = nsContentUtils::CheckSameOrigin(this, aImportedNode);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  PRUint16 nodeType;
-  aImportedNode->GetNodeType(&nodeType);
-  switch (nodeType) {
+  nsCOMPtr<nsINode> imported = do_QueryInterface(aImportedNode);
+  NS_ENSURE_TRUE(imported, NS_ERROR_UNEXPECTED);
+
+  nsresult rv = nsContentUtils::CheckSameOrigin(this, imported);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  switch (imported->NodeType()) {
     case nsIDOMNode::ATTRIBUTE_NODE:
     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
     case nsIDOMNode::ELEMENT_NODE:
     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
     case nsIDOMNode::TEXT_NODE:
     case nsIDOMNode::CDATA_SECTION_NODE:
     case nsIDOMNode::COMMENT_NODE:
     case nsIDOMNode::DOCUMENT_TYPE_NODE:
     {
-      nsCOMPtr<nsINode> imported = do_QueryInterface(aImportedNode);
-      NS_ENSURE_TRUE(imported, NS_ERROR_FAILURE);
-
       nsCOMPtr<nsIDOMNode> newNode;
       nsCOMArray<nsINode> nodesWithProperties;
       rv = nsNodeUtils::Clone(imported, aDeep, mNodeInfoManager,
                               nodesWithProperties, getter_AddRefs(newNode));
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsIDocument *ownerDoc = imported->OwnerDoc();
       rv = nsNodeUtils::CallUserDataHandlers(nodesWithProperties, ownerDoc,
                                              nsIDOMUserDataHandler::NODE_IMPORTED,
                                              true);
       NS_ENSURE_SUCCESS(rv, rv);
 
       newNode.swap(*aResult);
 
       return NS_OK;
     }
-    case nsIDOMNode::ENTITY_NODE:
-    case nsIDOMNode::ENTITY_REFERENCE_NODE:
-    case nsIDOMNode::NOTATION_NODE:
-    {
-      return NS_ERROR_NOT_IMPLEMENTED;
-    }
     default:
     {
       NS_WARNING("Don't know how to clone this nodetype for importNode.");
 
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
   }
 }
@@ -5074,34 +5047,29 @@ nsDocument::CreateNodeIterator(nsIDOMNod
                                nsIDOMNodeIterator **_retval)
 {
   *_retval = nsnull;
 
   if (!aOptionalArgc) {
     aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
   }
 
-  if (!aRoot)
+  if (!aRoot) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-
-  nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_ENSURE_ARG_POINTER(_retval);
+  }
 
   nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
-  NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-
-  nsNodeIterator *iterator = new nsNodeIterator(root,
-                                                aWhatToShow,
-                                                aFilter);
-  NS_ENSURE_TRUE(iterator, NS_ERROR_OUT_OF_MEMORY);
-
-  NS_ADDREF(*_retval = iterator);
-
+  NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED);
+
+  nsresult rv = nsContentUtils::CheckSameOrigin(this, root);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsRefPtr<nsNodeIterator> iterator = new nsNodeIterator(root, aWhatToShow,
+                                                         aFilter);
+  iterator.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
                              PRUint32 aWhatToShow,
                              nsIDOMNodeFilter *aFilter,
                              PRUint8 aOptionalArgc,
@@ -6031,43 +5999,111 @@ public:
     return NS_OK;
   }
 
 private:
   nsCOMArray<nsINode> mNodesWithProperties;
   nsCOMPtr<nsIDocument> mOwnerDoc;
 };
 
+/**
+ * Get a scope from aNewDocument. Also get a context through the scope of one
+ * of the documents, from the stack or the safe context.
+ *
+ * @param aOldDocument The document to try to get a context from.
+ * @param aNewDocument The document to get aNewScope from.
+ * @param aCx [out] Context gotten through one of the scopes, from the stack
+ *                  or the safe context.
+ * @param aNewScope [out] Scope gotten from aNewDocument.
+ */
+static nsresult
+GetContextAndScope(nsIDocument* aOldDocument, nsIDocument* aNewDocument,
+                   JSContext** aCx, JSObject** aNewScope)
+{
+  MOZ_ASSERT(aOldDocument);
+  MOZ_ASSERT(aNewDocument);
+
+  *aCx = nsnull;
+  *aNewScope = nsnull;
+
+  JSObject* newScope = aNewDocument->GetWrapper();
+  JSObject* global;
+  if (!newScope) {
+    nsIScriptGlobalObject *newSGO = aNewDocument->GetScopeObject();
+    if (!newSGO || !(global = newSGO->GetGlobalJSObject())) {
+      return NS_OK;
+    }
+  }
+
+  JSContext* cx = nsContentUtils::GetContextFromDocument(aOldDocument);
+  if (!cx) {
+    cx = nsContentUtils::GetContextFromDocument(aNewDocument);
+
+    if (!cx) {
+      // No context reachable from the old or new document, use the
+      // calling context, or the safe context if no caller can be
+      // found.
+
+      nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
+      stack->Peek(&cx);
+
+      if (!cx) {
+        stack->GetSafeJSContext(&cx);
+
+        if (!cx) {
+          // No safe context reachable, bail.
+          NS_WARNING("No context reachable in GetContextAndScopes()!");
+
+          return NS_ERROR_NOT_AVAILABLE;
+        }
+      }
+    }
+  }
+
+  if (!newScope && cx) {
+    JS::Value v;
+    nsresult rv = nsContentUtils::WrapNative(cx, global, aNewDocument,
+                                             aNewDocument, &v);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    newScope = JSVAL_TO_OBJECT(v);
+  }
+
+  *aCx = cx;
+  *aNewScope = newScope;
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
 {
   NS_ENSURE_ARG(aAdoptedNode);
 
   *aResult = nsnull;
 
-  nsresult rv = nsContentUtils::CheckSameOrigin(this, aAdoptedNode);
+  nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode);
+  NS_ENSURE_TRUE(adoptedNode, NS_ERROR_UNEXPECTED);
+
+  nsresult rv = nsContentUtils::CheckSameOrigin(this, adoptedNode);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode);
-
   // Scope firing mutation events so that we don't carry any state that
   // might be stale
   {
     nsINode* parent = adoptedNode->GetNodeParent();
     if (parent) {
       nsContentUtils::MaybeFireNodeRemoved(adoptedNode, parent,
                                            adoptedNode->OwnerDoc());
     }
   }
 
   nsAutoScriptBlocker scriptBlocker;
 
-  PRUint16 nodeType;
-  aAdoptedNode->GetNodeType(&nodeType);
-  switch (nodeType) {
+  switch (adoptedNode->NodeType()) {
     case nsIDOMNode::ATTRIBUTE_NODE:
     {
       // Remove from ownerElement.
       nsCOMPtr<nsIDOMAttr> adoptedAttr = do_QueryInterface(aAdoptedNode);
       NS_ASSERTION(adoptedAttr, "Attribute not implementing nsIDOMAttr");
 
       nsCOMPtr<nsIDOMElement> ownerElement;
       rv = adoptedAttr->GetOwnerElement(getter_AddRefs(ownerElement));
@@ -6112,23 +6148,17 @@ nsDocument::AdoptNode(nsIDOMNode *aAdopt
       // Remove from parent.
       nsCOMPtr<nsINode> parent = adoptedNode->GetNodeParent();
       if (parent) {
         parent->RemoveChildAt(parent->IndexOf(adoptedNode), true);
       }
 
       break;
     }
-    case nsIDOMNode::ENTITY_REFERENCE_NODE:
-    {
-      return NS_ERROR_NOT_IMPLEMENTED;
-    }
     case nsIDOMNode::DOCUMENT_NODE:
-    case nsIDOMNode::ENTITY_NODE:
-    case nsIDOMNode::NOTATION_NODE:
     {
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
     default:
     {
       NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
 
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
@@ -6136,17 +6166,17 @@ nsDocument::AdoptNode(nsIDOMNode *aAdopt
   }
 
   nsIDocument *oldDocument = adoptedNode->OwnerDoc();
   bool sameDocument = oldDocument == this;
 
   JSContext *cx = nsnull;
   JSObject *newScope = nsnull;
   if (!sameDocument) {
-    rv = nsContentUtils::GetContextAndScope(oldDocument, this, &cx, &newScope);
+    rv = GetContextAndScope(oldDocument, this, &cx, &newScope);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMArray<nsINode> nodesWithProperties;
   rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nsnull : mNodeInfoManager,
                           cx, newScope, nodesWithProperties);
   if (NS_FAILED(rv)) {
     // Disconnect all nodes from their parents, since some have the old document
@@ -6193,17 +6223,18 @@ nsDocument::AdoptNode(nsIDOMNode *aAdopt
   if (nodesWithProperties.Count()) {
     nsContentUtils::AddScriptRunner(new nsUserDataCaller(nodesWithProperties,
                                                          this));
   }
 
   NS_ASSERTION(adoptedNode->OwnerDoc() == this,
                "Should still be in the document we just got adopted into");
 
-  return CallQueryInterface(adoptedNode, aResult);
+  NS_ADDREF(*aResult = aAdoptedNode);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
 {
   return nsINode::GetOwnerDocument(aOwnerDocument);
 }
 
@@ -9264,8 +9295,47 @@ nsDocument::DocSizeOfExcludingThis(nsWin
     mAttrStyleSheet ?
     mAttrStyleSheet->DOMSizeOfIncludingThis(aWindowSizes->mMallocSizeOf) :
     0;
 
   // Measurement of the following members may be added later if DMD finds it
   // is worthwhile:
   // - many!
 }
+
+bool
+MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
+{
+  nsCOMArray<nsIDocument>* documents =
+    static_cast<nsCOMArray<nsIDocument>*>(aData);
+  if (aDoc) {
+    aDoc->SetIsInSyncOperation(true);
+    documents->AppendObject(aDoc);
+    aDoc->EnumerateSubDocuments(MarkDocumentTreeToBeInSyncOperation, aData);
+  }
+  return true;
+}
+
+nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc)
+{
+  mMicroTaskLevel = nsContentUtils::MicroTaskLevel();
+  nsContentUtils::SetMicroTaskLevel(0);
+  if (aDoc) {
+    nsPIDOMWindow* win = aDoc->GetWindow();
+    if (win) {
+      nsCOMPtr<nsIDOMWindow> topWindow;
+      win->GetTop(getter_AddRefs(topWindow));
+      nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
+      if (top) {                               
+        nsCOMPtr<nsIDocument> doc = do_QueryInterface(top->GetExtantDocument());
+        MarkDocumentTreeToBeInSyncOperation(doc, &mDocuments);
+      }
+    }
+  }
+}
+
+nsAutoSyncOperation::~nsAutoSyncOperation()
+{
+  for (PRInt32 i = 0; i < mDocuments.Count(); ++i) {
+    mDocuments[i]->SetIsInSyncOperation(false);
+  }
+  nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel);
+}
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -504,18 +504,16 @@ class nsDocument : public nsIDocument,
 {
 public:
   typedef mozilla::dom::Element Element;
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_SIZEOF_EXCLUDING_THIS
 
-  using nsINode::GetScriptTypeID;
-
   virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
   virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
                           nsIPrincipal* aPrincipal);
 
   // StartDocumentLoad is pure virtual so that subclasses must override it.
   // The nsDocument StartDocumentLoad does some setup, but does NOT set
   // *aDocListener; this is the job of subclasses.
   virtual nsresult StartDocumentLoad(const char* aCommand,
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -78,16 +78,20 @@
 #include "nsITransferable.h" // for kUnicodeMime
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
 #include "nsStringBuffer.h"
 #include "mozilla/dom/Element.h"
+#include "nsIEditorDocShell.h"
+#include "nsIEditor.h"
+#include "nsIHTMLEditor.h"
+#include "nsIDocShell.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
 
 enum nsRangeIterationDirection {
   kDirectionOut = -1,
@@ -344,16 +348,52 @@ nsDocumentEncoder::GetMimeType(nsAString
 
 
 bool
 nsDocumentEncoder::IncludeInContext(nsINode *aNode)
 {
   return false;
 }
 
+static
+bool
+IsInvisibleBreak(nsINode *aNode) {
+  // xxxehsan: we should probably figure out a way to determine
+  // if a BR node is visible without using the editor.
+  Element* elt = aNode->AsElement();
+  if (!elt->IsHTML(nsGkAtoms::br) ||
+      !aNode->IsEditable()) {
+    return false;
+  }
+
+  // Grab the editor associated with the document
+  nsIDocument *doc = aNode->GetCurrentDoc();
+  if (doc) {
+    nsPIDOMWindow *window = doc->GetWindow();
+    if (window) {
+      nsIDocShell *docShell = window->GetDocShell();
+      if (docShell) {
+        nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
+        if (editorDocShell) {
+          nsCOMPtr<nsIEditor> editor;
+          editorDocShell->GetEditor(getter_AddRefs(editor));
+          nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
+          if (htmlEditor) {
+            bool isVisible = false;
+            nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
+            htmlEditor->BreakIsVisible(domNode, &isVisible);
+            return !isVisible;
+          }
+        }
+      }
+    }
+  }
+  return false;
+}
+
 nsresult
 nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
                                       PRInt32 aStartOffset,
                                       PRInt32 aEndOffset,
                                       nsAString& aStr,
                                       nsINode* aOriginalNode)
 {
   if (!IsVisibleNode(aNode))
@@ -376,16 +416,21 @@ nsDocumentEncoder::SerializeNodeStart(ns
   }
 
   // Either there was no fixed-up node,
   // or the caller did fixup themselves and aNode is already fixed
   if (!node)
     node = aNode;
   
   if (node->IsElement()) {
+    if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
+                   nsIDocumentEncoder::OutputDropInvisibleBreak)) &&
+        IsInvisibleBreak(node)) {
+      return NS_OK;
+    }
     Element* originalElement =
       aOriginalNode && aOriginalNode->IsElement() ?
         aOriginalNode->AsElement() : nsnull;
     mSerializer->AppendElementStart(node->AsElement(),
                                     originalElement, aStr);
     return NS_OK;
   }
 
@@ -1240,17 +1285,25 @@ nsHTMLCopyEncoder::Init(nsIDOMDocument* 
 
   mIsTextWidget = false;
   Initialize();
 
   mIsCopying = true;
   mDocument = do_QueryInterface(aDocument);
   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
 
-  mMimeType.AssignLiteral("text/html");
+  // Hack, hack! Traditionally, the caller passes text/unicode, which is
+  // treated as "guess text/html or text/plain" in this context. (It has a
+  // different meaning in other contexts. Sigh.) From now on, "text/plain"
+  // means forcing text/plain instead of guessing.
+  if (aMimeType.EqualsLiteral("text/plain")) {
+    mMimeType.AssignLiteral("text/plain");
+  } else {
+    mMimeType.AssignLiteral("text/html");
+  }
 
   // Make all links absolute when copying
   // (see related bugs #57296, #41924, #58646, #32768)
   mFlags = aFlags | OutputAbsoluteLinks;
 
   if (!mDocument->IsScriptEnabled())
     mFlags |= OutputNoScriptContent;
 
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -806,17 +806,18 @@ nsFrameScriptExecutor::LoadFrameScriptIn
   if (!dataString.IsEmpty()) {
     nsContentUtils::ThreadJSContextStack()->Push(mCx);
     {
       // Need to scope JSAutoRequest to happen after Push but before Pop,
       // at least for now. See bug 584673.
       JSAutoRequest ar(mCx);
       JSObject* global = nsnull;
       mGlobal->GetJSObject(&global);
-      if (global) {
+      JSAutoEnterCompartment ac;
+      if (global && ac.enter(mCx, global)) {
         uint32 oldopts = JS_GetOptions(mCx);
         JS_SetOptions(mCx, oldopts | JSOPTION_NO_SCRIPT_RVAL);
 
         JSScript* script =
           JS_CompileUCScriptForPrincipals(mCx, nsnull,
                                           nsJSPrincipals::get(mPrincipal),
                                           static_cast<const jschar*>(dataString.get()),
                                           dataString.Length(),
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -143,17 +143,17 @@
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsCCUncollectableMarker.h"
 
 #include "mozAutoDocUpdate.h"
 
 #include "nsCSSParser.h"
 #include "prprf.h"
-
+#include "nsDOMMutationObserver.h"
 #include "nsSVGFeatures.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsCycleCollector.h"
 #include "xpcpublic.h"
 #include "xpcprivate.h"
 #include "nsLayoutStatics.h"
 #include "mozilla/Telemetry.h"
 
@@ -1256,16 +1256,23 @@ nsINode::Traverse(nsINode *tmp, nsCycleC
 
   nsSlots *slots = tmp->GetExistingSlots();
   if (slots) {
     slots->Traverse(cb);
   }
 
   if (tmp->HasProperties()) {
     nsNodeUtils::TraverseUserData(tmp, cb);
+    nsCOMArray<nsISupports>* objects =
+      static_cast<nsCOMArray<nsISupports>*>(tmp->GetProperty(nsGkAtoms::keepobjectsalive));
+    if (objects) {
+      for (PRInt32 i = 0; i < objects->Count(); ++i) {
+         cb.NoteXPCOMChild(objects->ObjectAt(i));
+      }
+    }
   }
 
   if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
       tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
     nsContentUtils::TraverseListenerManager(tmp, cb);
   }
 
   return true;
@@ -1285,16 +1292,17 @@ nsINode::Unlink(nsINode *tmp)
   if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
       tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
     nsContentUtils::RemoveListenerManager(tmp);
     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
   }
 
   if (tmp->HasProperties()) {
     nsNodeUtils::UnlinkUserData(tmp);
+    tmp->DeleteProperty(nsGkAtoms::keepobjectsalive);
   }
 }
 
 //----------------------------------------------------------------------
 
 nsEventStates
 Element::IntrinsicState() const
 {
@@ -2487,19 +2495,16 @@ nsGenericElement::nsGenericElement(alrea
 {
   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ELEMENT_NODE ||
                     (mNodeInfo->NodeType() ==
                        nsIDOMNode::DOCUMENT_FRAGMENT_NODE &&
                      mNodeInfo->Equals(nsGkAtoms::documentFragmentNodeName,
                                        kNameSpaceID_None)),
                     "Bad NodeType in aNodeInfo");
 
-  // Set the default scriptID to JS - but skip SetScriptTypeID as it
-  // does extra work we know isn't necessary here...
-  SetFlags((nsIProgrammingLanguage::JAVASCRIPT << NODE_SCRIPT_TYPE_OFFSET));
   SetIsElement();
 }
 
 nsGenericElement::~nsGenericElement()
 {
   NS_PRECONDITION(!IsInDoc(),
                   "Please remove this from the document properly");
   if (GetParent()) {
@@ -3711,40 +3716,16 @@ nsGenericElement::GetBindingParent() con
 }
 
 bool
 nsGenericElement::IsNodeOfType(PRUint32 aFlags) const
 {
   return !(aFlags & ~eCONTENT);
 }
 
-//----------------------------------------------------------------------
-
-PRUint32
-nsGenericElement::GetScriptTypeID() const
-{
-    PtrBits flags = GetFlags();
-
-    return (flags >> NODE_SCRIPT_TYPE_OFFSET) & NODE_SCRIPT_TYPE_MASK;
-}
-
-NS_IMETHODIMP
-nsGenericElement::SetScriptTypeID(PRUint32 aLang)
-{
-    if ((aLang & NODE_SCRIPT_TYPE_MASK) != aLang) {
-        NS_ERROR("script ID too large!");
-        return NS_ERROR_FAILURE;
-    }
-    /* SetFlags will just mask in the specific flags set, leaving existing
-       ones alone.  So we must clear all the bits first */
-    UnsetFlags(NODE_SCRIPT_TYPE_MASK << NODE_SCRIPT_TYPE_OFFSET);
-    SetFlags(aLang << NODE_SCRIPT_TYPE_OFFSET);
-    return NS_OK;
-}
-
 nsresult
 nsGenericElement::InsertChildAt(nsIContent* aKid,
                                 PRUint32 aIndex,
                                 bool aNotify)
 {
   NS_PRECONDITION(aKid, "null ptr");
 
   return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren);
@@ -4265,18 +4246,20 @@ nsINode::ReplaceOrInsertBefore(bool aRep
     insPos = GetChildCount();
   }
 
   // Make sure that the inserted node is allowed as a child of its new parent.
   if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
   }
 
+  nsAutoMutationBatch mb;
   // If we're replacing
   if (aReplace) {
+    mb.Init(this, true, true);
     RemoveChildAt(insPos, true);
   }
 
   if (newContent->IsRootOfAnonymousSubtree()) {
     // This is anonymous content.  Don't allow its insertion
     // anywhere, since it might have UnbindFromTree calls coming
     // its way.
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
@@ -4287,17 +4270,23 @@ nsINode::ReplaceOrInsertBefore(bool aRep
   if (oldParent) {
     PRInt32 removeIndex = oldParent->IndexOf(newContent);
     if (removeIndex < 0) {
       // newContent is anonymous.  We can't deal with this, so just bail
       NS_ERROR("How come our flags didn't catch this?");
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
 
+    nsAutoMutationBatch mb(oldParent, true, true);
     oldParent->RemoveChildAt(removeIndex, true);
+    if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
+      mb.RemovalDone();
+      mb.SetPrevSibling(oldParent->GetChildAt(removeIndex - 1));
+      mb.SetNextSibling(oldParent->GetChildAt(removeIndex));
+    }
 
     // Adjust insert index if the node we ripped out was a sibling
     // of the node we're inserting before
     if (oldParent == this && removeIndex < insPos) {
       --insPos;
     }
   }
 
@@ -4332,18 +4321,31 @@ nsINode::ReplaceOrInsertBefore(bool aRep
          child;
          child = child->GetNextSibling()) {
       NS_ASSERTION(child->GetCurrentDoc() == nsnull,
                    "How did we get a child with a current doc?");
       fragChildren.AppendElement(child);
     }
 
     // Remove the children from the fragment.
-    for (PRUint32 i = count; i > 0;) {
-      newContent->RemoveChildAt(--i, true);
+    {
+      nsAutoMutationBatch mb(newContent, false, true);
+      for (PRUint32 i = count; i > 0;) {
+        newContent->RemoveChildAt(--i, true);
+      }
+    }
+
+    if (!aReplace) {
+      mb.Init(this, true, true);
+    }
+    nsAutoMutationBatch* mutationBatch = nsAutoMutationBatch::GetCurrentBatch();
+    if (mutationBatch) {
+      mutationBatch->RemovalDone();
+      mutationBatch->SetPrevSibling(GetChildAt(insPos - 1));
+      mutationBatch->SetNextSibling(GetChildAt(insPos));
     }
 
     bool appending =
       !IsNodeOfType(eDOCUMENT) && PRUint32(insPos) == GetChildCount();
     PRInt32 firstInsPos = insPos;
     nsIContent* firstInsertedContent = fragChildren[0];
 
     // Iterate through the fragment's children, and insert them in the new
@@ -4358,35 +4360,47 @@ nsINode::ReplaceOrInsertBefore(bool aRep
           nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
                                        firstInsertedContent,
                                        firstInsPos);
         }
         return res;
       }
     }
 
+    if (mutationBatch && !appending) {
+      mutationBatch->NodesAdded();
+    }
+
     // Notify and fire mutation events when appending
     if (appending) {
       nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
                                    firstInsertedContent, firstInsPos);
+      if (mutationBatch) {
+        mutationBatch->NodesAdded();
+      }
       // Optimize for the case when there are no listeners
       if (nsContentUtils::
             HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
         nsGenericElement::FireNodeInserted(doc, this, fragChildren);
       }
     }
   }
   else {
     // Not inserting a fragment but rather a single node.
 
     // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=544654
     //       We need to reparent here for nodes for which the parent of their
     //       wrapper is not the wrapper for their ownerDocument (XUL elements,
     //       form controls, ...). Also applies in the fragment code above.
 
+    if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
+      mb.RemovalDone();
+      mb.SetPrevSibling(GetChildAt(insPos - 1));
+      mb.SetNextSibling(GetChildAt(insPos));
+    }
     res = InsertChildAt(newContent, insPos, true);
     NS_ENSURE_SUCCESS(res, res);
   }
 
   return NS_OK;
 }
 
 nsresult
@@ -5116,19 +5130,18 @@ nsGenericElement::AddScriptEventListener
   bool defer = true;
   nsEventListenerManager* manager = GetEventListenerManagerForAttr(aEventName,
                                                                    &defer);
   if (!manager) {
     return NS_OK;
   }
 
   defer = defer && aDefer; // only defer if everyone agrees...
-  PRUint32 lang = GetScriptTypeID();
-  manager->AddScriptEventListener(aEventName, aValue, lang, defer,
-                                  !nsContentUtils::IsChromeDoc(ownerDoc));
+  manager->AddScriptEventListener(aEventName, aValue, nsIProgrammingLanguage::JAVASCRIPT,
+                                  defer, !nsContentUtils::IsChromeDoc(ownerDoc));
   return NS_OK;
 }
 
 
 //----------------------------------------------------------------------
 
 const nsAttrName*
 nsGenericElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
@@ -5188,17 +5201,17 @@ nsGenericElement::MaybeCheckSameAttrVal(
         // should serialize the attribute value now to keep a snapshot.
         //
         // We have to serialize the value anyway in order to create the
         // mutation event so there's no cost in doing it now.
         aOldValue.SetToSerialized(*info.mValue);
       }
       bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
       if (valueMatches && aPrefix == info.mName->GetPrefix()) {
-        return true;
+        return !OwnerDoc()->MayHaveDOMMutationObservers();
       }
       modification = true;
     }
   }
   *aModType = modification ?
     static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION) :
     static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
   return false;
@@ -6050,16 +6063,47 @@ nsGenericElement::FireNodeRemovedForChil
 }
 
 void
 nsGenericElement::GetLinkTarget(nsAString& aTarget)
 {
   aTarget.Truncate();
 }
 
+static void
+nsCOMArrayDeleter(void* aObject, nsIAtom* aPropertyName,
+                  void* aPropertyValue, void* aData)
+{
+  nsCOMArray<nsISupports>* objects =
+    static_cast<nsCOMArray<nsISupports>*>(aPropertyValue);
+  delete objects;
+}
+
+void
+nsINode::BindObject(nsISupports* aObject)
+{
+  nsCOMArray<nsISupports>* objects =
+    static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
+  if (!objects) {
+    objects = new nsCOMArray<nsISupports>();
+    SetProperty(nsGkAtoms::keepobjectsalive, objects, nsCOMArrayDeleter, true);
+  }
+  objects->AppendObject(aObject);
+}
+
+void
+nsINode::UnbindObject(nsISupports* aObject)
+{
+  nsCOMArray<nsISupports>* objects =
+    static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
+  if (objects) {
+    objects->RemoveObject(aObject);
+  }
+}
+
 // NOTE: The aPresContext pointer is NOT addrefed.
 // *aSelectorList might be null even if NS_OK is returned; this
 // happens when all the selectors were pseudo-element selectors.
 static nsresult
 ParseSelectorList(nsINode* aNode,
                   const nsAString& aSelectorString,
                   nsCSSSelectorList** aSelectorList)
 {
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -338,19 +338,16 @@ public:
   virtual nsresult AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
                               bool aNotify);
   virtual bool TextIsOnlyWhitespace();
   virtual void AppendTextTo(nsAString& aResult);
   virtual nsIContent *GetBindingParent() const;
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
   virtual bool IsLink(nsIURI** aURI) const;
 
-  virtual PRUint32 GetScriptTypeID() const;
-  NS_IMETHOD SetScriptTypeID(PRUint32 aLang);
-
   virtual void DestroyContent();
   virtual void SaveSubtreeState();
 
   virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/)
   {
     return nsnull;
   }
   virtual nsIDOMCSSStyleDeclaration* GetSMILOverrideStyle();
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -486,16 +486,17 @@ GK_ATOM(ismap, "ismap")
 GK_ATOM(itemid, "itemid")
 GK_ATOM(itemprop, "itemprop")
 GK_ATOM(itemref, "itemref")
 GK_ATOM(itemscope, "itemscope")
 GK_ATOM(itemtype, "itemtype")
 GK_ATOM(kbd, "kbd")
 GK_ATOM(noautofocus, "noautofocus")
 GK_ATOM(keepcurrentinview, "keepcurrentinview")
+GK_ATOM(keepobjectsalive, "keepobjectsalive")
 GK_ATOM(key, "key")
 GK_ATOM(keycode, "keycode")
 GK_ATOM(keydown, "keydown")
 GK_ATOM(keygen, "keygen")
 GK_ATOM(keypress, "keypress")
 GK_ATOM(keyset, "keyset")
 GK_ATOM(keytext, "keytext")
 GK_ATOM(keyup, "keyup")
@@ -1896,20 +1897,21 @@ GK_ATOM(x_tibt, "x-tibt")
 // used in gfxGDIFontList.h
 GK_ATOM(ko_xxx, "ko-xxx")
 GK_ATOM(x_central_euro, "x-central-euro")
 GK_ATOM(x_symbol, "x-symbol")
 
 // referenced in all.js
 GK_ATOM(x_user_def, "x-user-def")
 
-// additional languages that use Turkish-style case transformation
+// additional languages that have special case transformations
 GK_ATOM(az, "az")
 GK_ATOM(ba, "ba")
 GK_ATOM(crh, "crh")
+GK_ATOM(nl, "nl")
 
 // Names for editor transactions
 GK_ATOM(TypingTxnName, "Typing")
 GK_ATOM(IMETxnName, "IME")
 GK_ATOM(DeleteTxnName, "Deleting")
 
 // IPC stuff
 GK_ATOM(Remote, "remote")
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -83,51 +83,16 @@ nsresult NS_NewHTMLContentSerializer(nsI
   nsHTMLContentSerializer* it = new nsHTMLContentSerializer();
   if (!it) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return CallQueryInterface(it, aSerializer);
 }
 
-static
-bool
-IsInvisibleBreak(nsIContent *aNode, nsIAtom *aTag, PRInt32 aNamespace) {
-  // xxxehsan: we should probably figure out a way to determine
-  // if a BR node is visible without using the editor.
-  if (!(aTag == nsGkAtoms::br && aNamespace == kNameSpaceID_XHTML) ||
-      !aNode->IsEditable()) {
-    return false;
-  }
-
-  // Grab the editor associated with the document
-  nsIDocument *doc = aNode->GetCurrentDoc();
-  if (doc) {
-    nsPIDOMWindow *window = doc->GetWindow();
-    if (window) {
-      nsIDocShell *docShell = window->GetDocShell();
-      if (docShell) {
-        nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
-        if (editorDocShell) {
-          nsCOMPtr<nsIEditor> editor;
-          editorDocShell->GetEditor(getter_AddRefs(editor));
-          nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
-          if (htmlEditor) {
-            bool isVisible = false;
-            nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
-            htmlEditor->BreakIsVisible(domNode, &isVisible);
-            return !isVisible;
-          }
-        }
-      }
-    }
-  }
-  return false;
-}
-
 nsHTMLContentSerializer::nsHTMLContentSerializer()
 {
     mIsHTMLSerializer = true;
 }
 
 nsHTMLContentSerializer::~nsHTMLContentSerializer()
 {
 }
@@ -258,21 +223,16 @@ nsHTMLContentSerializer::AppendElementSt
   bool forceFormat = false;
   if (!CheckElementStart(content, forceFormat, aStr)) {
     return NS_OK;
   }
 
   nsIAtom *name = content->Tag();
   PRInt32 ns = content->GetNameSpaceID();
 
-  if ((mFlags & nsIDocumentEncoder::OutputPreformatted) &&
-      IsInvisibleBreak(content, name, ns)) {
-    return NS_OK;
-  }
-
   bool lineBreakBeforeOpen = LineBreakBeforeOpen(ns, name);
 
   if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
     if (mColPos && lineBreakBeforeOpen) {
       AppendNewLineToString(aStr);
     }
     else {
       MaybeAddNewlineForRootNode(aStr);
--- a/content/base/src/nsNodeIterator.cpp
+++ b/content/base/src/nsNodeIterator.cpp
@@ -202,17 +202,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 DOMCI_DATA(NodeIterator, nsNodeIterator)
 
 // QueryInterface implementation for nsNodeIterator
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeIterator)
     NS_INTERFACE_MAP_ENTRY(nsIDOMNodeIterator)
     NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
-    NS_INTERFACE_MAP_ENTRY(nsIMutationObserver2)
     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNodeIterator)
     NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeIterator)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeIterator)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeIterator)
 
 /* readonly attribute nsIDOMNode root; */
@@ -340,16 +339,8 @@ void nsNodeIterator::ContentRemoved(nsID
                                     PRInt32 aIndexInContainer,
                                     nsIContent *aPreviousSibling)
 {
     nsINode *container = NODE_FROM(aContainer, aDocument);
 
     mPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
     mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
 }
-
-void nsNodeIterator::AttributeChildRemoved(nsINode* aAttribute,
-                                           nsIContent* aChild)
-{
-  mPointer.AdjustAfterRemoval(mRoot, aAttribute, aChild, 0);
-  mWorkingPointer.AdjustAfterRemoval(mRoot, aAttribute, aChild, 0);
-}
-
--- a/content/base/src/nsNodeIterator.h
+++ b/content/base/src/nsNodeIterator.h
@@ -50,29 +50,28 @@
 #include "nsStubMutationObserver.h"
 
 class nsINode;
 class nsIDOMNode;
 class nsIDOMNodeFilter;
 
 class nsNodeIterator : public nsIDOMNodeIterator,
                        public nsTraversal,
-                       public nsStubMutationObserver2
+                       public nsStubMutationObserver
 {
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDOMNODEITERATOR
 
     nsNodeIterator(nsINode *aRoot,
                    PRUint32 aWhatToShow,
                    nsIDOMNodeFilter *aFilter);
     virtual ~nsNodeIterator();
 
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-    NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNodeIterator, nsIDOMNodeIterator)
 
 private:
     struct NodePointer {
         NodePointer() : mNode(nsnull) {};
         NodePointer(nsINode *aNode, bool aBeforeNode);
 
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -37,21 +37,19 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsNodeUtils.h"
 #include "nsContentUtils.h"
 #include "nsINode.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Element.h"
 #include "nsIMutationObserver.h"
-#include "nsIMutationObserver2.h"
 #include "nsIDocument.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsEventListenerManager.h"
-#include "nsIAttribute.h"
 #include "nsIXPConnect.h"
 #include "nsGenericElement.h"
 #include "pldhash.h"
 #include "nsIDOMAttr.h"
 #include "nsCOMArray.h"
 #include "nsPIDOMWindow.h"
 #include "nsDocument.h"
 #ifdef MOZ_XUL
@@ -61,42 +59,48 @@
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 #include "nsImageLoadingContent.h"
 #include "jsgc.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsObjectLoadingContent.h"
+#include "nsDOMMutationObserver.h"
 
 using namespace mozilla::dom;
 
 // This macro expects the ownerDocument of content_ to be in scope as
 // |nsIDocument* doc|
-// NOTE: AttributeChildRemoved doesn't use this macro but has a very similar use.
-// If you change how this macro behave please update AttributeChildRemoved.
 #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
   PR_BEGIN_MACRO                                                  \
+  bool needsEnterLeave = doc->MayHaveDOMMutationObservers();      \
+  if (needsEnterLeave) {                                          \
+    nsDOMMutationObserver::EnterMutationHandling();               \
+  }                                                               \
   nsINode* node = content_;                                       \
-  NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document");     \
+  NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document");        \
   if (doc) {                                                      \
     static_cast<nsIMutationObserver*>(doc->BindingManager())->    \
       func_ params_;                                              \
   }                                                               \
   do {                                                            \
     nsINode::nsSlots* slots = node->GetExistingSlots();           \
     if (slots && !slots->mMutationObservers.IsEmpty()) {          \
       /* No need to explicitly notify the first observer first    \
          since that'll happen anyway. */                          \
       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(                         \
         slots->mMutationObservers, nsIMutationObserver,           \
         func_, params_);                                          \
     }                                                             \
     node = node->GetNodeParent();                                 \
   } while (node);                                                 \
+  if (needsEnterLeave) {                                          \
+    nsDOMMutationObserver::LeaveMutationHandling();               \
+  }                                                               \
   PR_END_MACRO
 
 void
 nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
                                      CharacterDataChangeInfo* aInfo)
 {
   nsIDocument* doc = aContent->OwnerDoc();
   IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
@@ -194,42 +198,16 @@ nsNodeUtils::ContentRemoved(nsINode* aCo
   }
 
   IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
                              (document, container, aChild, aIndexInContainer,
                               aPreviousSibling));
 }
 
 void
-nsNodeUtils::AttributeChildRemoved(nsINode* aAttribute,
-                                   nsIContent* aChild)
-{
-  NS_PRECONDITION(aAttribute->IsNodeOfType(nsINode::eATTRIBUTE),
-                  "container must be a nsIAttribute");
-
-  // This is a variant of IMPL_MUTATION_NOTIFICATION.
-  do {
-    nsINode::nsSlots* slots = aAttribute->GetExistingSlots();
-    if (slots && !slots->mMutationObservers.IsEmpty()) {
-      // This is a variant of NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS.
-      nsTObserverArray<nsIMutationObserver*>::ForwardIterator iter_ =
-        slots->mMutationObservers;
-      nsCOMPtr<nsIMutationObserver2> obs_;
-      while (iter_.HasMore()) {
-        obs_ = do_QueryInterface(iter_.GetNext());
-        if (obs_) {
-          obs_->AttributeChildRemoved(aAttribute, aChild);
-        }
-      }
-    }
-    aAttribute = aAttribute->GetNodeParent();
-  } while (aAttribute);
-}
-
-void
 nsNodeUtils::LastRelease(nsINode* aNode)
 {
   nsINode::nsSlots* slots = aNode->GetExistingSlots();
   if (slots) {
     if (!slots->mMutationObservers.IsEmpty()) {
       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
                                          nsIMutationObserver,
                                          NodeWillBeDestroyed, (aNode));
@@ -564,18 +542,22 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
         nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
         olc->NotifyOwnerDocumentActivityChanged();
       }
     }
 
     // nsImageLoadingContent needs to know when its document changes
     if (oldDoc != newDoc) {
       nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aNode));
-      if (imageContent)
+      if (imageContent) {
         imageContent->NotifyOwnerDocumentChanged(oldDoc);
+      }
+      if (oldDoc->MayHaveDOMMutationObservers()) {
+        newDoc->SetMayHaveDOMMutationObservers();
+      }
     }
 
     if (elem) {
       elem->RecompileScriptEventListeners();
     }
 
     if (aCx && wrapper) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
@@ -593,42 +575,21 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
     }
   }
 
   // XXX If there are any attribute nodes on this element with UserDataHandlers
   // we should technically adopt/clone/import such attribute nodes and notify
   // those handlers. However we currently don't have code to do so without
   // also notifying when it's not safe so we're not doing that at this time.
 
-  // The DOM spec says to always adopt/clone/import the children of attribute
-  // nodes.
-  // XXX The following block is here because our implementation of attribute
-  //     nodes is broken when it comes to inserting children. Instead of cloning
-  //     their children we force creation of the only child by calling
-  //     GetChildAt(0). We can remove this when
-  //     https://bugzilla.mozilla.org/show_bug.cgi?id=56758 is fixed.
-  if (aClone && aNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
-    nsCOMPtr<nsINode> attrChildNode = aNode->GetChildAt(0);
-    // We only need to do this if the child node has properties (because we
-    // might need to call a userdata handler).
-    if (attrChildNode && attrChildNode->HasProperties()) {
-      nsCOMPtr<nsINode> clonedAttrChildNode = clone->GetChildAt(0);
-      if (clonedAttrChildNode) {
-        bool ok = aNodesWithProperties.AppendObject(attrChildNode) &&
-                    aNodesWithProperties.AppendObject(clonedAttrChildNode);
-        NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
-      }
-    }
-  }
-  // XXX End of workaround for broken attribute nodes.
-  else if (aDeep || aNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
+  if (aDeep && (!aClone || !aNode->IsNodeOfType(nsINode::eATTRIBUTE))) {
     // aNode's children.
     for (nsIContent* cloneChild = aNode->GetFirstChild();
          cloneChild;
-       cloneChild = cloneChild->GetNextSibling()) {
+         cloneChild = cloneChild->GetNextSibling()) {
       nsCOMPtr<nsINode> child;
       rv = CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager,
                          aCx, aNewScope, aNodesWithProperties, clone,
                          getter_AddRefs(child));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
--- a/content/base/src/nsNodeUtils.h
+++ b/content/base/src/nsNodeUtils.h
@@ -125,23 +125,16 @@ public:
    * @param aIndexInContainer Index of removed child
    * @see nsIMutationObserver::ContentRemoved
    */
   static void ContentRemoved(nsINode* aContainer,
                              nsIContent* aChild,
                              PRInt32 aIndexInContainer,
                              nsIContent* aPreviousSibling);
   /**
-   * Send AttributeChildRemoved notifications to nsIMutationObservers.
-   * @param aAttribute Attribute from which the child has been removed.
-   * @param aChild     Removed child.
-   * @see nsIMutationObserver2::AttributeChildRemoved.
-   */
-  static void AttributeChildRemoved(nsINode* aAttribute, nsIContent* aChild);
-  /**
    * Send ParentChainChanged notifications to nsIMutationObservers
    * @param aContent  The piece of content that had its parent changed.
    * @see nsIMutationObserver::ParentChainChanged
    */
   static inline void ParentChainChanged(nsIContent *aContent)
   {
     nsINode::nsSlots* slots = aContent->GetExistingSlots();
     if (slots && !slots->mMutationObservers.IsEmpty()) {
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -43,16 +43,17 @@
 #include "nscore.h"
 #include "nsRange.h"
 
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentFragment.h"
+#include "nsIDOMDocumentType.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMText.h"
 #include "nsDOMError.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMNodeList.h"
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
@@ -1521,16 +1522,36 @@ nsresult nsRange::CutContents(nsIDOMDocu
   // Save the range end points locally to avoid interference
   // of Range gravity during our edits!
 
   nsCOMPtr<nsIDOMNode> startContainer = do_QueryInterface(mStartParent);
   PRInt32              startOffset = mStartOffset;
   nsCOMPtr<nsIDOMNode> endContainer = do_QueryInterface(mEndParent);
   PRInt32              endOffset = mEndOffset;
 
+  if (retval) {
+    // For extractContents(), abort early if there's a doctype (bug 719533).
+    // This can happen only if the common ancestor is a document, in which case
+    // we just need to find its doctype child and check if that's in the range.
+    nsCOMPtr<nsIDOMDocument> commonAncestorDocument(do_QueryInterface(commonAncestor));
+    if (commonAncestorDocument) {
+      nsCOMPtr<nsIDOMDocumentType> doctype;
+      rv = commonAncestorDocument->GetDoctype(getter_AddRefs(doctype));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (doctype &&
+          nsContentUtils::ComparePoints(startContainer, startOffset,
+                                        doctype.get(), 0) < 0 &&
+          nsContentUtils::ComparePoints(doctype.get(), 0,
+                                        endContainer, endOffset) < 0) {
+        return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
+      }
+    }
+  }
+
   // Create and initialize a subtree iterator that will give
   // us all the subtrees within the range.
 
   RangeSubtreeIterator iter;
 
   rv = iter.Init(this);
   if (NS_FAILED(rv)) return rv;
 
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -424,18 +424,17 @@ nsScriptLoader::ProcessScriptElement(nsI
   if (!context || !context->GetScriptsEnabled()) {
     return false;
   }
 
   // Default script language is whatever the root element specifies
   // (which may come from a header or http-meta tag), or if there
   // is no root element, from the script global object.
   Element* rootElement = mDocument->GetRootElement();
-  PRUint32 typeID = rootElement ? rootElement->GetScriptTypeID() :
-                                  context->GetScriptTypeID();
+  PRUint32 typeID = nsIProgrammingLanguage::JAVASCRIPT;
   PRUint32 version = 0;
   nsAutoString language, type, src;
   nsresult rv = NS_OK;
 
   // Check the type attribute to determine language and version.
   // If type exists, it trumps the deprecated 'language='
   aElement->GetScriptType(type);
   if (!type.IsEmpty()) {
@@ -471,17 +470,17 @@ nsScriptLoader::ProcessScriptElement(nsI
       // Use the object factory to locate a matching language.
       nsCOMPtr<nsIScriptRuntime> runtime;
       rv = NS_GetScriptRuntime(mimeType, getter_AddRefs(runtime));
       if (NS_FAILED(rv) || runtime == nsnull) {
         // Failed to get the explicitly specified language
         NS_WARNING("Failed to find a scripting language");
         typeID = nsIProgrammingLanguage::UNKNOWN;
       } else
-        typeID = runtime->GetScriptTypeID();
+        typeID = nsIProgrammingLanguage::JAVASCRIPT;
     }
     if (typeID != nsIProgrammingLanguage::UNKNOWN) {
       // Get the version string, and ensure the language supports it.
       nsAutoString versionName;
       rv = parser.GetParameter("version", versionName);
       if (NS_FAILED(rv)) {
         // no version attribute - version remains 0.
         if (rv != NS_ERROR_INVALID_ARG)
@@ -551,18 +550,16 @@ nsScriptLoader::ProcessScriptElement(nsI
   // this isn't a priority.!
   // See also similar code in nsXULContentSink.cpp
   if (typeID != nsIProgrammingLanguage::JAVASCRIPT &&
       !nsContentUtils::IsChromeDoc(mDocument)) {
     NS_WARNING("Untrusted language called from non-chrome - ignored");
     return false;
   }
 
-  scriptContent->SetScriptTypeID(typeID);
-
   // Step 14. in the HTML5 spec
 
   nsRefPtr<nsScriptLoadRequest> request;
   if (aElement->GetScriptExternal()) {
     // external script
     nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
     if (!scriptURI) {
       return false;
@@ -881,18 +878,17 @@ nsScriptLoader::EvaluateScript(nsScriptL
   if (!pwin || !pwin->IsInnerWindow()) {
     return NS_ERROR_FAILURE;
   }
   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
   NS_ASSERTION(globalObject, "windows must be global objects");
 
   // Get the script-type to be used by this element.
   NS_ASSERTION(scriptContent, "no content - what is default script-type?");
-  PRUint32 stid = scriptContent ? scriptContent->GetScriptTypeID() :
-                                  nsIProgrammingLanguage::JAVASCRIPT;
+
   // and make sure we are setup for this type of script.
   rv = globalObject->EnsureScriptEnvironment();
   if (NS_FAILED(rv))
     return rv;
 
   // Make sure context is a strong reference since we access it after
   // we've executed a script, which may cause all other references to
   // the context to go away.
@@ -920,30 +916,19 @@ nsScriptLoader::EvaluateScript(nsScriptL
                                url.get(), aRequest->mLineNo,
                                JSVersion(aRequest->mJSVersion), nsnull,
                                &isUndefined);
 
   // Put the old script back in case it wants to do anything else.
   mCurrentScript = oldCurrent;
 
   JSContext *cx = nsnull; // Initialize this to keep GCC happy.
-  if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
-    cx = context->GetNativeContext();
-    ::JS_BeginRequest(cx);
-    NS_ASSERTION(!::JS_IsExceptionPending(cx),
-                 "JS_ReportPendingException wasn't called in EvaluateString");
-  }
-
+  cx = context->GetNativeContext();
+  JSAutoRequest ar(cx);
   context->SetProcessingScriptTag(oldProcessingScriptTag);
-
-  if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
-    NS_ASSERTION(!::JS_IsExceptionPending(cx),
-                 "JS_ReportPendingException wasn't called");
-    ::JS_EndRequest(cx);
-  }
   return rv;
 }
 
 void
 nsScriptLoader::ProcessPendingRequestsAsync()
 {
   if (mParserBlockingRequest || !mPendingChildLoaders.IsEmpty()) {
     nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
--- a/content/base/src/nsStubMutationObserver.cpp
+++ b/content/base/src/nsStubMutationObserver.cpp
@@ -41,11 +41,8 @@
  * used as a base class within the content/layout library.  All methods do
  * nothing.
  */
 
 #include "nsStubMutationObserver.h"
 
 NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver)
 NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(nsStubMutationObserver)
-
-NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver2)
-NS_IMPL_NSIMUTATIONOBSERVER2_CONTENT(nsStubMutationObserver2)
--- a/content/base/src/nsStubMutationObserver.h
+++ b/content/base/src/nsStubMutationObserver.h
@@ -41,30 +41,25 @@
  * used as a base class within the content/layout library.  All methods do
  * nothing.
  */
 
 #ifndef nsStubMutationObserver_h_
 #define nsStubMutationObserver_h_
 
 #include "nsIMutationObserver.h"
-#include "nsIMutationObserver2.h"
 
 /**
  * There are two advantages to inheriting from nsStubMutationObserver
  * rather than directly from nsIMutationObserver:
  *  1. smaller compiled code size (since there's no need for the code
  *     for the empty virtual function implementations for every
  *     nsIMutationObserver implementation)
  *  2. the performance of document's loop over observers benefits from
  *     the fact that more of the functions called are the same (which
  *     can reduce instruction cache misses and perhaps improve branch
  *     prediction)
  */
 class nsStubMutationObserver : public nsIMutationObserver {
   NS_DECL_NSIMUTATIONOBSERVER
 };
 
-class nsStubMutationObserver2 : public nsIMutationObserver2 {
-  NS_DECL_NSIMUTATIONOBSERVER2
-};
-
 #endif /* !defined(nsStubMutationObserver_h_) */
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -38,17 +38,16 @@
 /*
  * Implementation of DOM Core's nsIDOMText node.
  */
 
 #include "nsTextNode.h"
 #include "nsContentUtils.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMMutationEvent.h"
-#include "nsIAttribute.h"
 #include "nsIDocument.h"
 #include "nsThreadUtils.h"
 #ifdef DEBUG
 #include "nsRange.h"
 #endif
 
 using namespace mozilla::dom;
 
@@ -179,39 +178,16 @@ nsTextNode::CloneDataNode(nsINodeInfo *a
   nsTextNode *it = new nsTextNode(ni.forget());
   if (it && aCloneText) {
     it->mText = mText;
   }
 
   return it;
 }
 
-void
-nsTextNode::BindToAttribute(nsIAttribute* aAttr)
-{
-  NS_ASSERTION(!IsInDoc(), "Unbind before binding!");
-  NS_ASSERTION(!GetNodeParent(), "Unbind before binding!");
-  NS_ASSERTION(HasSameOwnerDoc(aAttr), "Wrong owner document!");
-
-  mParent = aAttr;
-  SetParentIsContent(false);
-  ClearInDocument();
-  SetSubtreeRootPointer(aAttr->SubtreeRoot());
-}
-
-void
-nsTextNode::UnbindFromAttribute()
-{
-  NS_ASSERTION(GetNodeParent(), "Bind before unbinding!");
-  NS_ASSERTION(GetNodeParent()->IsNodeOfType(nsINode::eATTRIBUTE),
-               "Use this method only to unbind from an attribute!");
-  mParent = nsnull;
-  SetSubtreeRootPointer(this);
-}
-
 nsresult
 nsTextNode::AppendTextForNormalize(const PRUnichar* aBuffer, PRUint32 aLength,
                                    bool aNotify, nsIContent* aNextSibling)
 {
   CharacterDataChangeInfo::Details details = {
     CharacterDataChangeInfo::Details::eMerge, aNextSibling
   };
   return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify, &details);
--- a/content/base/src/nsTextNode.h
+++ b/content/base/src/nsTextNode.h
@@ -37,20 +37,16 @@
 
 /*
  * Implementation of DOM Core's nsIDOMText node.
  */
 
 #include "nsGenericDOMDataNode.h"
 #include "nsIDOMText.h"
 
-#include "nsIAttribute.h"
-#include "nsIDocument.h"
-#include "nsThreadUtils.h"
-
 /**
  * Class used to implement DOM text nodes
  */
 class nsTextNode : public nsGenericDOMDataNode,
                    public nsIDOMText
 {
 public:
   nsTextNode(already_AddRefed<nsINodeInfo> aNodeInfo);
@@ -69,19 +65,16 @@ public:
   NS_FORWARD_NSIDOMTEXT(nsGenericDOMDataNode::)
 
   // nsINode
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
 
   virtual nsGenericDOMDataNode* CloneDataNode(nsINodeInfo *aNodeInfo,
                                               bool aCloneText) const;
 
-  void BindToAttribute(nsIAttribute* aAttr);
-  void UnbindFromAttribute();
-
   virtual nsXPCClassInfo* GetClassInfo();
 
   nsresult AppendTextForNormalize(const PRUnichar* aBuffer, PRUint32 aLength,
                                   bool aNotify, nsIContent* aNextSibling);
 
 #ifdef DEBUG
   virtual void List(FILE* out, PRInt32 aIndent) const;
   virtual void DumpContent(FILE* out, PRInt32 aIndent, bool aDumpAll) const;
--- a/content/base/src/nsTreeWalker.cpp
+++ b/content/base/src/nsTreeWalker.cpp
@@ -139,22 +139,23 @@ NS_IMETHODIMP nsTreeWalker::GetCurrentNo
 
     *aCurrentNode = nsnull;
 
     return NS_OK;
 }
 NS_IMETHODIMP nsTreeWalker::SetCurrentNode(nsIDOMNode * aCurrentNode)
 {
     NS_ENSURE_TRUE(aCurrentNode, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-
-    nsresult rv = nsContentUtils::CheckSameOrigin(mRoot, aCurrentNode);
-    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_TRUE(mRoot, NS_ERROR_UNEXPECTED);
 
     nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentNode);
-    NS_ENSURE_TRUE(node, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
+
+    nsresult rv = nsContentUtils::CheckSameOrigin(mRoot, node);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     mCurrentNode.swap(node);
     return NS_OK;
 }
 
 /*
  * nsIDOMTreeWalker functions
  */
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -100,16 +100,17 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "jstypedarray.h"
 #include "nsStringBuffer.h"
 #include "nsDOMFile.h"
 #include "nsIFileChannel.h"
 #include "mozilla/Telemetry.h"
 #include "sampler.h"
+#include "mozilla/dom/bindings/XMLHttpRequestBinding.h"
 #include "nsIDOMFormData.h"
 
 #include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define LOAD_STR "load"
@@ -478,16 +479,18 @@ nsXMLHttpRequest::nsXMLHttpRequest()
     mWarnAboutSyncHtml(false),
     mLoadLengthComputable(false), mLoadTotal(0),
     mFirstStartRequestSeen(false),
     mInLoadProgressEvent(false),
     mResultJSON(JSVAL_VOID),
     mResultArrayBuffer(nsnull)
 {
   nsLayoutStatics::AddRef();
+
+  SetIsDOMBinding();
 #ifdef DEBUG
   StaticAssertions();
 #endif
 }
 
 nsXMLHttpRequest::~nsXMLHttpRequest()
 {
   mState |= XML_HTTP_REQUEST_DELETED;
@@ -535,42 +538,42 @@ nsXMLHttpRequest::Init()
 
   nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
   nsCOMPtr<nsIPrincipal> subjectPrincipal;
   if (secMan) {
     nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   NS_ENSURE_STATE(subjectPrincipal);
-  mPrincipal = subjectPrincipal;
 
   nsIScriptContext* context = GetScriptContextFromJSContext(cx);
+  nsCOMPtr<nsPIDOMWindow> window;
   if (context) {
-    nsCOMPtr<nsPIDOMWindow> window =
-      do_QueryInterface(context->GetGlobalObject());
-    BindToOwner(window ? window->GetCurrentInnerWindow() : nsnull);
+    window = do_QueryInterface(context->GetGlobalObject());
+    if (window) {
+      window = window->GetCurrentInnerWindow();
+    }
   }
 
+  Construct(subjectPrincipal, window);
   return NS_OK;
 }
 /**
  * This Init method should only be called by C++ consumers.
  */
 NS_IMETHODIMP
 nsXMLHttpRequest::Init(nsIPrincipal* aPrincipal,
                        nsIScriptContext* aScriptContext,
                        nsPIDOMWindow* aOwnerWindow,
                        nsIURI* aBaseURI)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
-
-  mPrincipal = aPrincipal;
-  BindToOwner(aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nsnull);
-  mBaseURI = aBaseURI;
-
+  Construct(aPrincipal,
+            aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nsnull,
+            aBaseURI);
   return NS_OK;
 }
 
 /**
  * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
  */
 NS_IMETHODIMP
 nsXMLHttpRequest::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
@@ -581,19 +584,19 @@ nsXMLHttpRequest::Initialize(nsISupports
     NS_WARNING("Unexpected nsIJSNativeInitializer owner");
     return NS_OK;
   }
 
   // This XHR object is bound to a |window|,
   // so re-set principal and script context.
   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aOwner);
   NS_ENSURE_STATE(scriptPrincipal);
-  mPrincipal = scriptPrincipal->GetPrincipal();
-  BindToOwner(owner);
-  return NS_OK; 
+
+  Construct(scriptPrincipal->GetPrincipal(), owner);
+  return NS_OK;
 }
 
 void
 nsXMLHttpRequest::ResetResponse()
 {
   mResponseXML = nsnull;
   mResponseBody.Truncate();
   mResponseText.Truncate();
@@ -1082,16 +1085,25 @@ void
 nsXMLHttpRequest::StaticAssertions()
 {
 #define ASSERT_ENUM_EQUAL(_lc, _uc) \
   MOZ_STATIC_ASSERT(\
     bindings::prototypes::XMLHttpRequestResponseType::_lc \
       == bindings::prototypes::XMLHttpRequestResponseType::value(XML_HTTP_RESPONSE_TYPE_ ## _uc), \
     #_uc " should match")
 
+  ASSERT_ENUM_EQUAL(_empty, DEFAULT);
+  ASSERT_ENUM_EQUAL(arraybuffer, ARRAYBUFFER);
+  ASSERT_ENUM_EQUAL(blob, BLOB);
+  ASSERT_ENUM_EQUAL(document, DOCUMENT);
+  ASSERT_ENUM_EQUAL(json, JSON);
+  ASSERT_ENUM_EQUAL(text, TEXT);
+  ASSERT_ENUM_EQUAL(moz_chunked_text, CHUNKED_TEXT);
+  ASSERT_ENUM_EQUAL(moz_chunked_arraybuffer, CHUNKED_ARRAYBUFFER);
+  ASSERT_ENUM_EQUAL(moz_blob, MOZ_BLOB);
 #undef ASSERT_ENUM_EQUAL
 }
 #endif
 
 /* attribute AString responseType; */
 NS_IMETHODIMP nsXMLHttpRequest::SetResponseType(const nsAString& aResponseType)
 {
   nsXMLHttpRequest::ResponseType responseType;
@@ -1118,16 +1130,23 @@ NS_IMETHODIMP nsXMLHttpRequest::SetRespo
   }
 
   nsresult rv = NS_OK;
   SetResponseType(responseType, rv);
   return rv;
 }
 
 void
+nsXMLHttpRequest::SetResponseType(XMLHttpRequestResponseType aType,
+                                  nsresult& aRv)
+{
+  SetResponseType(ResponseType(aType), aRv);
+}
+
+void
 nsXMLHttpRequest::SetResponseType(nsXMLHttpRequest::ResponseType aResponseType,
                                   nsresult& aRv)
 {
   // If the state is not OPENED or HEADERS_RECEIVED raise an
   // INVALID_STATE_ERR exception and terminate these steps.
   if (!(mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT |
                   XML_HTTP_REQUEST_HEADERS_RECEIVED))) {
     aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
@@ -2701,25 +2720,25 @@ GetRequestBody(nsIVariant* aBody, nsIInp
   string.Adopt(data, len);
 
   return GetRequestBody(string, aResult, aContentType, aCharset);
 }
 
 /* static */
 nsresult
 nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
-                                 const RequestBody* aBody,
+                                 const Nullable<RequestBody>& aBody,
                                  nsIInputStream** aResult,
                                  nsACString& aContentType, nsACString& aCharset)
 {
   if (aVariant) {
     return ::GetRequestBody(aVariant, aResult, aContentType, aCharset);
   }
 
-  const RequestBody& body = *aBody;
+  const RequestBody& body = aBody.Value();
   RequestBody::Value value = body.GetValue();
   switch (body.GetType()) {
     case nsXMLHttpRequest::RequestBody::ArrayBuffer:
     {
       return ::GetRequestBody(value.mArrayBuffer, aResult, aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::Blob:
     {
@@ -2759,21 +2778,21 @@ nsXMLHttpRequest::GetRequestBody(nsIVari
   NS_NOTREACHED("Default cases exist for a reason");
   return NS_OK;
 }
 
 /* void send (in nsIVariant aBody); */
 NS_IMETHODIMP
 nsXMLHttpRequest::Send(nsIVariant *aBody)
 {
-  return Send(aBody, nsnull);
+  return Send(aBody, Nullable<RequestBody>());
 }
 
 nsresult
-nsXMLHttpRequest::Send(nsIVariant* aVariant, const RequestBody* aBody)
+nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
 {
   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
 
   nsresult rv = CheckInnerWindowCorrectness();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Return error if we're already processing a request
   if (XML_HTTP_REQUEST_SENT & mState) {
@@ -2880,17 +2899,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
   mUploadTotal = 0;
   // By default we don't have any upload, so mark upload complete.
   mUploadComplete = true;
   mErrorLoad = false;
   mLoadLengthComputable = false;
   mLoadTotal = 0;
   mUploadProgress = 0;
   mUploadProgressMax = 0;
-  if ((aVariant || aBody) && httpChannel &&
+  if ((aVariant || !aBody.IsNull()) && httpChannel &&
       !method.EqualsLiteral("GET")) {
 
     nsCAutoString charset;
     nsCAutoString defaultContentType;
     nsCOMPtr<nsIInputStream> postDataStream;
 
     rv = GetRequestBody(aVariant, aBody, getter_AddRefs(postDataStream),
                         defaultContentType, charset);
@@ -3108,23 +3127,27 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
           }
           suspendedWindow->SuspendTimeouts(1, false);
           resumeTimeoutRunnable = new nsResumeTimeoutsEvent(suspendedWindow);
         }
       }
     }
 
     ChangeState(XML_HTTP_REQUEST_SENT);
-    // Note, calling ChangeState may have cleared
-    // XML_HTTP_REQUEST_SYNCLOOPING flag.
-    nsIThread *thread = NS_GetCurrentThread();
-    while (mState & XML_HTTP_REQUEST_SYNCLOOPING) {
-      if (!NS_ProcessNextEvent(thread)) {
-        rv = NS_ERROR_UNEXPECTED;
-        break;
+
+    {
+      nsAutoSyncOperation sync(suspendedDoc);
+      // Note, calling ChangeState may have cleared
+      // XML_HTTP_REQUEST_SYNCLOOPING flag.
+      nsIThread *thread = NS_GetCurrentThread();
+      while (mState & XML_HTTP_REQUEST_SYNCLOOPING) {
+        if (!NS_ProcessNextEvent(thread)) {
+          rv = NS_ERROR_UNEXPECTED;
+          break;
+        }
       }
     }
 
     if (suspendedDoc) {
       suspendedDoc->UnsuppressEventHandlingAndFireEvents(true);
     }
 
     if (resumeTimeoutRunnable) {
@@ -3836,16 +3859,30 @@ nsXMLHttpRequest::GetInterface(const nsI
     return wwatch->GetPrompt(window, aIID,
                              reinterpret_cast<void**>(aResult));
 
   }
 
   return QueryInterface(aIID, aResult);
 }
 
+JS::Value
+nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSIID* aIID, nsresult& aRv)
+{
+  const nsID* iid = aIID->GetID();
+  nsCOMPtr<nsISupports> result;
+  JS::Value v = JSVAL_NULL;
+  aRv = GetInterface(*iid, getter_AddRefs(result));
+  NS_ENSURE_SUCCESS(aRv, JSVAL_NULL);
+
+  JSObject* global = JS_GetGlobalForObject(aCx, GetWrapper());
+  aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
+  return NS_SUCCEEDED(aRv) ? v : JSVAL_NULL;
+}
+
 nsXMLHttpRequestUpload*
 nsXMLHttpRequest::GetUpload()
 {
   if (!mUpload) {
     mUpload = new nsXMLHttpRequestUpload(this);
   }
   return mUpload;
 }
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -62,124 +62,87 @@
 #include "nsIDOMNSEvent.h"
 #include "nsITimer.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsDOMProgressEvent.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsContentUtils.h"
 #include "nsDOMFile.h"
 #include "nsDOMBlobBuilder.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "mozilla/dom/bindings/XMLHttpRequestBinding.h"
+#include "mozilla/dom/bindings/XMLHttpRequestUploadBinding.h"
+
+#include "mozilla/Assertions.h"
 
 class nsILoadGroup;
 class AsyncVerifyRedirectCallbackForwarder;
 class nsIUnicodeDecoder;
 class nsIDOMFormData;
 
+#define IMPL_EVENT_HANDLER(_lowercase, _capitalized)                    \
+  JSObject* GetOn##_lowercase()                                         \
+  {                                                                     \
+    return GetListenerAsJSObject(mOn##_capitalized##Listener);          \
+  }                                                                     \
+  void SetOn##_lowercase(JSContext* aCx, JSObject* aCallback, nsresult& aRv) \
+  {                                                                     \
+    aRv = SetJSObjectListener(aCx, NS_LITERAL_STRING(#_lowercase),      \
+                              mOn##_capitalized##Listener,              \
+                              aCallback);                               \
+  }
+
 class nsXHREventTarget : public nsDOMEventTargetHelper,
                          public nsIXMLHttpRequestEventTarget
 {
 public:
+  typedef mozilla::dom::bindings::prototypes::XMLHttpRequestResponseType::value
+          XMLHttpRequestResponseType;
+
   virtual ~nsXHREventTarget() {}
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXHREventTarget,
                                            nsDOMEventTargetHelper)
   NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
-  JSObject* GetOnloadstart()
-  {
-    return GetListenerAsJSObject(mOnLoadStartListener);
-  }
-  JSObject* GetOnprogress()
-  {
-    return GetListenerAsJSObject(mOnProgressListener);
-  }
-  JSObject* GetOnabort()
-  {
-    return GetListenerAsJSObject(mOnAbortListener);
-  }
-  JSObject* GetOnerror()
-  {
-    return GetListenerAsJSObject(mOnErrorListener);
-  }
-  JSObject* GetOnload()
-  {
-    return GetListenerAsJSObject(mOnLoadListener);
-  }
-  JSObject* GetOntimeout()
-  {
-    return GetListenerAsJSObject(mOnTimeoutListener);
-  }
-  JSObject* GetOnloadend()
-  {
-    return GetListenerAsJSObject(mOnLoadendListener);
-  }
-  void SetOnloadstart(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("loadstart"),
-                              mOnLoadStartListener,
-                              aCallback);
-  }
-  void SetOnprogress(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("progress"),
-                              mOnProgressListener,
-                              aCallback);
-  }
-  void SetOnabort(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("abort"), mOnAbortListener,
-                              aCallback);
-  }
-  void SetOnerror(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("error"), mOnErrorListener,
-                              aCallback);
-  }
-  void SetOnload(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("load"), mOnLoadListener,
-                              aCallback);
-  }
-  void SetOntimeout(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("timeout"),
-                              mOnTimeoutListener,
-                              aCallback);
-  }
-  void SetOnloadend(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("loadend"),
-                              mOnLoadendListener,
-                              aCallback);
-  }
-
+  IMPL_EVENT_HANDLER(loadstart, LoadStart)
+  IMPL_EVENT_HANDLER(progress, Progress)
+  IMPL_EVENT_HANDLER(abort, Abort)
+  IMPL_EVENT_HANDLER(error, Error)
+  IMPL_EVENT_HANDLER(load, Load)
+  IMPL_EVENT_HANDLER(timeout, Timeout)
+  IMPL_EVENT_HANDLER(loadend, Loadend)
+  
   virtual void DisconnectFromOwner();
 protected:
   static inline JSObject* GetListenerAsJSObject(nsDOMEventListenerWrapper* aWrapper)
   {
+    if (!aWrapper) {
+      return nsnull;
+    }
+
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder =
         do_QueryInterface(aWrapper->GetInner());
     JSObject* obj;
     return holder && NS_SUCCEEDED(holder->GetJSObject(&obj)) ? obj : nsnull;
   }
-  inline nsresult SetJSObjectListener(const nsAString& aType,
+  inline nsresult SetJSObjectListener(JSContext* aCx,
+                                      const nsAString& aType,
                                       nsRefPtr<nsDOMEventListenerWrapper>& aWrapper,
                                       JSObject* aCallback)
   {
-    nsresult rv;
-    nsIScriptContext* context = GetContextForEventHandlers(&rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     nsCOMPtr<nsIDOMEventListener> listener;
     if (aCallback) {
-      rv = nsContentUtils::XPConnect()->WrapJS(context->GetNativeContext(),
-                                               aCallback,
-                                               NS_GET_IID(nsIDOMEventListener),
-                                               getter_AddRefs(listener));
+      nsresult rv =
+        nsContentUtils::XPConnect()->WrapJS(aCx,
+                                            aCallback,
+                                            NS_GET_IID(nsIDOMEventListener),
+                                            getter_AddRefs(listener));
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return RemoveAddEventListener(aType, aWrapper, listener);
   }
 
   nsRefPtr<nsDOMEventListenerWrapper> mOnLoadListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
@@ -192,22 +155,33 @@ protected:
 
 class nsXMLHttpRequestUpload : public nsXHREventTarget,
                                public nsIXMLHttpRequestUpload
 {
 public:
   nsXMLHttpRequestUpload(nsDOMEventTargetHelper* aOwner)
   {
     BindToOwner(aOwner);
+    SetIsDOMBinding();
   }                                         
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
   NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
   NS_DECL_NSIXMLHTTPREQUESTUPLOAD
 
+  virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
+                               bool *triedToWrap)
+  {
+    return mozilla::dom::bindings::prototypes::XMLHttpRequestUpload::Wrap(cx, scope, this, triedToWrap);
+  }
+  nsISupports* GetParentObject()
+  {
+    return GetOwner();
+  }
+
   bool HasListeners()
   {
     return mListenerManager && mListenerManager->HasListeners();
   }
 };
 
 class nsXMLHttpRequest : public nsXHREventTarget,
                          public nsIXMLHttpRequest,
@@ -220,16 +194,53 @@ class nsXMLHttpRequest : public nsXHREve
                          public nsIJSNativeInitializer,
                          public nsITimerCallback
 {
   friend class nsXHRParseEndListener;
 public:
   nsXMLHttpRequest();
   virtual ~nsXMLHttpRequest();
 
+  virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
+                               bool *triedToWrap)
+  {
+    return mozilla::dom::bindings::prototypes::XMLHttpRequest::Wrap(cx, scope, this, triedToWrap);
+  }
+  nsISupports* GetParentObject()
+  {
+    return GetOwner();
+  }
+
+  // The WebIDL parser converts constructors into methods called _Constructor.
+  static already_AddRefed<nsXMLHttpRequest>
+  _Constructor(nsISupports* aGlobal, nsresult& aRv)
+  {
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
+    nsCOMPtr<nsIScriptObjectPrincipal> principal = do_QueryInterface(aGlobal);
+    if (!window || ! principal) {
+      aRv = NS_ERROR_FAILURE;
+      return NULL;
+    }
+
+    nsRefPtr<nsXMLHttpRequest> req = new nsXMLHttpRequest();
+    req->Construct(principal->GetPrincipal(), window);
+    return req.forget();
+  }
+
+  void Construct(nsIPrincipal* aPrincipal,
+                 nsPIDOMWindow* aOwnerWindow,
+                 nsIURI* aBaseURI = NULL)
+  {
+    MOZ_ASSERT(aPrincipal);
+    MOZ_ASSERT_IF(aOwnerWindow, aOwnerWindow->IsInnerWindow());
+    mPrincipal = aPrincipal;
+    BindToOwner(aOwnerWindow);
+    mBaseURI = aBaseURI;
+  }
+
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIXMLHttpRequest
   NS_DECL_NSIXMLHTTPREQUEST
 
   // nsIJSXMLHttpRequest
   NS_IMETHOD GetOnuploadprogress(nsIDOMEventListener** aOnuploadprogress);
   NS_IMETHOD SetOnuploadprogress(nsIDOMEventListener* aOnuploadprogress);
@@ -260,26 +271,17 @@ public:
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
 
 #ifdef DEBUG
   void StaticAssertions();
 #endif
 
   // event handler
-  JSObject* GetOnreadystatechange()
-  {
-    return GetListenerAsJSObject(mOnReadystatechangeListener);
-  }
-  void SetOnreadystatechange(JSObject* aCallback, nsresult& aRv)
-  {
-    aRv = SetJSObjectListener(NS_LITERAL_STRING("readystatechange"),
-                              mOnReadystatechangeListener,
-                              aCallback);
-  }
+  IMPL_EVENT_HANDLER(readystatechange, Readystatechange)
 
   // states
   uint16_t GetReadyState();
 
   // request
   void Open(const nsAString& aMethod, const nsAString& aUrl, bool aAsync,
             const nsAString& aUser, const nsAString& aPassword, nsresult& aRv)
   {
@@ -363,31 +365,35 @@ private:
     }
 
   private:
     Type mType;
     Value mValue;
   };
 
   static nsresult GetRequestBody(nsIVariant* aVariant,
-                                 const RequestBody* aBody,
+                                 const Nullable<RequestBody>& aBody,
                                  nsIInputStream** aResult,
                                  nsACString& aContentType,
                                  nsACString& aCharset);
 
-  nsresult Send(nsIVariant* aVariant, const RequestBody* aBody);
+  nsresult Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody);
+  nsresult Send(const Nullable<RequestBody>& aBody)
+  {
+    return Send(nsnull, aBody);
+  }
   nsresult Send(const RequestBody& aBody)
   {
-    return Send(nsnull, &aBody);
+    return Send(Nullable<RequestBody>(aBody));
   }
 
 public:
   void Send(nsresult& aRv)
   {
-    aRv = Send(nsnull, nsnull);
+    aRv = Send(Nullable<RequestBody>());
   }
   void Send(JSObject* aArrayBuffer, nsresult& aRv)
   {
     NS_ASSERTION(aArrayBuffer, "Null should go to string version");
     aRv = Send(RequestBody(aArrayBuffer));
   }
   void Send(nsIDOMBlob* aBlob, nsresult& aRv)
   {
@@ -444,30 +450,38 @@ public:
     }
   }
   void GetAllResponseHeaders(nsString& aResponseHeaders);
   void OverrideMimeType(const nsAString& aMimeType)
   {
     // XXX Should we do some validation here?
     mOverrideMimeType = aMimeType;
   }
+  XMLHttpRequestResponseType GetResponseType()
+  {
+    return XMLHttpRequestResponseType(mResponseType);
+  }
+  void SetResponseType(XMLHttpRequestResponseType aType, nsresult& aRv);
   JS::Value GetResponse(JSContext* aCx, nsresult& aRv);
   void GetResponseText(nsString& aResponseText, nsresult& aRv);
   nsIDocument* GetResponseXML(nsresult& aRv);
 
   bool GetMozBackgroundRequest();
   void SetMozBackgroundRequest(bool aMozBackgroundRequest, nsresult& aRv);
   bool GetMultipart();
   void SetMultipart(bool aMultipart, nsresult& aRv);
 
   nsIChannel* GetChannel()
   {
     return mChannel;
   }
 
+  // We need a GetInterface callable from JS for chrome JS
+  JS::Value GetInterface(JSContext*aCx, nsIJSIID* aIID, nsresult& aRv);
+
   // This creates a trusted readystatechange event, which is not cancelable and
   // doesn't bubble.
   static nsresult CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent);
   // For backwards compatibility aPosition should contain the headers for upload
   // and aTotalSize is LL_MAXUINT when unknown. Both those values are
   // used by nsXMLHttpProgressEvent. Normal progress event should not use
   // headers in aLoaded and aTotal is 0 when unknown.
   void DispatchProgressEvent(nsDOMEventTargetHelper* aTarget,
@@ -707,16 +721,18 @@ protected:
   struct RequestHeader
   {
     nsCString header;
     nsCString value;
   };
   nsTArray<RequestHeader> mModifiedRequestHeaders;
 };
 
+#undef IMPL_EVENT_HANDLER
+
 // helper class to expose a progress DOM Event
 
 class nsXMLHttpProgressEvent : public nsIDOMProgressEvent,
                                public nsIDOMLSProgressEvent,
                                public nsIDOMNSEvent,
                                public nsIPrivateDOMEvent
 {
 public:
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -280,16 +280,17 @@ include $(topsrcdir)/config/rules.mk
 		test_CrossSiteXHR_cache.html \
 		file_CrossSiteXHR_cache_server.sjs \
 		test_XHRDocURI.html \
 		file_XHRDocURI.xml \
 		file_XHRDocURI.xml^headers^ \
 		file_XHRDocURI.text \
 		file_XHRDocURI.text^headers^ \
 		test_DOMException.html \
+		test_mutationobservers.html \
 		$(NULL)
 
 _TEST_FILES2 = \
 		test_bug459424.html \
 		bug461735-redirect1.sjs \
 		bug461735-redirect2.sjs \
 		bug461735-post-redirect.js \
 		test_bug513194.html \
@@ -435,21 +436,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug564047.html \
 		test_bug567350.html \
 		test_bug578096.html \
 		test_bug585978.html \
 		test_bug592366.html \
 		test_bug597345.html \
 		script-1_bug597345.sjs \
 		script-2_bug597345.js \
-		test_bug598877.html \
 		test_bug599588.html \
-		test_bug600466.html \
-		test_bug600468.html \
-		test_bug600471.html \
 		test_bug601803.html \
 		file_bug601803a.html \
 		file_bug601803b.html \
 		test_bug602838.html \
 		script_bug602838.sjs \
 		test_bug614583.html \
 		test_bug604660.html \
 		file_bug604660-1.xml \
@@ -457,17 +454,16 @@ include $(topsrcdir)/config/rules.mk
 		file_bug604660-3.js \
 		file_bug604660-4.js \
 		file_bug604660-5.xml \
 		file_bug604660-6.xsl \
 		test_bug605982.html \
 		test_bug606729.html \
 		test_treewalker_nextsibling.xml \
 		test_bug614058.html \
-		test_bug590771.html \
 		test_bug622117.html \
 		test_base.xhtml \
 		file_base_xbl.xml \
 		test_bug622246.html \
 		test_bug484396.html \
 		test_bug466080.html \
 		bug466080.sjs \
 		test_bug625722.html \
@@ -573,16 +569,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug738108.html \
 		test_bug366944.html \
 		test_bug650386_redirect_301.html \
 		test_bug650386_redirect_302.html \
 		test_bug650386_redirect_303.html \
 		test_bug650386_redirect_307.html \
 		file_bug650386_content.sjs \
 		file_bug650386_report.sjs \
+		test_bug719533.html \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
--- a/content/base/test/test_bug383430.html
+++ b/content/base/test/test_bug383430.html
@@ -20,13 +20,13 @@ https://bugzilla.mozilla.org/show_bug.cg
 /** Test for Bug 383430 **/
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
 var req = new XMLHttpRequest();
 req.mozBackgroundRequest = true;
 req.open("GET", window.location.href);
 req.send(null);
 
-ok(req.channel.loadGroup == null, "loadGroup is null");
+ok(SpecialPowers.wrap(req).channel.loadGroup == null, "loadGroup is null");
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_bug393968.html
+++ b/content/base/test/test_bug393968.html
@@ -18,18 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 393968 **/
 var req = new XMLHttpRequest();
 req.open("POST", window.location.href);
 req.setRequestHeader("Content-Type", "text/plain; charset=us-ascii; boundary=01234567890");
 req.send("Some text");
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-is(req.channel
+is(SpecialPowers.wrap(req).channel
       .QueryInterface(Components.interfaces.nsIHttpChannel)
       .getRequestHeader("Content-Type"),
    "text/plain; charset=UTF-8; boundary=01234567890",
    "Headers should match");
 
 </script>
 </pre>
 </body>
--- a/content/base/test/test_bug397234.html
+++ b/content/base/test/test_bug397234.html
@@ -19,18 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 397234 **/
 var req = new XMLHttpRequest();
 req.open("POST", window.location.href);
 // Capitalization of charet param is on purpose!
 req.setRequestHeader("Content-Type", "text/plain; charset='uTf-8'");
 req.send("Some text");
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-is(req.channel
+is(SpecialPowers.wrap(req).channel
       .QueryInterface(Components.interfaces.nsIHttpChannel)
       .getRequestHeader("Content-Type"),
    "text/plain; charset='uTf-8'",
    "Headers should match");
 
 </script>
 </pre>
 </body>
--- a/content/base/test/test_bug413974.html
+++ b/content/base/test/test_bug413974.html
@@ -18,18 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 413974 **/
 var req = new XMLHttpRequest();
 req.open("POST", window.location.href);
 req.setRequestHeader("Content-Type", "text/plain; boundary=01234567890");
 req.send("Some text");
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-is(req.channel
+is(SpecialPowers.wrap(req).channel
       .QueryInterface(Components.interfaces.nsIHttpChannel)
       .getRequestHeader("Content-Type"),
    "text/plain; charset=UTF-8; boundary=01234567890",
    "Charset should come before boundary");
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_bug422537.html
+++ b/content/base/test/test_bug422537.html
@@ -31,17 +31,17 @@ var body = [
   "foo",
   isupports_string
 ];
 
 for each (var i in body) {
   var xhr = new XMLHttpRequest();
   xhr.open("POST", url, true);
   xhr.send(i);
-  var chan = xhr.channel;
+  var chan = SpecialPowers.unwrap(SpecialPowers.wrap(xhr).channel);
   if (!(chan instanceof Components.interfaces.nsIUploadChannel))
     throw "Must be an upload channel";
   var stream = chan.uploadStream;
   if (!stream || !(stream instanceof Components.interfaces.nsISeekableStream))
     throw "Stream must be seekable";
   // the following is a no-op, but should not throw an exception
   stream.seek(Components.interfaces.nsISeekableStream.NS_SEEK_CUR, 0);
 }
--- a/content/base/test/test_bug431701.html
+++ b/content/base/test/test_bug431701.html
@@ -93,18 +93,17 @@ addLoadEvent(function() {
   for (var i = 0; i < tests.length; ++i) {
     doTest(i);
   }
 
   // Now check what xhr does
   var xhr = new XMLHttpRequest();
   xhr.open("POST", document.location.href);
   xhr.send(createDoc());
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  is(xhr.channel.QueryInterface(Components.interfaces.nsIHttpChannel)
+  is(SpecialPowers.wrap(xhr).channel.QueryInterface(Components.interfaces.nsIHttpChannel)
                 .getRequestHeader("Content-Type"),
      "application/xml; charset=UTF-8", "Testing correct type on the wire");
   xhr.abort();
                      
   SimpleTest.finish();
 });
 
 
--- a/content/base/test/test_bug475156.html
+++ b/content/base/test/test_bug475156.html
@@ -12,18 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 var path = "http://mochi.test:8888/tests/content/base/test/";
 
 function fromCache(xhr)
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var ch = xhr.channel.QueryInterface(Components.interfaces.nsICachingChannel);
+  var ch = SpecialPowers.wrap(xhr).channel.QueryInterface(Components.interfaces.nsICachingChannel);
   return ch.isFromCache();  
 }
 
 var tests = [
   // First just init the file with an ETag
   {
     init: function(xhr) 
     {
deleted file mode 100644
--- a/content/base/test/test_bug590771.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=590771
--->
-<head>
-  <title>Test for Bug 590771</title>
-  <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=590771">Mozilla Bug 590771</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 590771 **/
-
-function test1()
-{
-  var attr = document.createAttribute("foo");
-  attr.value = "bar";
-  var ni = document.createNodeIterator(attr, -1, null, false);
-  ni.nextNode();
-  ni.nextNode();
-  is(ni.referenceNode, attr.firstChild,
-      "iterator should be on the first child attribute");
-
-  attr.removeChild(attr.firstChild);
-  is(ni.referenceNode, attr,
-     "iterator should be on the attribute now");
-}
-
-function test2()
-{
-  var attr = document.createAttribute("foo");
-  attr.value = "bar";
-  var ni = document.createNodeIterator(attr, -1, null, false);
-  ni.nextNode();
-  ni.nextNode();
-  is(ni.referenceNode, attr.firstChild,
-      "iterator should be on the first child attribute");
-
-  attr.value = "";
-  is(ni.referenceNode, attr,
-     "iterator should be on the attribute now");
-}
-
-function test3()
-{
-  var attr = document.createAttribute("foo");
-  attr.value = "bar";
-  var node = document.createElement("div");
-  node.setAttributeNode(attr);
-  var ni = document.createNodeIterator(attr, -1, null, false);
-  ni.nextNode();
-  ni.nextNode();
-  is(ni.referenceNode, attr.firstChild,
-      "iterator should be on the first child attribute");
-
-  node.setAttribute("foo", "");
-  is(ni.referenceNode, attr,
-     "iterator should be on the attribute now");
-}
-
-test1();
-test2();
-test3();
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug598877.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=598877
--->
-<head>
-  <title>Test for Bug 598877</title>
-  <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=598877">Mozilla Bug 598877</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 598877 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-ok(attr.firstChild, "attr.firstChild should be a text node");
-is(attr.firstChild.nodeValue, "bar", "the text node value should be 'bar'");
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug600466.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=600466
--->
-<head>
-  <title>Test for Bug 600466</title>
-  <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=600466">Mozilla Bug 600466</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 600466 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-ok(attr.firstChild, "attr should have a first child");
-
-attr.removeChild(attr.firstChild);
-ok(!attr.firstChild, "attr should not have a first child anymore");
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug600468.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=600468
--->
-<head>
-  <title>Test for Bug 600468</title>
-  <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=600468">Mozilla Bug 600468</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 600468 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-ok(attr.firstChild, "attr should have a first child");
-
-attr.value = "";
-ok(!attr.firstChild, "attr should not have a first child");
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug600471.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=600471
--->
-<head>
-  <title>Test for Bug 600471</title>
-  <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=600471">Mozilla Bug 600471</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 600471 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-var node = document.createElement("div");
-node.setAttributeNode(attr);
-
-node.setAttribute("foo", "newvalue");
-is(attr.firstChild.nodeValue, "newvalue", "the value should be updated");
-
-</script>
-</pre>
-</body>
-</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug719533.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=719544
+-->
+<title>Test for Bug 719544</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=719544">Mozilla Bug 719544</a>
+<script>
+
+/** Test for Bug 719544 **/
+var threw = false;
+var origLength = document.childNodes.length;
+try {
+  var range = document.createRange();
+  range.selectNodeContents(document);
+  range.extractContents();
+} catch(e) {
+  threw = true;
+  is(Object.getPrototypeOf(e), DOMException.prototype,
+     "Must throw DOMException");
+  is(e.name, "HierarchyRequestError", "Must throw HierarchyRequestError");
+}
+ok(threw, "Must throw");
+is(document.childNodes.length, origLength, "Must preserve original children");
+
+</script>
--- a/content/base/test/test_copypaste.html
+++ b/content/base/test/test_copypaste.html
@@ -127,45 +127,45 @@ function testCopyPaste () {
   testClipboardValue("text/unicode",
                      "This is a draggable bit of text.");
   testClipboardValue("text/html",
                      "<div id=\"draggable\" title=\"title to have a long HTML line\">This is a <em>draggable</em> bit of text.</div>");
   testPasteText("This is a draggable bit of text.");
 
   copyChildrenToClipboard("alist");
   testSelectionToString(" bla\n\n    foo\n    bar\n\n");
-  testClipboardValue("text/unicode", "bla\n\n    foo\n    bar\n\n");
+  testClipboardValue("text/unicode", " bla\n\n    foo\n    bar\n\n");
   testClipboardValue("text/html", "<div id=\"alist\">\n    bla\n    <ul>\n      <li>foo</li>\n      \n      <li>bar</li>\n    </ul>\n  </div>");
-  testPasteText("bla\n\n    foo\n    bar\n\n");
+  testPasteText(" bla\n\n    foo\n    bar\n\n");
 
   copyChildrenToClipboard("blist");
   testSelectionToString(" mozilla\n\n    foo\n    bar\n\n");
-  testClipboardValue("text/unicode", "mozilla\n\n    foo\n    bar\n\n");
+  testClipboardValue("text/unicode", " mozilla\n\n    foo\n    bar\n\n");
   testClipboardValue("text/html", "<div id=\"blist\">\n    mozilla\n    <ol>\n      <li>foo</li>\n      \n      <li>bar</li>\n    </ol>\n  </div>");
-  testPasteText("mozilla\n\n    foo\n    bar\n\n");
+  testPasteText(" mozilla\n\n    foo\n    bar\n\n");
 
   copyChildrenToClipboard("clist");
   testSelectionToString(" mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
-  testClipboardValue("text/unicode", "mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
+  testClipboardValue("text/unicode", " mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
   testClipboardValue("text/html", "<div id=\"clist\">\n    mzla\n    <ul>\n      <li>foo<ul>\n        <li>bazzinga!</li>\n      </ul></li>\n      \n      <li>bar</li>\n    </ul>\n  </div>");
-  testPasteText("mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
+  testPasteText(" mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
 
   copyChildrenToClipboard("div4");
   testSelectionToString(" Tt t t ");
-  testClipboardValue("text/unicode", "Tt t t ");
+  testClipboardValue("text/unicode", " Tt t t ");
   testClipboardValue("text/html", "<div id=\"div4\">\n  T<textarea>t t t</textarea>\n</div>");
   testInnerHTML("div4", "\n  T<textarea>t t t</textarea>\n");
-  testPasteText("Tt t t ");
+  testPasteText(" Tt t t ");
 
   copyChildrenToClipboard("div5");
   testSelectionToString(" T ");
-  testClipboardValue("text/unicode", "T ");
+  testClipboardValue("text/unicode", " T ");
   testClipboardValue("text/html", "<div id=\"div5\">\n  T<textarea>     </textarea>\n</div>");
   testInnerHTML("div5", "\n  T<textarea>     </textarea>\n");
-  testPasteText("T ");
+  testPasteText(" T ");
 
   copyRangeToClipboard($("div6").childNodes[0],0, $("div6").childNodes[1],1);
   testSelectionToString("");
 // START Disabled due to bug 564688
 if (false) {
   testClipboardValue("text/unicode", "");
   testClipboardValue("text/html", "");
 }
@@ -226,16 +226,21 @@ if (false) {
   // ============ NOSCRIPT should not be copied
 
   copyChildrenToClipboard("div13");
   testSelectionToString("__");
   testClipboardValue("text/unicode", "__");
   testClipboardValue("text/html", "<div id=\"div13\">__</div>");
   testPasteText("__");
 
+  // ============ converting cell boundaries to tabs in tables
+
+  copyToClipboard($("tr1"));
+  testClipboardValue("text/unicode", "foo\tbar");
+
   // ============ manipulating Selection in oncopy
 
   copyRangeToClipboard($("div11").childNodes[0],0, $("div11").childNodes[1],2);
   testClipboardValue("text/unicode", "Xdiv11");
   testClipboardValue("text/html", "<div><p>X<span>div</span>11</p></div>");
   setTimeout(function(){testSelectionToString("div11")},0);
 
   setTimeout(function(){
@@ -315,11 +320,13 @@ x.appendChild(document.createTextNode('d
 x.appendChild(document.createTextNode('10'))
 </script>
 
 <div id="div11" oncopy="modifySelection('X')"><span>div</span>11</div>
 <div id="div12" oncopy="modifySelection('X<b style=\'display:none\'>Y</b>')"><span>div</span>12</div>
 
 <div id="div13">_<noscript>FAIL</noscript>_</div>
 
+<table><tr id=tr1><td>foo</td><td>bar</td></tr></table>
+
 </div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_mutationobservers.html
@@ -0,0 +1,467 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=641821
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 641821</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest()">                                                  
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=641821">Mozilla Bug 641821</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+                                
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 641821 **/
+
+var div = document.createElement("div");
+
+var M;
+if ("MozMutationObserver" in window) {
+  M = window.MozMutationObserver;
+} else if ("WebKitMutationObserver" in window) {
+  M = window.WebKitMutationObserver;
+} else {
+  M = window.MutationObserver;
+}
+
+function log(str) {
+  var d = document.createElement("div");
+  d.textContent = str;
+  if (str.indexOf("PASSED") >= 0) {
+    d.setAttribute("style", "color: green;");
+  } else {
+    d.setAttribute("style", "color: red;");
+  }
+  document.getElementById("log").appendChild(d);
+}
+
+// Some helper functions so that this test runs also outside mochitest.
+if (!("ok" in window)) {
+  window.ok = function(val, str) {
+    log(str + (val ? " PASSED\n" : " FAILED\n"));
+  }
+}
+
+if (!("is" in window)) {
+  window.is = function(val, refVal, str) {
+    log(str + (val == refVal? " PASSED " : " FAILED ") + 
+        (val != refVal ? "expected " + refVal + " got " + val + "\n" : "\n"));
+  }
+}
+
+if (!("isnot" in window)) {
+  window.isnot = function(val, refVal, str) {
+    log(str + (val != refVal? " PASSED " : " FAILED ") + 
+        (val == refVal ? "Didn't expect " + refVal + "\n" : "\n"));
+  }
+}
+
+if (!("SimpleTest" in window)) {
+  window.SimpleTest =
+  {
+    finish: function() {
+      document.getElementById("log").appendChild(document.createTextNode("DONE"));
+    },
+    waitForExplicitFinish: function() {}
+  }
+}
+
+function then(thenFn) {
+  setTimeout(function() {
+    if (thenFn) {
+      setTimeout(thenFn, 0);
+    } else {
+      SimpleTest.finish();
+    }
+  }, 0);
+}
+
+var m;
+var m2;
+var m3;
+var m4;
+
+// Checks basic parameter validation and normal 'this' handling.
+// Tests also basic attribute handling.
+function runTest() {
+  m = new M(function(){});
+  ok(m, "MutationObserver supported");
+
+  var e = null;
+  try {
+    m.observe(document, {});
+  } catch (ex) {
+    e = ex;
+  }
+  ok(e, "Should have thrown an exception");
+  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+
+  e = null;
+  try {
+    m.observe(document, { childList: true, attributeOldValue: true });
+  } catch (ex) {
+    e = ex;
+  }
+  ok(e, "Should have thrown an exception");
+  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+
+  e = null;
+  try {
+    m.observe(document, { childList: true, attributeFilter: ["foo"] });
+  } catch (ex) {
+    e = ex;
+  }
+  ok(e, "Should have thrown an exception");
+  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+
+  e = null;
+  try {
+    m.observe(document, { childList: true, characterDataOldValue: true });
+  } catch (ex) {
+    e = ex;
+  }
+  ok(e, "Should have thrown an exception");
+  is(e.code, DOMException.SYNTAX_ERR, "Should have thrown DOMException.SYNTAX_ERR");
+
+  e = null;
+  try {
+    m.observe(document);
+  } catch (ex) {
+    e = ex;
+  }
+  ok(e, "Should have thrown an exception");  
+
+  m = new M(function(records, observer) {
+      is(observer, m, "2nd parameter should be the mutation observer");
+      is(observer, this, "2nd parameter should be 'this'");
+      is(records.length, 1, "Should have one record.");
+      is(records[0].type, "attributes", "Should have got attributes record");
+      is(records[0].target, div, "Should have got div as target");
+      is(records[0].attributeName, "foo", "Should have got record about foo attribute");
+      observer.disconnect();
+      then(testThisBind);
+      m = null;
+    });
+  m.observe(div, { attributes: true});
+  div.setAttribute("foo", "bar");
+}
+
+// 'this' handling when fn.bind() is used.
+function testThisBind() {
+  var child = div.appendChild(document.createElement("div"));
+  var gchild = child.appendChild(document.createElement("div"));
+  m = new M((function(records, observer) {
+      is(observer, m, "2nd parameter should be the mutation observer");
+      isnot(observer, this, "2nd parameter should be 'this'");
+      is(records.length, 3, "Should have one record.");
+      is(records[0].type, "attributes", "Should have got attributes record");
+      is(records[0].target, div, "Should have got div as target");
+      is(records[0].attributeName, "foo", "Should have got record about foo attribute");
+      is(records[0].oldValue, "bar", "oldValue should be bar");
+      is(records[1].type, "attributes", "Should have got attributes record");
+      is(records[1].target, div, "Should have got div as target");
+      is(records[1].attributeName, "foo", "Should have got record about foo attribute");
+      is(records[1].oldValue, "bar2", "oldValue should be bar2");
+      is(records[2].type, "attributes", "Should have got attributes record");
+      is(records[2].target, gchild, "Should have got div as target");
+      is(records[2].attributeName, "foo", "Should have got record about foo attribute");
+      is(records[2].oldValue, null, "oldValue should be bar2");
+      observer.disconnect();
+      then(testCharacterData);
+      m = null;
+    }).bind(window));
+  m.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
+  div.setAttribute("foo", "bar2");
+  div.removeAttribute("foo");
+  div.removeChild(child);
+  child.removeChild(gchild);
+  div.appendChild(gchild);
+  div.removeChild(gchild);
+  gchild.setAttribute("foo", "bar");
+}
+
+function testCharacterData() {
+  m = new M(function(records, observer) {
+      is(records[0].type, "characterData", "Should have got characterData");
+      is(records[0].oldValue, null, "Shouldn't have got oldData");
+      observer.disconnect();
+      m = null;
+    });
+  m2 = new M(function(records, observer) {
+      is(records[0].type, "characterData", "Should have got characterData");
+      is(records[0].oldValue, "foo", "Should have got oldData");
+      observer.disconnect();
+      m2 = null;
+    });
+  m3 = new M(function(records, observer) {
+      ok(false, "This should not be called!");
+      observer.disconnect();
+      m3 = null;
+    });
+  m4 = new M(function(records, observer) {
+      is(records[0].oldValue, null, "Shouldn't have got oldData");
+      observer.disconnect();
+      m3.disconnect();
+      m3 = null;
+      then(testChildList);
+      m4 = null;
+    });
+
+  div.appendChild(document.createTextNode("foo"));
+  m.observe(div, { characterData: true, subtree: true });
+  m2.observe(div, { characterData: true, characterDataOldValue: true, subtree: true});
+  // If observing the same node twice, only the latter option should apply.
+  m3.observe(div, { characterData: true, subtree: true });
+  m3.observe(div, { characterData: true, subtree: false });
+  m4.observe(div.firstChild, { characterData: true, subtree: false });
+  div.firstChild.data = "bar";
+}
+
+function testChildList() {
+  var fc = div.firstChild;
+  m = new M(function(records, observer) {
+      is(records[0].type, "childList", "Should have got childList");
+      is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
+      is(records[0].removedNodes.length, 1, "Should have got removedNodes");
+      is(records[0].removedNodes[0], fc, "Should have removed a text node");
+      observer.disconnect();
+      then(testChildList2);
+      m = null;
+    });
+  m.observe(div, { childList: true});
+  div.removeChild(div.firstChild);
+}
+
+function testChildList2() {
+  div.innerHTML = "<span>1</span><span>2</span>";
+  m = new M(function(records, observer) {
+      is(records[0].type, "childList", "Should have got childList");
+      is(records[0].removedNodes.length, 2, "Should have got removedNodes");
+      is(records[0].addedNode