Merge mozilla-central to build-system.
authorMitchell Field <mitchell.field@live.com.au>
Sat, 09 Apr 2011 05:15:19 +1000
changeset 67705 877127eae177507f65bc689347f26e28789524bb
parent 67704 0492a8954c054849d246ea02de01a67e449b6a30 (current diff)
parent 67672 4f957dd3f9f79e175d7cb78faaf59a4e74fc10bd (diff)
child 67706 f858cc85724a1ae4d4a4ca8f0dae1867c21b7207
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.2a1pre
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 mozilla-central to build-system.
mobile/.hgignore
mobile/.hgtags
mobile/app/macbuild/.DS_Store
mobile/app/macbuild/CVS/Entries
mobile/app/macbuild/CVS/Repository
mobile/app/macbuild/CVS/Root
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -152,21 +152,22 @@ void
 NotificationController::ScheduleContentInsertion(nsAccessible* aContainer,
                                                  nsIContent* aStartChildNode,
                                                  nsIContent* aEndChildNode)
 {
   // Ignore content insertions until we constructed accessible tree.
   if (mTreeConstructedState == eTreeConstructionPending)
     return;
 
-  nsRefPtr<ContentInsertion> insertion =
-    new ContentInsertion(mDocument, aContainer, aStartChildNode, aEndChildNode);
-
-  if (insertion && mContentInsertions.AppendElement(insertion))
+  nsRefPtr<ContentInsertion> insertion = new ContentInsertion(mDocument,
+                                                              aContainer);
+  if (insertion && insertion->InitChildList(aStartChildNode, aEndChildNode) &&
+      mContentInsertions.AppendElement(insertion)) {
     ScheduleProcessing();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: protected
 
 void
 NotificationController::ScheduleProcessing()
 {
@@ -676,25 +677,41 @@ NotificationController::TextEnumerator(n
   return PL_DHASH_NEXT;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationController: content inserted notification
 
 NotificationController::ContentInsertion::
-  ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer,
-                   nsIContent* aStartChildNode, nsIContent* aEndChildNode) :
+  ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer) :
   mDocument(aDocument), mContainer(aContainer)
 {
+}
+
+bool
+NotificationController::ContentInsertion::
+  InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode)
+{
+  bool haveToUpdate = false;
+
   nsIContent* node = aStartChildNode;
   while (node != aEndChildNode) {
-    mInsertedContent.AppendElement(node);
+    // Notification triggers for content insertion even if no content was
+    // actually inserted, check if the given content has a frame to discard
+    // this case early.
+    if (node->GetPrimaryFrame()) {
+      if (mInsertedContent.AppendElement(node))
+        haveToUpdate = true;
+    }
+
     node = node->GetNextSibling();
   }
+
+  return haveToUpdate;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationController::ContentInsertion)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(NotificationController::ContentInsertion)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContainer)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
--- a/accessible/src/base/NotificationController.h
+++ b/accessible/src/base/NotificationController.h
@@ -316,23 +316,23 @@ private:
   nsTArray<nsRefPtr<nsDocAccessible> > mHangingChildDocuments;
 
   /**
    * Storage for content inserted notification information.
    */
   class ContentInsertion
   {
   public:
-    ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer,
-                     nsIContent* aStartChildNode, nsIContent* aEndChildNode);
+    ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer);
     virtual ~ContentInsertion() { mDocument = nsnull; }
 
     NS_INLINE_DECL_REFCOUNTING(ContentInsertion)
     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
 
+    bool InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode);
     void Process();
 
   private:
     ContentInsertion();
     ContentInsertion(const ContentInsertion&);
     ContentInsertion& operator = (const ContentInsertion&);
 
     // The document used to process content insertion, matched to document of
--- a/accessible/src/base/nsAccTreeWalker.cpp
+++ b/accessible/src/base/nsAccTreeWalker.cpp
@@ -61,18 +61,18 @@ struct WalkState
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccTreeWalker
 ////////////////////////////////////////////////////////////////////////////////
 
 nsAccTreeWalker::
   nsAccTreeWalker(nsIWeakReference* aShell, nsIContent* aContent,
-                  PRBool aWalkAnonContent) :
-  mWeakShell(aShell), mState(nsnull)
+                  PRBool aWalkAnonContent, bool aWalkCache) :
+  mWeakShell(aShell), mState(nsnull), mWalkCache(aWalkCache)
 {
   NS_ASSERTION(aContent, "No node for the accessible tree walker!");
 
   if (aContent)
     mState = new WalkState(aContent);
 
   mChildFilter = aWalkAnonContent ? nsIContent::eAllChildren :
                                   nsIContent::eAllButXBL;
@@ -109,17 +109,18 @@ nsAccTreeWalker::NextChildInternal(bool 
   if (mState->childList)
     mState->childList->GetLength(&length);
 
   while (mState->childIdx < length) {
     nsIContent* childNode = mState->childList->GetNodeAt(mState->childIdx);
     mState->childIdx++;
 
     bool isSubtreeHidden = false;
-    nsAccessible* accessible =
+    nsAccessible* accessible = mWalkCache ?
+      GetAccService()->GetAccessibleInWeakShell(childNode, mWeakShell) :
       GetAccService()->GetOrCreateAccessible(childNode, presShell, mWeakShell,
                                              &isSubtreeHidden);
 
     if (accessible)
       return accessible;
 
     // Walk down into subtree to find accessibles.
     if (!isSubtreeHidden) {
--- a/accessible/src/base/nsAccTreeWalker.h
+++ b/accessible/src/base/nsAccTreeWalker.h
@@ -49,17 +49,17 @@ struct WalkState;
 
 /**
  * This class is used to walk the DOM tree to create accessible tree.
  */
 class nsAccTreeWalker
 {
 public:
   nsAccTreeWalker(nsIWeakReference *aShell, nsIContent *aNode, 
-                  PRBool aWalkAnonymousContent);
+                  PRBool aWalkAnonymousContent, bool aWalkCache = false);
   virtual ~nsAccTreeWalker();
 
   /**
    * Return the next child accessible.
    *
    * @note Returned accessible is bound to the document, if the accessible is
    *       rejected during tree creation then the caller should be unbind it
    *       from the document.
@@ -90,12 +90,13 @@ private:
 
   /**
    * Pop state from stack.
    */
   void PopState();
 
   nsCOMPtr<nsIWeakReference> mWeakShell;
   PRInt32 mChildFilter;
+  bool mWalkCache;
   WalkState* mState;
 };
 
 #endif 
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -469,45 +469,54 @@ nsAccessible::GetPreviousSibling(nsIAcce
 
   /* readonly attribute nsIAccessible firstChild; */
 NS_IMETHODIMP
 nsAccessible::GetFirstChild(nsIAccessible **aFirstChild) 
 {
   NS_ENSURE_ARG_POINTER(aFirstChild);
   *aFirstChild = nsnull;
 
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   PRInt32 childCount = GetChildCount();
   NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE);
 
   if (childCount > 0)
     NS_ADDREF(*aFirstChild = GetChildAt(0));
 
   return NS_OK;
 }
 
   /* readonly attribute nsIAccessible lastChild; */
 NS_IMETHODIMP
 nsAccessible::GetLastChild(nsIAccessible **aLastChild)
 {
   NS_ENSURE_ARG_POINTER(aLastChild);
   *aLastChild = nsnull;
 
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   PRInt32 childCount = GetChildCount();
   NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE);
 
   NS_IF_ADDREF(*aLastChild = GetChildAt(childCount - 1));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetChildAt(PRInt32 aChildIndex, nsIAccessible **aChild)
 {
   NS_ENSURE_ARG_POINTER(aChild);
   *aChild = nsnull;
 
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   PRInt32 childCount = GetChildCount();
   NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE);
 
   // If child index is negative, then return last child.
   // XXX: do we really need this?
   if (aChildIndex < 0)
     aChildIndex = childCount - 1;
 
@@ -521,16 +530,19 @@ nsAccessible::GetChildAt(PRInt32 aChildI
 
 // readonly attribute nsIArray children;
 NS_IMETHODIMP
 nsAccessible::GetChildren(nsIArray **aOutChildren)
 {
   NS_ENSURE_ARG_POINTER(aOutChildren);
   *aOutChildren = nsnull;
 
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   PRInt32 childCount = GetChildCount();
   NS_ENSURE_TRUE(childCount != -1, NS_ERROR_FAILURE);
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> children =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -550,16 +562,19 @@ nsAccessible::GetAllowsAnonChildAccessib
 }
 
 /* readonly attribute long childCount; */
 NS_IMETHODIMP
 nsAccessible::GetChildCount(PRInt32 *aChildCount) 
 {
   NS_ENSURE_ARG_POINTER(aChildCount);
 
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   *aChildCount = GetChildCount();
   return *aChildCount != -1 ? NS_OK : NS_ERROR_FAILURE;  
 }
 
 /* readonly attribute long indexInParent; */
 NS_IMETHODIMP
 nsAccessible::GetIndexInParent(PRInt32 *aIndexInParent)
 {
@@ -2807,88 +2822,75 @@ nsAccessible::RemoveChild(nsAccessible* 
   mEmbeddedObjCollector = nsnull;
 
   return PR_TRUE;
 }
 
 nsAccessible*
 nsAccessible::GetChildAt(PRUint32 aIndex)
 {
-  if (EnsureChildren())
-    return nsnull;
-
   nsAccessible *child = mChildren.SafeElementAt(aIndex, nsnull);
   if (!child)
     return nsnull;
 
 #ifdef DEBUG
   nsAccessible* realParent = child->mParent;
   NS_ASSERTION(!realParent || realParent == this,
                "Two accessibles have the same first child accessible!");
 #endif
 
   return child;
 }
 
 PRInt32
 nsAccessible::GetChildCount()
 {
-  return EnsureChildren() ? -1 : mChildren.Length();
+  return mChildren.Length();
 }
 
 PRInt32
 nsAccessible::GetIndexOf(nsAccessible* aChild)
 {
-  return EnsureChildren() || (aChild->mParent != this) ?
-    -1 : aChild->GetIndexInParent();
+  return (aChild->mParent != this) ? -1 : aChild->GetIndexInParent();
 }
 
 PRInt32
 nsAccessible::GetIndexInParent() const
 {
   return mIndexInParent;
 }
 
 PRInt32
 nsAccessible::GetEmbeddedChildCount()
 {
-  if (EnsureChildren())
-    return -1;
-
   if (IsChildrenFlag(eMixedChildren)) {
     if (!mEmbeddedObjCollector)
       mEmbeddedObjCollector = new EmbeddedObjCollector(this);
     return mEmbeddedObjCollector ? mEmbeddedObjCollector->Count() : -1;
   }
 
   return GetChildCount();
 }
 
 nsAccessible*
 nsAccessible::GetEmbeddedChildAt(PRUint32 aIndex)
 {
-  if (EnsureChildren())
-    return nsnull;
-
   if (IsChildrenFlag(eMixedChildren)) {
     if (!mEmbeddedObjCollector)
       mEmbeddedObjCollector = new EmbeddedObjCollector(this);
     return mEmbeddedObjCollector ?
       mEmbeddedObjCollector->GetAccessibleAt(aIndex) : nsnull;
   }
 
   return GetChildAt(aIndex);
 }
 
 PRInt32
 nsAccessible::GetIndexOfEmbeddedChild(nsAccessible* aChild)
 {
-  if (EnsureChildren())
-    return -1;
-
   if (IsChildrenFlag(eMixedChildren)) {
     if (!mEmbeddedObjCollector)
       mEmbeddedObjCollector = new EmbeddedObjCollector(this);
     return mEmbeddedObjCollector ?
       mEmbeddedObjCollector->GetIndexAt(aChild) : -1;
   }
 
   return GetIndexOf(aChild);
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -1422,36 +1422,36 @@ void
 nsDocAccessible::ContentRemoved(nsIContent* aContainerNode,
                                 nsIContent* aChildNode)
 {
   // Update the whole tree of this document accessible when the container is
   // null (document element is removed).
   nsAccessible* container = aContainerNode ?
     GetAccessibleOrContainer(aContainerNode) : this;
 
-  UpdateTree(container, aChildNode, PR_FALSE);
+  UpdateTree(container, aChildNode, false);
 }
 
 void
 nsDocAccessible::RecreateAccessible(nsIContent* aContent)
 {
   // XXX: we shouldn't recreate whole accessible subtree, instead we should
   // subclass hide and show events to handle them separately and implement their
   // coalescence with normal hide and show events. Note, in this case they
   // should be coalesced with normal show/hide events.
 
   // Check if the node is in DOM still.
   nsIContent* parentContent = aContent->GetParent();
   if (parentContent && parentContent->IsInDoc()) {
     nsAccessible* container = GetAccessibleOrContainer(parentContent);
 
     // Remove and reinsert.
-    UpdateTree(container, aContent, PR_FALSE);
+    UpdateTree(container, aContent, false);
     container->UpdateChildren();
-    UpdateTree(container, aContent, PR_TRUE);
+    UpdateTree(container, aContent, true);
   }
 }
 
 void
 nsDocAccessible::NotifyOfCachingStart(nsAccessible* aAccessible)
 {
   if (!mCacheRoot)
     mCacheRoot = aAccessible;
@@ -1463,25 +1463,30 @@ nsDocAccessible::NotifyOfCachingEnd(nsAc
   if (mCacheRoot == aAccessible && !mIsPostCacheProcessing) {
     // Allow invalidation list insertions while container children are recached.
     mIsPostCacheProcessing = PR_TRUE;
 
     // Invalidate children of container accessible for each element in
     // invalidation list.
     for (PRUint32 idx = 0; idx < mInvalidationList.Length(); idx++) {
       nsIContent* content = mInvalidationList[idx];
-      if (!HasAccessible(content)) {
-        // Make sure we keep children updated. While we're inside of caching
-        // loop then we must exist it with cached children.
+      nsAccessible* accessible = GetAccessible(content);
+      if (!accessible) {
         nsAccessible* container = GetContainerAccessible(content);
         NS_ASSERTION(container,
                      "Got a referenced element that is not in document!");
-        if (container)
+        if (container) {
           container->UpdateChildren();
+          accessible = GetAccessible(content);
+        }
       }
+
+      // Make sure the subtree is created.
+      if (accessible)
+        CacheChildrenInSubtree(accessible);
     }
     mInvalidationList.Clear();
 
     mCacheRoot = nsnull;
     mIsPostCacheProcessing = PR_FALSE;
   }
 }
 
@@ -1792,26 +1797,38 @@ nsDocAccessible::ProcessContentInserted(
   // double processing, however generated events are coalesced and we don't
   // harm an AT.
   // Theoretically the element might be not in tree at all at this point what
   // means there's no container.
   for (PRUint32 idx = 0; idx < aInsertedContent->Length(); idx++) {
     nsAccessible* directContainer =
       GetContainerAccessible(aInsertedContent->ElementAt(idx));
     if (directContainer)
-      UpdateTree(directContainer, aInsertedContent->ElementAt(idx), PR_TRUE);
+      UpdateTree(directContainer, aInsertedContent->ElementAt(idx), true);
   }
 }
 
 void
 nsDocAccessible::UpdateTree(nsAccessible* aContainer, nsIContent* aChildNode,
-                            PRBool aIsInsert)
+                            bool aIsInsert)
 {
-  PRUint32 updateFlags =
-    UpdateTreeInternal(aChildNode, aChildNode->GetNextSibling(), aIsInsert);
+  PRUint32 updateFlags = eNoAccessible;
+
+  // If child node is not accessible then look for its accessible children.
+  nsAccessible* child = GetAccessible(aChildNode);
+  if (child) {
+    updateFlags |= UpdateTreeInternal(child, aIsInsert);
+
+  } else {
+    nsAccTreeWalker walker(mWeakShell, aChildNode,
+                           aContainer->GetAllowsAnonChildAccessibles(), true);
+
+    while ((child = walker.NextChild()))
+      updateFlags |= UpdateTreeInternal(child, aIsInsert);
+  }
 
   // Content insertion/removal is not cause of accessible tree change.
   if (updateFlags == eNoAccessible)
     return;
 
   // Check to see if change occurred inside an alert, and fire an EVENT_ALERT
   // if it did.
   if (aIsInsert && !(updateFlags & eAlertAccessible)) {
@@ -1844,107 +1861,87 @@ nsDocAccessible::UpdateTree(nsAccessible
   nsRefPtr<AccEvent> reorderEvent =
     new AccEvent(nsIAccessibleEvent::EVENT_REORDER, aContainer->GetNode(),
                  eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
   if (reorderEvent)
     FireDelayedAccessibleEvent(reorderEvent);
 }
 
 PRUint32
-nsDocAccessible::UpdateTreeInternal(nsIContent* aStartNode,
-                                    nsIContent* aEndNode,
-                                    PRBool aIsInsert)
+nsDocAccessible::UpdateTreeInternal(nsAccessible* aChild, bool aIsInsert)
 {
-  PRUint32 updateFlags = eNoAccessible;
-  for (nsIContent* node = aStartNode; node != aEndNode;
-       node = node->GetNextSibling()) {
+  PRUint32 updateFlags = eAccessible;
+
+  nsINode* node = aChild->GetNode();
+  if (aIsInsert) {
+    // Create accessible tree for shown accessible.
+    CacheChildrenInSubtree(aChild);
+
+  } else {
+    // Fire menupopup end event before hide event if a menu goes away.
+
+    // XXX: We don't look into children of hidden subtree to find hiding
+    // menupopup (as we did prior bug 570275) because we don't do that when
+    // menu is showing (and that's impossible until bug 606924 is fixed).
+    // Nevertheless we should do this at least because layout coalesces
+    // the changes before our processing and we may miss some menupopup
+    // events. Now we just want to be consistent in content insertion/removal
+    // handling.
+    if (aChild->ARIARole() == nsIAccessibleRole::ROLE_MENUPOPUP) {
+      nsRefPtr<AccEvent> event =
+        new AccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, aChild);
 
-    // Tree update triggers for content insertion even if no content was
-    // inserted actually, check if the given content has a frame to discard
-    // this case early.
-    if (aIsInsert && !node->GetPrimaryFrame())
-      continue;
+      if (event)
+        FireDelayedAccessibleEvent(event);
+    }
+  }
+
+  // Fire show/hide event.
+  nsRefPtr<AccEvent> event;
+  if (aIsInsert)
+    event = new AccShowEvent(aChild, node);
+  else
+    event = new AccHideEvent(aChild, node);
 
-    nsAccessible* accessible = GetAccessible(node);
+  if (event)
+    FireDelayedAccessibleEvent(event);
 
-    if (!accessible) {
-      updateFlags |= UpdateTreeInternal(node->GetFirstChild(), nsnull,
-                                        aIsInsert);
-      continue;
+  if (aIsInsert) {
+    PRUint32 ariaRole = aChild->ARIARole();
+    if (ariaRole == nsIAccessibleRole::ROLE_MENUPOPUP) {
+      // Fire EVENT_MENUPOPUP_START if ARIA menu appears.
+      FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
+                                 node, AccEvent::eRemoveDupes);
+
+    } else if (ariaRole == nsIAccessibleRole::ROLE_ALERT) {
+      // Fire EVENT_ALERT if ARIA alert appears.
+      updateFlags = eAlertAccessible;
+      FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, node,
+                                 AccEvent::eRemoveDupes);
     }
 
-    updateFlags |= eAccessible;
-
-    if (aIsInsert) {
-      // Create accessible tree for shown accessible.
-      CacheChildrenInSubtree(accessible);
-
-    } else {
-      // Fire menupopup end event before hide event if a menu goes away.
-
-      // XXX: We don't look into children of hidden subtree to find hiding
-      // menupopup (as we did prior bug 570275) because we don't do that when
-      // menu is showing (and that's impossible until bug 606924 is fixed).
-      // Nevertheless we should do this at least because layout coalesces
-      // the changes before our processing and we may miss some menupopup
-      // events. Now we just want to be consistent in content insertion/removal
-      // handling.
-      if (accessible->ARIARole() == nsIAccessibleRole::ROLE_MENUPOPUP) {
-        nsRefPtr<AccEvent> event =
-          new AccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, accessible);
-
-        if (event)
-          FireDelayedAccessibleEvent(event);
-      }
+    // If focused node has been shown then it means its frame was recreated
+    // while it's focused. Fire focus event on new focused accessible. If
+    // the queue contains focus event for this node then it's suppressed by
+    // this one.
+    if (node == gLastFocusedNode) {
+      FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
+                                 node, AccEvent::eCoalesceFromSameDocument);
     }
-
-    // Fire show/hide event.
-    nsRefPtr<AccEvent> event;
-    if (aIsInsert)
-      event = new AccShowEvent(accessible, node);
-    else
-      event = new AccHideEvent(accessible, node);
-
-    if (event)
-      FireDelayedAccessibleEvent(event);
+  } else {
+    // Update the tree for content removal.
+    // The accessible parent may differ from container accessible if
+    // the parent doesn't have own DOM node like list accessible for HTML
+    // selects.
+    nsAccessible* parent = aChild->GetParent();
+    NS_ASSERTION(parent, "No accessible parent?!");
+    if (parent)
+      parent->RemoveChild(aChild);
 
-    if (aIsInsert) {
-      PRUint32 ariaRole = accessible->ARIARole();
-      if (ariaRole == nsIAccessibleRole::ROLE_MENUPOPUP) {
-        // Fire EVENT_MENUPOPUP_START if ARIA menu appears.
-        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
-                                   node, AccEvent::eRemoveDupes);
-
-      } else if (ariaRole == nsIAccessibleRole::ROLE_ALERT) {
-        // Fire EVENT_ALERT if ARIA alert appears.
-        updateFlags = eAlertAccessible;
-        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, node,
-                                   AccEvent::eRemoveDupes);
-      }
-
-      // If focused node has been shown then it means its frame was recreated
-      // while it's focused. Fire focus event on new focused accessible. If
-      // the queue contains focus event for this node then it's suppressed by
-      // this one.
-      if (node == gLastFocusedNode) {
-        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
-                                   node, AccEvent::eCoalesceFromSameDocument);
-      }
-    } else {
-      // Update the tree for content removal.
-      // The accessible parent may differ from container accessible if
-      // the parent doesn't have own DOM node like list accessible for HTML
-      // selects.
-      nsAccessible* parent = accessible->GetParent();
-      NS_ASSERTION(parent, "No accessible parent?!");
-      if (parent)
-        parent->RemoveChild(accessible);
-
-      UncacheChildrenInSubtree(accessible);
-    }
+    UncacheChildrenInSubtree(aChild);
   }
 
   return updateFlags;
 }
 
 void
 nsDocAccessible::CacheChildrenInSubtree(nsAccessible* aRoot)
 {
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -438,31 +438,29 @@ protected:
    */
   void ProcessContentInserted(nsAccessible* aContainer,
                               const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent);
 
   /**
    * Update the accessible tree for content insertion or removal.
    */
   void UpdateTree(nsAccessible* aContainer, nsIContent* aChildNode,
-                  PRBool aIsInsert);
+                  bool aIsInsert);
 
   /**
    * Helper for UpdateTree() method. Go down to DOM subtree and updates
    * accessible tree. Return one of these flags.
    */
   enum EUpdateTreeFlags {
     eNoAccessible = 0,
     eAccessible = 1,
     eAlertAccessible = 2
   };
 
-  PRUint32 UpdateTreeInternal(nsIContent* aStartNode,
-                              nsIContent* aEndNode,
-                              PRBool aIsInsert);
+  PRUint32 UpdateTreeInternal(nsAccessible* aChild, bool aIsInsert);
 
   /**
    * Create accessible tree.
    */
   void CacheChildrenInSubtree(nsAccessible* aRoot);
 
   /**
    * Remove accessibles in subtree from node to accessible map.
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -2207,17 +2207,16 @@ nsHyperTextAccessible::GetChildOffset(PR
       mOffsets.RemoveElementsAt(aChildIndex, count);
 
     return mOffsets[aChildIndex - 1];
   }
 
   PRUint32 lastOffset = mOffsets.IsEmpty() ?
     0 : mOffsets[mOffsets.Length() - 1];
 
-  EnsureChildren();
   while (mOffsets.Length() < aChildIndex) {
     nsAccessible* child = mChildren[mOffsets.Length()];
     lastOffset += nsAccUtils::TextLength(child);
     mOffsets.AppendElement(lastOffset);
   }
 
   return mOffsets[aChildIndex - 1];
 }
--- a/accessible/tests/mochitest/events/Makefile.in
+++ b/accessible/tests/mochitest/events/Makefile.in
@@ -64,16 +64,17 @@ include $(topsrcdir)/config/rules.mk
 		test_dragndrop.html \
 		test_flush.html \
 		test_focus.html \
 		test_focus.xul \
 		test_focus_name.html \
 		test_focusdoc.html \
 		test_menu.xul \
 		test_mutation.html \
+		test_mutation.xhtml \
 		test_scroll.xul \
 		test_selection.html \
 		test_statechange.html \
 		test_text_alg.html \
 		test_text.html \
 		test_textattrchange.html \
 		test_tree.xul \
 		test_valuechange.html \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_mutation.xhtml
@@ -0,0 +1,99 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+  <title>Accessible mutation events testing</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <bindings xmlns="http://www.mozilla.org/xbl" >
+    <binding id="button">
+      <content>
+        <button xmlns="http://www.w3.org/1999/xhtml">a button</button>
+      </content>
+    </binding>
+  </bindings>
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+
+    /**
+     * Insert a not accessible bound element containing an accessible element
+     * in anonymous content.
+     */
+    function insertBinding(aContainerID)
+    {
+      this.containerNode = getNode(aContainerID);
+
+      function getButtonFromBinding(aNode)
+      {
+        try { return document.getAnonymousNodes(aNode.firstChild)[0]; }
+        catch (e) { return null; }
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, getButtonFromBinding, this.containerNode),
+        new invokerChecker(EVENT_REORDER, this.containerNode)
+      ];
+
+      this.invoke = function insertBinding_invoke()
+      {
+        var span = document.createElement("span");
+        span.setAttribute("style", "-moz-binding:url(#button)");
+        this.containerNode.appendChild(span);
+      }
+
+      this.getID = function insertBinding_getID()
+      {
+        return "insert button binding";
+      }
+    }
+
+    /**
+     * Do tests.
+     */
+    var gQueue = null;
+    //gA11yEventDumpID = "eventdump"; // debug stuff
+    //gA11yEventDumpToConsole = true;
+
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new insertBinding("testContainer"));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=646369"
+     title="UpdateTree should rely on accessible tree walker rather than DOM tree traversal">
+    Mozilla Bug 646369</a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+  <div id="eventdump"></div>
+
+  <div id="testContainer"></div>
+</body>
+</html>
--- a/browser/base/content/aboutDialog.css
+++ b/browser/base/content/aboutDialog.css
@@ -1,14 +1,14 @@
 #aboutDialog {
   padding-top: 0;
   -moz-padding-end: 0;
   padding-bottom: 10px;
   -moz-padding-start: 0;
-  width: 600px;
+  width: 620px;
 }
 
 #clientBox {
   background-color: #F7F7F7;
   color: #222222;
 }
 
 #leftBox {
@@ -53,20 +53,16 @@
 }
 
 .text-blurb {
   margin-bottom: 10px;
   -moz-margin-start: 0;
   -moz-padding-start: 0;
 }
 
-#updateBox {
-  margin-bottom: 10px;
-}
-
 #updateButton,
 #updateDeck > hbox > label {
   -moz-margin-start: 0;
   -moz-padding-start: 0;
 }
 
 #updateDeck > hbox > label:not([class="text-link"]) {
   color: #909090;
@@ -94,8 +90,41 @@
 }
 
 #trademark {
   font-size: xx-small;
   text-align: center;
   color: #999999;
   margin-top: 10px;
 }
+
+#currentChannel {
+  margin: 0;
+  padding: 0;
+  font-weight: bold;
+}
+
+#channelSelector {
+  margin-top: 10px;
+}
+
+#channelMenulist {
+  margin: 0;
+}
+
+.channel-description {
+  margin: 10px 0;
+  text-align: center;
+}
+
+#detailsBox,
+#channelSelector,
+.channel-description {
+  -moz-transition: opacity 250ms;
+}
+
+#contentDeck:not([selectedIndex="0"]) > #detailsBox,
+#contentDeck:not([selectedIndex="1"]) > #channelSelector,
+#channelDescriptionDeck:not([selectedIndex="0"]) > #releaseDescription,
+#channelDescriptionDeck:not([selectedIndex="1"]) > #betaDescription,
+#channelDescriptionDeck:not([selectedIndex="2"]) > #auroraDescription {
+  opacity: 0;
+}
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -83,16 +83,18 @@ function init(aEvent)
     document.getElementById("extra-trademark").hidden = true;
   }
 #endif
 
 #ifdef MOZ_UPDATER
   gAppUpdater = new appUpdater();
 #endif
 
+  gChannelSelector.init();
+
 #ifdef XP_MACOSX
   // it may not be sized at this point, and we need its width to calculate its position
   window.sizeToContent();
   window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5);
 #endif
 }
 
 #ifdef MOZ_UPDATER
@@ -567,8 +569,73 @@ appUpdater.prototype =
     if (!aIID.equals(Components.interfaces.nsIProgressEventSink) &&
         !aIID.equals(Components.interfaces.nsIRequestObserver) &&
         !aIID.equals(Components.interfaces.nsISupports))
       throw Components.results.NS_ERROR_NO_INTERFACE;
     return this;
   }
 };
 #endif
+
+var gChannelSelector = {
+  validChannels: { release: 1, beta: 1, aurora: 1 },
+  
+  init: function() {
+    try {
+      this.channelValue = Services.prefs.getCharPref("app.update.desiredChannel");
+    } catch (e) {
+      let defaults = Services.prefs.getDefaultBranch("");
+      this.channelValue = defaults.getCharPref("app.update.channel");
+    }
+
+    // Only show channel selector UI on valid update channels.
+    if (this.channelValue in this.validChannels) {
+      document.getElementById("currentChannelText").hidden = false;
+      this.setChannelLabel(this.channelValue);
+      this.setChannelMenuitem(this.channelValue);
+    }
+  },
+
+  selectChannel: function(aSelectedItem) {
+    document.getElementById("channelDescriptionDeck").selectedPanel =
+      document.getElementById(aSelectedItem.value + "Description");
+  },
+
+  cancel: function() {
+    this.setChannelMenuitem(this.channelValue);
+    this.hide();
+  },
+
+  apply: function() {
+    this.channelValue = document.getElementById("channelMenulist").selectedItem.value;
+    this.setChannelLabel(this.channelValue);
+
+    // Change app update channel.
+    Services.prefs.setCharPref("app.update.desiredChannel", this.channelValue);
+
+    // App updater will look at app.update.desiredChannel for new channel value
+    // and will clear it when the update is complete.
+    gAppUpdater.isChecking = true;
+    gAppUpdater.checker.checkForUpdates(gAppUpdater.updateCheckListener, true);
+
+    this.hide();
+  },
+
+  show: function() {
+    document.getElementById("contentDeck").selectedPanel =
+      document.getElementById("channelSelector");
+  },
+
+  hide: function() {
+    document.getElementById("contentDeck").selectedPanel =
+      document.getElementById("detailsBox");  
+  },
+
+  setChannelLabel: function(aValue) {
+    let channelLabel = document.getElementById("currentChannel");
+    channelLabel.value = document.getElementById(aValue + "Menuitem").label;
+  },
+
+  setChannelMenuitem: function(aValue) {
+    document.getElementById("channelMenulist").selectedItem =
+      document.getElementById(aValue + "Menuitem");
+  }
+}
--- a/browser/base/content/aboutDialog.xul
+++ b/browser/base/content/aboutDialog.xul
@@ -72,54 +72,91 @@
 
   <vbox>
     <hbox id="clientBox">
       <vbox id="leftBox" flex="1"/>
       <vbox id="rightBox" flex="1">
 #expand <label id="version" value="__MOZ_APP_VERSION__"/>
         <label id="distribution" class="text-blurb"/>
         <label id="distributionId" class="text-blurb"/>
-        <vbox id="updateBox">
+
+        <!-- Make sure the selectedIndex attribute is always set so that the CSS
+             selectors for transitions work -->        
+        <deck id="contentDeck" selectedIndex="0">
+          <vbox id="detailsBox">
+            <vbox id="updateBox">
 #ifdef MOZ_UPDATER
-          <deck id="updateDeck" orient="vertical">
-            <hbox id="updateButtonBox" align="center">
-              <button id="updateButton" align="start"
-                      oncommand="gAppUpdater.buttonOnCommand();"/>
-              <spacer flex="1"/>
-            </hbox>
-            <hbox id="checkingForUpdates" align="center">
-              <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
-            </hbox>
-            <hbox id="checkingAddonCompat" align="center">
-              <image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
-            </hbox>
-            <hbox id="downloading" align="center">
-              <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
+              <deck id="updateDeck" orient="vertical">
+                <hbox id="updateButtonBox" align="center">
+                  <button id="updateButton" align="start"
+                          oncommand="gAppUpdater.buttonOnCommand();"/>
+                  <spacer flex="1"/>
+                </hbox>
+                <hbox id="checkingForUpdates" align="center">
+                  <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
+                </hbox>
+                <hbox id="checkingAddonCompat" align="center">
+                  <image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
+                </hbox>
+                <hbox id="downloading" align="center">
+                  <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
+                </hbox>
+                <hbox id="downloadFailed" align="center">
+                  <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
+                </hbox>
+                <hbox id="adminDisabled" align="center">
+                  <label>&update.adminDisabled;</label>
+                </hbox>
+                <hbox id="noUpdatesFound" align="center">
+                  <label>&update.noUpdatesFound;</label>
+                </hbox>
+                <hbox id="manualUpdate" align="center">
+                  <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
+                </hbox>
+              </deck>
+#endif
+            </vbox>
+
+            <description class="text-blurb" id="currentChannelText" hidden="true">
+              &channel.description.start;<label id="currentChannel"/>&channel.description.end;<label id="channelChangeLink" class="text-link" onclick="gChannelSelector.show();">&channel.change;</label>
+            </description>
+            <description class="text-blurb">
+              &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
+            </description>
+            <description class="text-blurb">
+              &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
+            </description>
+          </vbox>
+
+          <vbox id="channelSelector">
+            <hbox pack="center" align="center">
+              <label>&channel.selector.start;</label>
+              <menulist id="channelMenulist" onselect="gChannelSelector.selectChannel(this.selectedItem);">
+                <menupopup>
+                  <menuitem id="releaseMenuitem" label="Release" value="release"/>
+                  <menuitem id="betaMenuitem" label="Beta" value="beta"/>
+                  <menuseparator/>
+                  <menuitem id="auroraMenuitem" label="Aurora" value="aurora"/>
+                </menupopup>
+              </menulist>
+              <label>&channel.selector.end;</label>
             </hbox>
-            <hbox id="downloadFailed" align="center">
-              <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
-            </hbox>
-            <hbox id="adminDisabled" align="center">
-              <label>&update.adminDisabled;</label>
-            </hbox>
-            <hbox id="noUpdatesFound" align="center">
-              <label>&update.noUpdatesFound;</label>
+
+            <deck id="channelDescriptionDeck" selectedIndex="0">
+              <description id="releaseDescription" class="channel-description">&channel.release.description;</description>
+              <description id="betaDescription" class="channel-description">&channel.beta.description;</description>
+              <description id="auroraDescription" class="channel-description">&channel.aurora.description;</description>
+            </deck>
+
+            <hbox id="channelSelectorButtons" pack="center">
+              <button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
+              <button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
             </hbox>
-            <hbox id="manualUpdate" align="center">
-              <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
-            </hbox>
-          </deck>
-#endif
-        </vbox>
-        <description class="text-blurb">
-          &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
-        </description>
-        <description class="text-blurb">
-          &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
-        </description>
+          </vbox>
+        </deck>
       </vbox>
     </hbox>
     <vbox id="bottomBox">
       <hbox pack="center">
         <label class="text-link bottom-link" href="about:license">&bottomLinks.license;</label>
         <label class="text-link bottom-link" href="about:rights">&bottomLinks.rights;</label>
         <label class="text-link bottom-link" href="http://www.mozilla.com/legal/privacy/">&bottomLinks.privacy;</label>
       </hbox>
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -315,18 +315,20 @@ let TabView = {
   afterUndoCloseTab: function () {
     if (this._window)
       this._window.UI.restoredClosedTab = false;
   },
 
   // ----------
   // On move to group pop showing.
   moveToGroupPopupShowing: function TabView_moveToGroupPopupShowing(event) {
-    // there are hidden tabs so initialize the iframe and update the context menu
-    if ((gBrowser.tabs.length - gBrowser.visibleTabs.length) > 0)
+    // Update the context menu only if Panorama was already initialized or if
+    // there are hidden tabs.
+    let numHiddenTabs = gBrowser.tabs.length - gBrowser.visibleTabs.length;
+    if (this._window || numHiddenTabs > 0)
       this.updateContextMenu(TabContextMenu.contextTab, event.target);
   },
 
   // ----------
   // Function: _addToolbarButton
   // Adds the TabView button to the TabsToolbar.
   _addToolbarButton: function TabView__addToolbarButton() {
     let buttonId = "tabview-button";
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -686,16 +686,17 @@ GroupItem.prototype = Utils.extend(new I
       }, {
         duration: 170,
         complete: function() {
           iQ(this).hide();
         }
       });
 
       this.droppable(false);
+      this.removeTrenches();
       this._createUndoButton();
     } else
       this.close();
     
     this._makeClosestTabActive();
   },
   
   // ----------
@@ -735,16 +736,17 @@ GroupItem.prototype = Utils.extend(new I
   _unhide: function GroupItem__unhide() {
     let self = this;
 
     this._cancelFadeAwayUndoButtonTimer();
     this.hidden = false;
     this.$undoContainer.remove();
     this.$undoContainer = null;
     this.droppable(true);
+    this.setTrenches(this.bounds);
 
     GroupItems.setActiveGroupItem(this);
     if (this._activeTab)
       UI.setActiveTab(this._activeTab);
 
     iQ(this.container).show().animate({
       "-moz-transform": "scale(1)",
       "opacity": 1
@@ -1232,18 +1234,18 @@ GroupItem.prototype = Utils.extend(new I
       return false;
 
     var bb = this.getContentBounds();
     var options = {
       return: 'widthAndColumns',
       count: count || this._children.length,
       hideTitle: false
     };
-    let arrObj = Items.arrange(null, bb, options);
- 
+    let arrObj = Items.arrange(this._children, bb, options);
+
     let shouldStack = arrObj.childWidth < TabItems.minTabWidth * 1.35;
     this._columns = shouldStack ? null : arrObj.columns;
 
     return shouldStack;
   },
 
   // ----------
   // Function: _freezeItemSize
--- a/browser/base/content/tabview/items.js
+++ b/browser/base/content/tabview/items.js
@@ -909,17 +909,16 @@ let Items = {
   //
   // Possible "options" properties:
   //   animate - whether to animate; default: true.
   //   z - the z index to set all the items; default: don't change z.
   //   return - if set to 'widthAndColumns', it'll return an object with the
   //     width of children and the columns.
   //   count - overrides the item count for layout purposes;
   //     default: the actual item count
-  //   padding - pixels between each item
   //   columns - (int) a preset number of columns to use
   //   dropPos - a <Point> which should have a one-tab space left open, used
   //             when a tab is dragged over.
   //
   // Returns:
   //   By default, an object with three properties: `rects`, the list of <Rect>s,
   //   `dropIndex`, the index which a dragged tab should have if dropped
   //   (null if no `dropPos` was specified), and the number of columns (`columns`).
--- a/browser/base/content/tabview/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -225,26 +225,16 @@ TabItem.prototype = Utils.extend(new Ite
   forceCanvasSize: function TabItem_forceCanvasSize(w, h) {
     this.canvasSizeForced = true;
     this.$canvas[0].width = w;
     this.$canvas[0].height = h;
     this.tabCanvas.paint();
   },
 
   // ----------
-  // Function: _getFontSizeFromWidth
-  // Private method that returns the fontsize to use given the tab's width
-  _getFontSizeFromWidth: function TabItem__getFontSizeFromWidth(width) {
-    let widthRange = new Range(0,TabItems.tabWidth);
-    let proportion = widthRange.proportion(width-TabItems.tabItemPadding.x, true);
-    // proportion is in [0,1]
-    return TabItems.fontSizeRange.scale(proportion);
-  },
-
-  // ----------
   // Function: unforceCanvasSize
   // Stops holding the thumbnail resolution; allows it to shift to the
   // size of thumbnail on screen. Note that this call does not nest, unlike
   // <TabItems.resumePainting>; if you call forceCanvasSize multiple
   // times, you just need a single unforce to clear them all.
   unforceCanvasSize: function TabItem_unforceCanvasSize() {
     this.canvasSizeForced = false;
   },
@@ -368,16 +358,29 @@ TabItem.prototype = Utils.extend(new Ite
           groupItem.add(self, {immediately: true});
 
           // if it matches the selected tab or no active tab and the browser
           // tab is hidden, the active group item would be set.
           if (self.tab == gBrowser.selectedTab ||
               (!GroupItems.getActiveGroupItem() && !self.tab.hidden))
             GroupItems.setActiveGroupItem(self.parent);
         }
+      } else {
+        // When duplicating a non-blank orphaned tab, create a group including both of them.
+        // This prevents overlaid tabs in Tab View (only one tab appears to be there).
+        // In addition, as only one active orphaned tab is shown when Tab View is hidden
+        // and there are two tabs shown after the duplication, it also prevents
+        // the inactive tab to suddenly disappear when toggling Tab View twice.
+        //
+        // Fixes:
+        //   Bug 645653 - Middle-click on reload button to duplicate orphan tabs does not create a group
+        //   Bug 643119 - Ctrl+Drag to duplicate does not work for orphaned tabs
+        //   ... (and any other way of duplicating a non-blank orphaned tab).
+        if (GroupItems.getActiveGroupItem() == null)
+          GroupItems.newTab(self, {immediately: true});
       }
     } else {
       // create tab by double click is handled in UI_init().
       if (!TabItems.creatingNewOrphanTab)
         GroupItems.newTab(self, {immediately: true});
     }
 
     self._reconnected = true;
@@ -435,26 +438,24 @@ TabItem.prototype = Utils.extend(new Ite
     if (rect.left != this.bounds.left || options.force)
       css.left = rect.left;
 
     if (rect.top != this.bounds.top || options.force)
       css.top = rect.top;
 
     if (rect.width != this.bounds.width || options.force) {
       css.width = rect.width - TabItems.tabItemPadding.x;
-      css.fontSize = this._getFontSizeFromWidth(rect.width);
+      css.fontSize = TabItems.getFontSizeFromWidth(rect.width);
       css.fontSize += 'px';
     }
 
     if (rect.height != this.bounds.height || options.force) {
+      css.height = rect.height - TabItems.tabItemPadding.y;
       if (!this.isStacked)
-          css.height = rect.height - TabItems.tabItemPadding.y -
-                       TabItems.fontSizeRange.max;
-      else
-        css.height = rect.height - TabItems.tabItemPadding.y;
+        css.height -= TabItems.fontSizeRange.max;
     }
 
     if (Utils.isEmptyObject(css))
       return;
 
     this.bounds.copy(rect);
 
     // If this is a brand new tab don't animate it in from
@@ -1275,67 +1276,69 @@ let TabItems = {
     var sane = true;
     if (!Utils.isRect(data.bounds)) {
       Utils.log('TabItems.storageSanity: bad bounds', data.bounds);
       sane = false;
     }
 
     return sane;
   },
-  
+
+  // ----------
+  // Function: getFontSizeFromWidth
+  // Private method that returns the fontsize to use given the tab's width
+  getFontSizeFromWidth: function TabItem_getFontSizeFromWidth(width) {
+    let widthRange = new Range(0, TabItems.tabWidth);
+    let proportion = widthRange.proportion(width - TabItems.tabItemPadding.x, true);
+    // proportion is in [0,1]
+    return TabItems.fontSizeRange.scale(proportion);
+  },
+
   // ----------
   // Function: _getWidthForHeight
   // Private method that returns the tabitem width given a height.
-  // Set options.hideTitle=true to measure without a title.
-  // Default is to measure with a title.
-  _getWidthForHeight: function TabItems__getWidthForHeight(height, options) {    
-    let titleSize = (options !== undefined && options.hideTitle === true) ? 
-      0 : TabItems.fontSizeRange.max;
-    return Math.max(0, Math.max(TabItems.minTabHeight, height - titleSize)) * 
-      TabItems.invTabAspect;
+  _getWidthForHeight: function TabItems__getWidthForHeight(height) {
+    return height * TabItems.invTabAspect;
   },
 
   // ----------
   // Function: _getHeightForWidth
   // Private method that returns the tabitem height given a width.
-  // Set options.hideTitle=false to measure without a title.
-  // Default is to measure with a title.
-  _getHeightForWidth: function TabItems__getHeightForWidth(width, options) {
-    let titleSize = (options !== undefined && options.hideTitle === true) ? 
-      0 : TabItems.fontSizeRange.max;
-    return Math.max(0, Math.max(TabItems.minTabWidth,width)) *
-      TabItems.tabAspect + titleSize;
+  _getHeightForWidth: function TabItems__getHeightForWidth(width) {
+    return width * TabItems.tabAspect;
   },
-  
+
   // ----------
   // Function: calcValidSize
   // Pass in a desired size, and receive a size based on proper title
   // size and aspect ratio.
   calcValidSize: function TabItems_calcValidSize(size, options) {
     Utils.assert(Utils.isPoint(size), 'input is a Point');
-    let retSize = new Point(0,0);
-    if (size.x==-1) {
-      retSize.x = this._getWidthForHeight(size.y, options);
-      retSize.y = size.y;
-    } else if (size.y==-1) {
-      retSize.x = size.x;
-      retSize.y = this._getHeightForWidth(size.x, options);
-    } else {
-      let fitHeight = this._getHeightForWidth(size.x, options);
-      let fitWidth = this._getWidthForHeight(size.y, options);
+
+    let width = Math.max(TabItems.minTabWidth, size.x);
+    let showTitle = !options || !options.hideTitle;
+    let titleSize = showTitle ? TabItems.fontSizeRange.max : 0;
+    let height = Math.max(TabItems.minTabHeight, size.y - titleSize);
+    let retSize = new Point(width, height);
 
-      // Go with the smallest final dimension.
-      if (fitWidth < size.x) {
-        retSize.x = fitWidth;
-        retSize.y = size.y;
-      } else {
-        retSize.x = size.x;
-        retSize.y = fitHeight;
-      }
+    if (size.x > -1)
+      retSize.y = this._getHeightForWidth(width);
+    if (size.y > -1)
+      retSize.x = this._getWidthForHeight(height);
+
+    if (size.x > -1 && size.y > -1) {
+      if (retSize.x < size.x)
+        retSize.y = this._getHeightForWidth(retSize.x);
+      else
+        retSize.x = this._getWidthForHeight(retSize.y);
     }
+
+    if (showTitle)
+      retSize.y += titleSize;
+
     return retSize;
   }
 };
 
 // ##########
 // Class: TabPriorityQueue
 // Container that returns tab items in a priority order
 // Current implementation assigns tab to either a high priority
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is sanitize dialog test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Drew Willcoxon <adw@mozilla.com> (Original Author)
  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
--- a/browser/base/content/test/browser_sanitizeDialog_treeView.js
+++ b/browser/base/content/test/browser_sanitizeDialog_treeView.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is sanitize dialog test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Drew Willcoxon <adw@mozilla.com> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -68,16 +68,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug595930.js \
                  browser_tabview_bug595943.js \
                  browser_tabview_bug595965.js \
                  browser_tabview_bug596781.js \
                  browser_tabview_bug597248.js \
                  browser_tabview_bug597360.js \
                  browser_tabview_bug597399.js \
                  browser_tabview_bug597980.js \
+                 browser_tabview_bug598375.js \
                  browser_tabview_bug598600.js \
                  browser_tabview_bug599626.js \
                  browser_tabview_bug600645.js \
                  browser_tabview_bug600812.js \
                  browser_tabview_bug602432.js \
                  browser_tabview_bug604098.js \
                  browser_tabview_bug604699.js \
                  browser_tabview_bug606657.js \
@@ -100,16 +101,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug623768.js \
                  browser_tabview_bug624265.js \
                  browser_tabview_bug624931.js \
                  browser_tabview_bug624727.js \
                  browser_tabview_bug624847.js \
                  browser_tabview_bug624953.js \
                  browser_tabview_bug625269.js \
                  browser_tabview_bug625424.js \
+                 browser_tabview_bug625666.js \
                  browser_tabview_bug626368.js \
                  browser_tabview_bug626525.js \
                  browser_tabview_bug626791.js \
                  browser_tabview_bug627288.js \
                  browser_tabview_bug627736.js \
                  browser_tabview_bug628165.js \
                  browser_tabview_bug628270.js \
                  browser_tabview_bug629189.js \
@@ -117,17 +119,20 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug630102.js \
                  browser_tabview_bug630157.js \
                  browser_tabview_bug631662.js \
                  browser_tabview_bug631752.js \
                  browser_tabview_bug633788.js \
                  browser_tabview_bug634077.js \
                  browser_tabview_bug634085.js \
                  browser_tabview_bug634158.js \
+                 browser_tabview_bug634672.js \
                  browser_tabview_bug635696.js \
+                 browser_tabview_bug641802.js \
+                 browser_tabview_bug645653.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_expander.js \
                  browser_tabview_firstrun_pref.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
                  browser_tabview_multiwindow_search.js \
                  browser_tabview_orphaned_tabs.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug598375.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function (win) {
+    registerCleanupFunction(function () win.close());
+
+    let cw = win.TabView.getContentWindow();
+    let groupItem = cw.GroupItems.groupItems[0];
+    groupItem.setBounds(new cw.Rect(cw.innerWidth - 200, 0, 200, 200));
+
+    whenTabViewIsHidden(finish, win);
+
+    let button = cw.document.getElementById("exit-button");
+    EventUtils.synthesizeMouseAtCenter(button, {}, cw);
+  });
+}
--- a/browser/base/content/test/tabview/browser_tabview_bug610208.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug610208.js
@@ -120,28 +120,30 @@ function test() {
     groupItem.setUserSize();
 
     cleanUpTest('testResizeGroup', originalBounds, next);
   }
 
   // make sure we don't freeze item size when removing an item from a stack
   let testRemoveWhileStacked = function () {
     let oldBounds = groupItem.getBounds();
-    groupItem.setSize(150, 200, true);
+    groupItem.setSize(250, 250, true);
     groupItem.setUserSize();
 
     let originalBounds = groupItem.getChild(0).getBounds();
-    ok(!groupItem._isStacked, 'testRemoveWhileStacked: group is not stacked');
+    ok(!groupItem.isStacked(), 'testRemoveWhileStacked: group is not stacked');
 
-    // add a new tab to let the group stack
-    win.gBrowser.loadOneTab('about:blank', {inBackground: true});
-    ok(groupItem._isStacked, 'testRemoveWhileStacked: group is now stacked');
+    // add new tabs to let the group stack
+    while (!groupItem.isStacked())
+      win.gBrowser.loadOneTab('about:blank', {inBackground: true});
 
     afterAllTabsLoaded(function () {
       groupItem.getChild(0).close();
+      ok(!groupItem.isStacked(), 'testRemoveWhileStacked: group is not stacked');
+
       let bounds = groupItem.getChild(0).getBounds();
       ok(originalBounds.equals(bounds), 'testRemoveWhileStacked: tabs did not change their size');
 
       // reset group size
       groupItem.setBounds(oldBounds);
       groupItem.setUserSize();
 
       next();
@@ -151,34 +153,34 @@ function test() {
   // 1) make sure item size is frozen when removing an item in expanded mode
   // 2) make sure item size stays frozen while moving the mouse in the expanded
   // layer
   let testExpandedMode = function () {
     let oldBounds = groupItem.getBounds();
     groupItem.setSize(100, 100, true);
     groupItem.setUserSize();
 
-    ok(groupItem._isStacked, 'testExpandedMode: group is stacked');
+    ok(groupItem.isStacked(), 'testExpandedMode: group is stacked');
 
     groupItem.addSubscriber(groupItem, 'expanded', function () {
       groupItem.removeSubscriber(groupItem, 'expanded');
       onExpanded();
     });
 
     groupItem.addSubscriber(groupItem, 'collapsed', function () {
       groupItem.removeSubscriber(groupItem, 'collapsed');
       onCollapsed();
     });
 
     let onExpanded = function () {
       let originalBounds = groupItem.getChild(0).getBounds();
       let tabItem = groupItem.getChild(1);
       let bounds = tabItem.getBounds();
 
-      for (let i=0; i<3; i++)
+      while (groupItem.getChildren().length > 2)
         groupItem.getChild(1).close();
 
       ok(originalBounds.equals(groupItem.getChild(0).getBounds()), 'testExpandedMode: tabs did not change their size');
 
       // move the mouse over the expanded layer
       let trayBounds = groupItem.expanded.bounds;
       let target = groupItem.expanded.$tray[0];
       EventUtils.synthesizeMouse(target, trayBounds.right - 5, trayBounds.bottom -5, {type: 'mousemove'}, cw);
--- a/browser/base/content/test/tabview/browser_tabview_bug618816.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug618816.js
@@ -1,47 +1,41 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let cw;
-
-  let createGroupItem = function () {
-    let bounds = new cw.Rect(20, 20, 400, 200);
-    let groupItem = new cw.GroupItem([], {bounds: bounds, immediately: true});
-
-    let groupItemId = groupItem.id;
-    registerCleanupFunction(function() {
-      let groupItem = cw.GroupItems.groupItem(groupItemId);
-      if (groupItem)
-        groupItem.close();
-    });
-
-    return groupItem;
-  }
+  let win;
 
   let testFocusTitle = function () {
     let title = 'title';
-    let groupItem = createGroupItem();
+    let groupItem = cw.GroupItems.groupItems[0];
     groupItem.setTitle(title);
 
     let target = groupItem.$titleShield[0];
     EventUtils.synthesizeMouseAtCenter(target, {}, cw);
 
     let input = groupItem.$title[0];
     is(input.selectionStart, 0, 'the whole text is selected');
     is(input.selectionEnd, title.length, 'the whole text is selected');
 
     EventUtils.synthesizeMouseAtCenter(input, {}, cw);
     is(input.selectionStart, title.length, 'caret is at the rightmost position and no text is selected');
     is(input.selectionEnd, title.length, 'caret is at the rightmost position and no text is selected');
 
-    groupItem.close();
-    hideTabView(finish);
+    win.close();
+    finish();
   }
 
   waitForExplicitFinish();
 
-  showTabView(function () {
-    cw = TabView.getContentWindow();
-    testFocusTitle();
+  newWindowWithTabView(function (tvwin) {
+    win = tvwin;
+
+    registerCleanupFunction(function () {
+      if (!win.closed)
+        win.close();
+    });
+
+    cw = win.TabView.getContentWindow();
+    SimpleTest.waitForFocus(testFocusTitle, cw);
   });
 }
--- a/browser/base/content/test/tabview/browser_tabview_bug624953.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug624953.js
@@ -1,39 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
 
-  let finishTest = function (groupItem) {
-    groupItem.addSubscriber(groupItem, 'groupHidden', function () {
-      groupItem.removeSubscriber(groupItem, 'groupHidden');
-      groupItem.closeHidden();
-      hideTabView(finish);
-    });
-
-    groupItem.closeAll();
-  }
-
   showTabView(function () {
     let cw = TabView.getContentWindow();
 
-    let bounds = new cw.Rect(20, 20, 150, 200);
-    let groupItem = new cw.GroupItem([], {bounds: bounds, immediately: true});
-    cw.GroupItems.setActiveGroupItem(groupItem);
-
-    for (let i=0; i<4; i++)
-      gBrowser.loadOneTab('about:blank', {inBackground: true});
-
-    ok(!groupItem._isStacked, 'groupItem is not stacked');
+    let groupItem = createGroupItemWithBlankTabs(window, 200, 240, 20, 4)
+    ok(!groupItem.isStacked(), 'groupItem is not stacked');
     cw.GroupItems.pauseArrange();
 
-    groupItem.setSize(150, 150);
+    groupItem.setSize(100, 100, true);
     groupItem.setUserSize();
-    ok(!groupItem._isStacked, 'groupItem is still not stacked');
+    ok(!groupItem.isStacked(), 'groupItem is still not stacked');
 
     cw.GroupItems.resumeArrange();
-    ok(groupItem._isStacked, 'groupItem is now stacked');
+    ok(groupItem.isStacked(), 'groupItem is now stacked');
 
-    finishTest(groupItem);
+    closeGroupItem(groupItem, finish);
   });
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug625666.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  let cw;
+
+  let getTabItemAspect = function (tabItem) {
+    let bounds = cw.iQ('.thumb', tabItem.container).bounds();
+    let padding = cw.TabItems.tabItemPadding;
+    return (bounds.height + padding.y) / (bounds.width + padding.x);
+  }
+
+  let getAspectRange = function () {
+    let aspect = cw.TabItems.tabAspect;
+    let variance = aspect / 100 * 1.5;
+    return new cw.Range(aspect - variance, aspect + variance);
+  }
+
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function (win) {
+    registerCleanupFunction(function () win.close());
+    cw = win.TabView.getContentWindow();
+
+    // prepare orphan tab
+    let tabItem = win.gBrowser.tabs[0]._tabViewTabItem;
+    tabItem.parent.remove(tabItem, {immediately: true});
+    tabItem.setBounds(new cw.Rect(20, 20, 200, 165), true);
+
+    let bounds = tabItem.getBounds();
+
+    // prepare group item
+    let box = new cw.Rect(20, 300, 400, 200);
+    let groupItem = new cw.GroupItem([], {bounds: box, immediately: true});
+
+    groupItem.setBounds(new cw.Rect(20, 100, 400, 200));
+    groupItem.pushAway(true);
+
+    let newBounds = tabItem.getBounds();
+    ok(newBounds.width < bounds.width, "The new width of item is smaller than the old one.");
+    ok(newBounds.height < bounds.height, "The new height of item is smaller than the old one.");
+
+    let aspectRange = getAspectRange();
+    let aspect = getTabItemAspect(tabItem);
+    ok(aspectRange.contains(aspect), "orphaned tabItem's aspect is correct");
+
+    finish();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug634672.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  let cw;
+  let win;
+
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function (tvwin) {
+    win = tvwin;
+    cw = win.TabView.getContentWindow();
+
+    registerCleanupFunction(function () {
+      if (win && !win.closed)
+        win.close();
+    });
+
+    // fill the group item with some tabs
+    for (let i = 0; i < 5; i++)
+      win.gBrowser.loadOneTab("about:blank");
+
+    let groupItem = cw.GroupItems.groupItems[0];
+    groupItem.setSize(400, 400, true);
+    let range = new cw.Range(1, 400);
+
+    // determine the groupItem's largest possible stacked size
+    while (range.extent > 1) {
+      let pivot = Math.floor(range.extent / 2);
+      groupItem.setSize(range.min + pivot, range.min + pivot, true);
+
+      if (groupItem.isStacked())
+        range.min += pivot;
+      else
+        range.max -= pivot;
+    }
+
+    // stack the group
+    groupItem.setSize(range.min, range.min, true);
+    ok(groupItem.isStacked(), "groupItem is stacked");
+
+    // one step back to un-stack the groupItem
+    groupItem.setSize(range.max, range.max, true);
+    ok(!groupItem.isStacked(), "groupItem is no longer stacked");
+
+    // check that close buttons are visible
+    let tabItem = groupItem.getChild(0);
+    isnot(tabItem.$close.css("display"), "none", "close button is visible");
+
+    finish();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug641802.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  let openMoveToGroupPopup = function () {
+    let tab = gBrowser.selectedTab;
+    document.popupNode = tab;
+    contextMenu.openPopup(tab, "end_after", 0, 0, true, false);
+    tvMenuPopup.openPopup(tvMenu, "end_after", 0, 0, true, false);
+  }
+
+  let hideMoveToGroupPopup = function () {
+    tvMenuPopup.hidePopup();
+    contextMenu.hidePopup();
+  }
+
+  let assertValidPrerequisites = function (visible) {
+    let cw = TabView.getContentWindow();
+    is(cw.GroupItems.groupItems.length, 1, "there is one groupItem");
+    is(gBrowser.tabs.length, 1, "there is one tab");
+    is(TabView.isVisible(), visible, "tabview is visible");
+  }
+
+  let tvMenu = document.getElementById("context_tabViewMenu");
+  let contextMenu = document.getElementById("tabContextMenu");
+  let tvMenuPopup = document.getElementById("context_tabViewMenuPopup");
+
+  waitForExplicitFinish();
+
+  registerCleanupFunction(function () {
+    hideMoveToGroupPopup();
+    hideTabView(function () {});
+
+    let groupItems = TabView.getContentWindow().GroupItems.groupItems;
+    if (groupItems.length > 1)
+      closeGroupItem(groupItems[0], function () {});
+  });
+
+  showTabView(function () {
+    assertValidPrerequisites(true);
+
+    hideTabView(function () {
+      let groupItem = createGroupItemWithBlankTabs(window, 200, 200, 10, 1);
+      groupItem.setTitle("group2");
+
+      gBrowser.selectedTab = gBrowser.tabs[0];
+
+      executeSoon(function () {
+        openMoveToGroupPopup();
+        is(tvMenuPopup.firstChild.getAttribute("label"), "group2", "menuItem is present");
+        hideMoveToGroupPopup();
+
+        closeGroupItem(groupItem, function () {
+          openMoveToGroupPopup();
+          is(tvMenuPopup.firstChild.tagName, "menuseparator", "menuItem is not present");
+          hideMoveToGroupPopup();
+
+          assertValidPrerequisites(false);
+          finish();
+        });
+      });
+    });
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug645653.js
@@ -0,0 +1,83 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* Orphans a non-blank tab, duplicates it and checks whether a new group is created with two tabs.
+ * The original one should be the first tab of the new group.
+ *
+ * This prevents overlaid tabs in Tab View (only one tab appears to be there).
+ * In addition, as only one active orphaned tab is shown when Tab View is hidden
+ * and there are two tabs shown after the duplication, it also prevents
+ * the inactive tab to suddenly disappear when toggling Tab View twice.
+ *
+ * Covers:
+ *   Bug 645653 - Middle-click on reload button to duplicate orphan tabs does not create a group
+ *   Bug 643119 - Ctrl+Drag to duplicate does not work for orphaned tabs
+ *   ... (and any other way of duplicating a non-blank orphaned tab).
+ *
+ * See tabitems.js::_reconnect() for the fix.
+ *
+ * Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
+ */
+
+function loadedAboutMozilla(tab) {
+  return tab.linkedBrowser.contentDocument.getElementById('moztext');
+}
+
+function test() {
+  waitForExplicitFinish();
+  showTabView(function() {
+    ok(TabView.isVisible(), "Tab View is visible");
+
+    let contentWindow = TabView.getContentWindow();
+    is(contentWindow.GroupItems.groupItems.length, 1, "There is one group item on startup.");
+
+    let originalGroupItem = contentWindow.GroupItems.groupItems[0];
+    is(originalGroupItem.getChildren().length, 1, "There is one tab item in that group.");
+
+    let originalTabItem = originalGroupItem.getChild(0);
+    ok(originalTabItem, "The tabitem has been found.");
+
+    // close the group => orphan the tab
+    originalGroupItem.close();
+    contentWindow.GroupItems.setActiveGroupItem(originalGroupItem);
+    is(contentWindow.GroupItems.groupItems.length, 0, "There are not any groups now.");
+
+    ok(TabView.isVisible(), "Tab View is still shown.");
+
+    hideTabView(function() {
+      ok(!TabView.isVisible(), "Tab View is not shown anymore.");
+
+      // load a non-blank page
+      loadURI('about:mozilla');
+
+      afterAllTabsLoaded(function() {
+        ok(loadedAboutMozilla(originalTabItem.tab), "The original tab loaded about:mozilla.");
+
+        // duplicate it
+        duplicateTabIn(originalTabItem.tab, "tabshift");
+
+        afterAllTabsLoaded(function() {
+          // check
+          is(gBrowser.selectedTab, originalTabItem.tab, "The selected tab is the original one.");
+          is(contentWindow.GroupItems.groupItems.length, 1, "There is one group item again.");
+          let groupItem = contentWindow.GroupItems.groupItems[0];
+          is(groupItem.getChildren().length, 2, "There are two tab items in that group.");
+          is(originalTabItem, groupItem.getChild(0), "The first tab item in the group is the original one.");
+          let otherTab = groupItem.getChild(1);
+          ok(loadedAboutMozilla(otherTab.tab), "The other tab loaded about:mozilla.");
+
+          // clean up
+          gBrowser.removeTab(otherTab.tab);
+          is(contentWindow.GroupItems.groupItems.length, 1, "There is one group item after closing the second tab.");
+          is(groupItem.getChildren().length, 1, "There is only one tab item after closing the second tab.");
+          is(originalTabItem, groupItem.getChild(0), "The first tab item in the group is still the original one.");
+          loadURI("about:blank");
+          afterAllTabsLoaded(function() {
+            finish();
+          });
+        });
+      });
+    });
+  });
+}
+
--- a/browser/base/content/test/tabview/browser_tabview_expander.js
+++ b/browser/base/content/test/tabview/browser_tabview_expander.js
@@ -12,17 +12,17 @@ function onTabViewWindowLoaded(win) {
 
   let contentWindow = win.document.getElementById("tab-view").contentWindow;
   let [originalTab] = win.gBrowser.visibleTabs;
   let currentGroup = contentWindow.GroupItems.getActiveGroupItem();
   
   // let's create a group small enough to get stacked
   let group = new contentWindow.GroupItem([], {
     immediately: true,
-    bounds: {left: 20, top: 300, width: 300, height: 300}
+    bounds: {left: 20, top: 300, width: 400, height: 400}
   });
 
   let expander = contentWindow.iQ(group.container).find(".stackExpander");
   ok("length" in expander && expander.length == 1, "The group has an expander.");
 
   // procreate!
   contentWindow.GroupItems.setActiveGroupItem(group);
   for (var i=0; i<7; i++) {
--- a/browser/base/content/test/tabview/head.js
+++ b/browser/base/content/test/tabview/head.js
@@ -101,17 +101,18 @@ function afterAllTabsLoaded(callback, wi
     this.removeEventListener("load", onLoad, true);
     stillToLoad--;
     if (!stillToLoad)
       callback();
   }
 
   for (let a = 0; a < win.gBrowser.tabs.length; a++) {
     let browser = win.gBrowser.tabs[a].linkedBrowser;
-    if (browser.contentDocument.readyState != "complete") {
+    if (browser.contentDocument.readyState != "complete" ||
+        browser.webProgress.isLoadingDocument) {
       stillToLoad++;
       browser.addEventListener("load", onLoad, true);
     }
   }
 
   if (!stillToLoad)
     callback();
 }
--- a/browser/components/places/tests/browser/Makefile.in
+++ b/browser/components/places/tests/browser/Makefile.in
@@ -8,17 +8,17 @@
 #
 # Software distributed under the License is distributed on an "AS IS" basis,
 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 # for the specific language governing rights and limitations under the
 # License.
 #
 # The Original Code is Places test code.
 #
-# The Initial Developer of the Original Code is Mozilla Corp.
+# The Initial Developer of the Original Code is the Mozilla Foundation.
 # Portions created by the Initial Developer are Copyright (C) 2008
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #  Dietrich Ayala <dietrich@mozilla.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either of the GNU General Public License Version 2 or later (the "GPL"),
--- a/browser/components/places/tests/browser/browser_0_library_left_pane_migration.js
+++ b/browser/components/places/tests/browser/browser_0_library_left_pane_migration.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Marco Bonardo <mak77@bonardo.net> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_423515.js
+++ b/browser/components/places/tests/browser/browser_423515.js
@@ -9,17 +9,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2008
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dietrich Ayala <dietrich@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_425884.js
+++ b/browser/components/places/tests/browser/browser_425884.js
@@ -9,17 +9,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2008
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dietrich Ayala <dietrich@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_457473_no_copy_guid.js
+++ b/browser/components/places/tests/browser/browser_457473_no_copy_guid.js
@@ -9,17 +9,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2008
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dietrich Ayala <dietrich@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_library_infoBox.js
+++ b/browser/components/places/tests/browser/browser_library_infoBox.js
@@ -8,17 +8,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Margaret Leibovic <mleibovic@mozilla.com> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_library_left_pane_commands.js
+++ b/browser/components/places/tests/browser/browser_library_left_pane_commands.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Marco Bonardo <mak77@bonardo.net> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_library_left_pane_fixnames.js
+++ b/browser/components/places/tests/browser/browser_library_left_pane_fixnames.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Marco Bonardo <mak77@bonardo.net> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_library_middleclick.js
+++ b/browser/components/places/tests/browser/browser_library_middleclick.js
@@ -9,17 +9,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Marco Bonardo <mak77@bonardo.net>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_library_open_leak.js
+++ b/browser/components/places/tests/browser/browser_library_open_leak.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Drew Willcoxon <adw@mozilla.com> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_library_panel_leak.js
+++ b/browser/components/places/tests/browser/browser_library_panel_leak.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Marco Bonardo <mak77@bonardo.net> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_library_search.js
+++ b/browser/components/places/tests/browser/browser_library_search.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Drew Willcoxon <adw@mozilla.com> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/browser/browser_sort_in_library.js
+++ b/browser/components/places/tests/browser/browser_sort_in_library.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Drew Willcoxon <adw@mozilla.com> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/chrome/Makefile.in
+++ b/browser/components/places/tests/chrome/Makefile.in
@@ -8,17 +8,17 @@
 #
 # Software distributed under the License is distributed on an "AS IS" basis,
 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 # for the specific language governing rights and limitations under the
 # License.
 #
 # The Original Code is Places test code.
 #
-# The Initial Developer of the Original Code is Mozilla Corp.
+# The Initial Developer of the Original Code is the Mozilla Foundation.
 # Portions created by the Initial Developer are Copyright (C) 2009
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #  Drew Willcoxon <adw@mozilla.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either of the GNU General Public License Version 2 or later (the "GPL"),
--- a/browser/components/places/tests/chrome/test_0_multiple_left_pane.xul
+++ b/browser/components/places/tests/chrome/test_0_multiple_left_pane.xul
@@ -10,17 +10,17 @@
    -
    - Software distributed under the License is distributed on an "AS IS" basis,
    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    - for the specific language governing rights and limitations under the
    - License.
    -
    - The Original Code is the Places test code.
    -
-   - The Initial Developer of the Original Code is Mozilla Corp.
+   - The Initial Developer of the Original Code is the Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2009
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Marco Bonardo <mak77@bonardo.net> (Original Author)
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/chrome/test_bug427633_no_newfolder_if_noip.xul
+++ b/browser/components/places/tests/chrome/test_bug427633_no_newfolder_if_noip.xul
@@ -10,17 +10,17 @@
    -
    - Software distributed under the License is distributed on an "AS IS" basis,
    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    - for the specific language governing rights and limitations under the
    - License.
    -
    - The Original Code is the Places test code.
    -
-   - The Initial Developer of the Original Code is Mozilla Corp.
+   - The Initial Developer of the Original Code is the Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2009
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Marco Bonardo <mak77@bonardo.net> (Original Author)
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/chrome/test_bug485100-change-case-loses-tag.xul
+++ b/browser/components/places/tests/chrome/test_bug485100-change-case-loses-tag.xul
@@ -10,17 +10,17 @@
    -
    - Software distributed under the License is distributed on an "AS IS" basis,
    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    - for the specific language governing rights and limitations under the
    - License.
    -
    - The Original Code is the Places test code.
    -
-   - The Initial Developer of the Original Code is Mozilla Corp.
+   - The Initial Developer of the Original Code is the Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2009
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Marco Bonardo <mak77@bonardo.net> (Original Author)
    -   Dietrich Ayala <dietrich@mozilla.com>
    -
    - Alternatively, the contents of this file may be used under the terms of
--- a/browser/components/places/tests/chrome/test_treeview_date.xul
+++ b/browser/components/places/tests/chrome/test_treeview_date.xul
@@ -10,17 +10,17 @@
    -
    - Software distributed under the License is distributed on an "AS IS" basis,
    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    - for the specific language governing rights and limitations under the
    - License.
    -
    - The Original Code is the Places test code.
    -
-   - The Initial Developer of the Original Code is Mozilla Corp.
+   - The Initial Developer of the Original Code is the Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2009
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Marco Bonardo <mak77@bonardo.net> (Original Author)
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/unit/test_384370.js
+++ b/browser/components/places/tests/unit/test_384370.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Bug 384370 code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2008
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dietrich Ayala <dietrich@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/unit/test_398914.js
+++ b/browser/components/places/tests/unit/test_398914.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is mozilla.com code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dietrich Ayala <dietrich@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/unit/test_421483.js
+++ b/browser/components/places/tests/unit/test_421483.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places Unit Test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2008
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Marco Bonardo <mak77@supereva.it>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js
+++ b/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Bug 457441 code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2008
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Marco Bonardo <mak77@bonardo.net> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/unit/test_bookmarksRestoreNotification.js
+++ b/browser/components/places/tests/unit/test_bookmarksRestoreNotification.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Places test code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Drew Willcoxon <adw@mozilla.com> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/places/tests/unit/test_bookmarks_html.js
+++ b/browser/components/places/tests/unit/test_bookmarks_html.js
@@ -10,17 +10,17 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is mozilla.com code.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dietrich Ayala <dietrich@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/components/preferences/tests/browser_privacypane_8.js
+++ b/browser/components/preferences/tests/browser_privacypane_8.js
@@ -8,17 +8,17 @@
  * 
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Privacy PrefPane Test.
  *
- * The Initial Developer of the Original Code is Mozilla Corp.
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Drew Willcoxon <adw@mozilla.com> (Original Author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
--- a/browser/locales/en-US/chrome/browser/aboutDialog.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutDialog.dtd
@@ -49,8 +49,32 @@
 
 <!-- LOCALIZATION NOTE (update.downloading.start,update.downloading.end): update.downloading.start and 
      update.downloading.end all go into one line, with the amount downloaded inserted in between. As this
      is all in one line, try to make the localized text short (see bug 596813 for screenshots). The — is
      the "em dash" (long dash).
      example: Downloading update — 111 KB of 13 MB -->
 <!ENTITY update.downloading.start   "Downloading update — ">
 <!ENTITY update.downloading.end     "">
+
+<!-- LOCALIZATION NOTE (channel.description.start,channel.description.end): channel.description.start and
+     channel.description.end create one sentence, with the current channel label inserted in between.
+     example: You are currently on the _Stable_ update channel. -->
+<!ENTITY channel.description.start  "You are currently on the ">
+<!ENTITY channel.description.end    " update channel. ">
+
+<!ENTITY channel.change             "Change">
+
+<!ENTITY channel.release.description       "Enjoy the tried and tested final release being used by hundreds of millions around the world. Stay in control of your online experience with super speed, easy customization and the latest Web technologies.">
+<!ENTITY channel.beta.description          "Experience cutting edge features with more stability. Provide feedback to help refine and polish what will be in the final release.">
+<!ENTITY channel.aurora.description        "Experience the newest innovations in an unstable environment that's not for the faint of heart. Provide feedback on features and performance to help determine what makes the final release.">
+
+<!-- LOCALIZATION NOTE (channel.selector.start,channel.selector.end): channel.selector.start and
+     channel.selector.end create one sentence, with a channel selection menulist instered in between.
+     This is all in one line, so try to make the localized text short.
+     example: Switch to the [Stable] update channel. -->
+<!ENTITY channel.selector.start          "Switch to the">
+<!ENTITY channel.selector.end            "update channel.">
+
+<!-- LOCALIZATION NOTE (channel.selector.applyButton): This button applies the user's choice to switch
+     to a new update channel and starts the application update process. -->
+<!ENTITY channel.selector.applyButton    "Apply and Update">
+<!ENTITY channel.selector.cancelButton   "Cancel">
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -71,18 +71,18 @@ enum nsLinkState {
   eLinkState_Unknown    = 0,
   eLinkState_Unvisited  = 1,
   eLinkState_Visited    = 2,
   eLinkState_NotLink    = 3
 };
 
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID       \
-{ 0x5788c9eb, 0x646a, 0x4285, \
-  { 0xa2, 0x8c, 0xde, 0x0d, 0x43, 0x6b, 0x47, 0x72 } }
+{ 0x32b94ba0, 0x1ebc, 0x4dfc, \
+ { 0xba, 0x8c, 0x5f, 0x24, 0x2b, 0xcb, 0xaf, 0xce } }
 
 /**
  * A node of content in a document's content model. This interface
  * is supported by all content objects.
  */
 class nsIContent : public nsINode {
 public:
 #ifdef MOZILLA_INTERNAL_API
@@ -795,17 +795,17 @@ public:
   virtual nsEventStates IntrinsicState() const;
 
   /**
    * Get the ID of this content node (the atom corresponding to the
    * value of the null-namespace attribute whose name is given by
    * GetIDAttributeName().  This may be null if there is no ID.
    */
   nsIAtom* GetID() const {
-    if (HasFlag(NODE_HAS_ID)) {
+    if (HasID()) {
       return DoGetID();
     }
     return nsnull;
   }
 
   /**
    * Get the class list of this content node (this corresponds to the
    * value of the null-namespace attribute whose name is given by
@@ -955,17 +955,17 @@ public:
   nsIContent* GetEditingHost();
 
   // Overloaded from nsINode
   virtual already_AddRefed<nsIURI> GetBaseURI() const;
 
 protected:
   /**
    * Hook for implementing GetID.  This is guaranteed to only be
-   * called if the NODE_HAS_ID flag is set.
+   * called if HasID() is true.
    */
   virtual nsIAtom* DoGetID() const = 0;
 
 private:
   /**
    * Hook for implementing GetClasses.  This is guaranteed to only be
    * called if the NODE_MAY_HAVE_CLASS flag is set.
    */
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -161,17 +161,17 @@ public:
       // mAllowDNSPrefetch starts true, so that we can always reliably && it
       // with various values that might disable it.  Since we never prefetch
       // unless we get a window, and in that case the docshell value will get
       // &&-ed in, this is safe.
       mAllowDNSPrefetch(PR_TRUE),
       mIsBeingUsedAsImage(PR_FALSE),
       mPartID(0)
   {
-    mParentPtrBits |= PARENT_BIT_INDOCUMENT;
+    SetInDocument();
   }
 #endif
   
   /**
    * Let the document know that we're starting to load data into it.
    * @param aCommand The parser command
    *                 XXXbz It's odd to have that here.
    * @param aChannel The channel the data will come from
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -73,122 +73,105 @@ class nsXPCClassInfo;
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 enum {
-  // This bit will be set if the node doesn't have nsSlots
-  NODE_DOESNT_HAVE_SLOTS =       0x00000001U,
-
   // This bit will be set if the node has a listener manager in the listener
   // manager hash
-  NODE_HAS_LISTENERMANAGER =     0x00000002U,
+  NODE_HAS_LISTENERMANAGER =     0x00000001U,
 
   // Whether this node has had any properties set on it
-  NODE_HAS_PROPERTIES =          0x00000004U,
+  NODE_HAS_PROPERTIES =          0x00000002U,
 
   // Whether this node is the root of an anonymous subtree.  Note that this
   // need not be a native anonymous subtree.  Any anonymous subtree, including
   // XBL-generated ones, will do.  This flag is set-once: once a node has it,
   // it must not be removed.
   // NOTE: Should only be used on nsIContent nodes
-  NODE_IS_ANONYMOUS =            0x00000008U,
+  NODE_IS_ANONYMOUS =            0x00000004U,
 
   // Whether the node has some ancestor, possibly itself, that is native
   // anonymous.  This includes ancestors crossing XBL scopes, in cases when an
   // XBL binding is attached to an element which has a native anonymous
   // ancestor.  This flag is set-once: once a node has it, it must not be
   // removed.
   // NOTE: Should only be used on nsIContent nodes
-  NODE_IS_IN_ANONYMOUS_SUBTREE = 0x00000010U,
+  NODE_IS_IN_ANONYMOUS_SUBTREE = 0x00000008U,
 
   // Whether this node is the root of a native anonymous (from the perspective
   // of its parent) subtree.  This flag is set-once: once a node has it, it
   // must not be removed.
   // NOTE: Should only be used on nsIContent nodes
-  NODE_IS_NATIVE_ANONYMOUS_ROOT = 0x00000020U,
+  NODE_IS_NATIVE_ANONYMOUS_ROOT = 0x00000010U,
 
   // Forces the XBL code to treat this node as if it were
   // in the document and therefore should get bindings attached.
-  NODE_FORCE_XBL_BINDINGS =      0x00000040U,
+  NODE_FORCE_XBL_BINDINGS =      0x00000020U,
 
   // Whether a binding manager may have a pointer to this
-  NODE_MAY_BE_IN_BINDING_MNGR =  0x00000080U,
-
-  NODE_IS_EDITABLE =             0x00000100U,
+  NODE_MAY_BE_IN_BINDING_MNGR =  0x00000040U,
 
-  // Set to true if the element has a non-empty id attribute. This can in rare
-  // cases lie for nsXMLElement, such as when the node has been moved between
-  // documents with different id mappings.
-  NODE_HAS_ID =                  0x00000200U,
+  NODE_IS_EDITABLE =             0x00000080U,
+
   // For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
   // node in fact has a class, but may be set even if it doesn't.
-  NODE_MAY_HAVE_CLASS =          0x00000400U,
-  NODE_MAY_HAVE_STYLE =          0x00000800U,
+  NODE_MAY_HAVE_CLASS =          0x00000100U,
 
-  NODE_IS_INSERTION_PARENT =     0x00001000U,
+  NODE_IS_INSERTION_PARENT =     0x00000200U,
 
   // Node has an :empty or :-moz-only-whitespace selector
-  NODE_HAS_EMPTY_SELECTOR =      0x00002000U,
+  NODE_HAS_EMPTY_SELECTOR =      0x00000400U,
 
   // A child of the node has a selector such that any insertion,
   // removal, or appending of children requires restyling the parent.
-  NODE_HAS_SLOW_SELECTOR =       0x00004000U,
+  NODE_HAS_SLOW_SELECTOR =       0x00000800U,
 
   // A child of the node has a :first-child, :-moz-first-node,
   // :only-child, :last-child or :-moz-last-node selector.
-  NODE_HAS_EDGE_CHILD_SELECTOR = 0x00008000U,
+  NODE_HAS_EDGE_CHILD_SELECTOR = 0x00001000U,
 
   // A child of the node has a selector such that any insertion or
   // removal of children requires restyling later siblings of that
   // element.  Additionally (in this manner it is stronger than
   // NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any
   // other content tree changes (e.g., the child changes to or from
   // matching :empty due to a grandchild insertion or removal), the
   // child's later siblings must also be restyled.
   NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
-                               = 0x00010000U,
+                               = 0x00002000U,
 
   NODE_ALL_SELECTOR_FLAGS =      NODE_HAS_EMPTY_SELECTOR |
                                  NODE_HAS_SLOW_SELECTOR |
                                  NODE_HAS_EDGE_CHILD_SELECTOR |
                                  NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS,
 
-  NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR
-                               = 0x00020000U,
-
   NODE_ATTACH_BINDING_ON_POSTCREATE
-                               = 0x00040000U,
+                               = 0x00004000U,
 
   // This node needs to go through frame construction to get a frame (or
   // undisplayed entry).
-  NODE_NEEDS_FRAME =             0x00080000U,
+  NODE_NEEDS_FRAME =             0x00008000U,
 
   // At least one descendant in the flattened tree has NODE_NEEDS_FRAME set.
   // This should be set on every node on the flattened tree path between the
   // node(s) with NODE_NEEDS_FRAME and the root content.
-  NODE_DESCENDANTS_NEED_FRAMES = 0x00100000U,
-
-  // Set if the node is an element.
-  NODE_IS_ELEMENT              = 0x00200000U,
-  
-  // Set if the node has the accesskey attribute set.
-  NODE_HAS_ACCESSKEY           = 0x00400000U,
+  NODE_DESCENDANTS_NEED_FRAMES = 0x00010000U,
 
   // Set if the node has the accesskey attribute set.
-  NODE_HAS_NAME                = 0x00800000U,
+  NODE_HAS_ACCESSKEY           = 0x00020000U,
 
   // 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 =               24,
+  NODE_SCRIPT_TYPE_OFFSET =               18,
 
   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
@@ -289,18 +272,18 @@ private:
 #define DOM_USER_DATA         1
 #define DOM_USER_DATA_HANDLER 2
 #ifdef MOZ_SMIL
 #define SMIL_MAPPED_ATTR_ANIMVAL 3
 #endif // MOZ_SMIL
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0x2a8dc794, 0x9178, 0x400e, \
-  { 0x81, 0xff, 0x55, 0x30, 0x30, 0xb6, 0x74, 0x3b } }
+{ 0x4776aa9a, 0xa886, 0x40c9, \
+ { 0xae, 0x4c, 0x4d, 0x92, 0xe2, 0xf0, 0xd9, 0x61 } }
 
 /**
  * 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 nsPIDOMEventTarget,
                 public nsWrapperCache
@@ -311,22 +294,23 @@ public:
   friend class nsNodeUtils;
   friend class nsNodeWeakReference;
   friend class nsNodeSupportsWeakRefTearoff;
   friend class nsAttrAndChildArray;
 
 #ifdef MOZILLA_INTERNAL_API
   nsINode(already_AddRefed<nsINodeInfo> aNodeInfo)
   : mNodeInfo(aNodeInfo),
-    mParentPtrBits(0),
-    mFlagsOrSlots(NODE_DOESNT_HAVE_SLOTS),
+    mParent(nsnull),
+    mFlags(0),
+    mBoolFlags(0),
     mNextSibling(nsnull),
     mPreviousSibling(nsnull),
     mFirstChild(nsnull),
-    mNodeHasRenderingObservers(false)
+    mSlots(nsnull)
   {
   }
 
 #endif
 
   virtual ~nsINode();
 
   /**
@@ -368,18 +352,18 @@ public:
    * @param aFlags what types you want to test for (see above)
    * @return whether the content matches ALL flags passed in
    */
   virtual PRBool IsNodeOfType(PRUint32 aFlags) const = 0;
 
   /**
    * Return whether the node is an Element node
    */
-  PRBool IsElement() const {
-    return HasFlag(NODE_IS_ELEMENT);
+  bool IsElement() const {
+    return GetBoolFlag(NodeIsElement);
   }
 
   /**
    * Return this node as an Element.  Should only be used for nodes
    * for which IsElement() is true.
    */
   mozilla::dom::Element* AsElement();
 
@@ -428,19 +412,19 @@ public:
     return mNodeInfo->GetDocument();
   }
 
   /**
    * Returns true if the content has an ancestor that is a document.
    *
    * @return whether this content is in a document tree
    */
-  PRBool IsInDoc() const
+  bool IsInDoc() const
   {
-    return mParentPtrBits & PARENT_BIT_INDOCUMENT;
+    return GetBoolFlag(IsInDocument);
   }
 
   /**
    * Get the document that this content is currently in, if any. This will be
    * null if the content has no ancestor that is a document.
    *
    * @return the current document
    */
@@ -700,32 +684,29 @@ public:
   nsIPrincipal* NodePrincipal() const {
     return mNodeInfo->NodeInfoManager()->DocumentPrincipal();
   }
 
   /**
    * Get the parent nsIContent for this node.
    * @return the parent, or null if no parent or the parent is not an nsIContent
    */
-  nsIContent* GetParent() const
-  {
-    return NS_LIKELY(mParentPtrBits & PARENT_BIT_PARENT_IS_CONTENT) ?
-           reinterpret_cast<nsIContent*>
-                           (mParentPtrBits & ~kParentBitMask) :
-           nsnull;
+  nsIContent* GetParent() const {
+    return NS_LIKELY(GetBoolFlag(ParentIsContent)) ?
+      reinterpret_cast<nsIContent*>(mParent) : nsnull;
   }
 
   /**
    * Get the parent nsINode for this node. This can be either an nsIContent,
    * an nsIDocument or an nsIAttribute.
    * @return the parent node
    */
   nsINode* GetNodeParent() const
   {
-    return reinterpret_cast<nsINode*>(mParentPtrBits & ~kParentBitMask);
+    return mParent;
   }
 
   /**
    * Adds a mutation observer to be notified when this node, or any of its
    * descendants, are modified. The node will hold a weak reference to the
    * observer, which means that it is the responsibility of the observer to
    * remove itself in case it dies before the node.  If an observer is added
    * while observers are being notified, it may also be notified.  In general,
@@ -795,35 +776,27 @@ public:
     return mNodeInfo->NodeInfoManager() == aOther->mNodeInfo->NodeInfoManager();
   }
 
   // This class can be extended by subclasses that wish to store more
   // information in the slots.
   class nsSlots
   {
   public:
-    nsSlots(PtrBits aFlags)
-      : mFlags(aFlags),
-        mChildNodes(nsnull),
+    nsSlots()
+      : mChildNodes(nsnull),
         mWeakReference(nsnull)
     {
     }
 
     // If needed we could remove the vtable pointer this dtor causes by
     // putting a DestroySlots function on nsINode
     virtual ~nsSlots();
 
     /**
-     * Storage for flags for this node. These are the same flags as the
-     * mFlagsOrSlots member, but these are used when the slots class
-     * is allocated.
-     */
-    PtrBits mFlags;
-
-    /**
      * A list of mutation observers
      */
     nsTObserverArray<nsIMutationObserver*> mMutationObservers;
 
     /**
      * An object implementing nsIDOMNodeList for this content (childNodes)
      * @see nsIDOMNodeList
      * @see nsGenericHTMLElement::GetChildNodes
@@ -848,46 +821,42 @@ public:
   }
 #endif
 
   PRBool HasFlag(PtrBits aFlag) const
   {
     return !!(GetFlags() & aFlag);
   }
 
-  PtrBits GetFlags() const
+  PRUint32 GetFlags() const
   {
-    return NS_UNLIKELY(HasSlots()) ? FlagsAsSlots()->mFlags : mFlagsOrSlots;
+    return mFlags;
   }
 
-  void SetFlags(PtrBits aFlagsToSet)
+  void SetFlags(PRUint32 aFlagsToSet)
   {
     NS_ASSERTION(!(aFlagsToSet & (NODE_IS_ANONYMOUS |
                                   NODE_IS_NATIVE_ANONYMOUS_ROOT |
                                   NODE_IS_IN_ANONYMOUS_SUBTREE |
                                   NODE_ATTACH_BINDING_ON_POSTCREATE |
                                   NODE_DESCENDANTS_NEED_FRAMES |
                                   NODE_NEEDS_FRAME)) ||
                  IsNodeOfType(eCONTENT),
                  "Flag only permitted on nsIContent nodes");
-    PtrBits* flags = HasSlots() ? &FlagsAsSlots()->mFlags :
-                                  &mFlagsOrSlots;
-    *flags |= aFlagsToSet;
+    mFlags |= aFlagsToSet;
   }
 
-  void UnsetFlags(PtrBits aFlagsToUnset)
+  void UnsetFlags(PRUint32 aFlagsToUnset)
   {
     NS_ASSERTION(!(aFlagsToUnset &
                    (NODE_IS_ANONYMOUS |
                     NODE_IS_IN_ANONYMOUS_SUBTREE |
                     NODE_IS_NATIVE_ANONYMOUS_ROOT)),
                  "Trying to unset write-only flags");
-    PtrBits* flags = HasSlots() ? &FlagsAsSlots()->mFlags :
-                                  &mFlagsOrSlots;
-    *flags &= ~aFlagsToUnset;
+    mFlags &= ~aFlagsToUnset;
   }
 
   void SetEditableFlag(PRBool aEditable)
   {
     if (aEditable) {
       SetFlags(NODE_IS_EDITABLE);
     }
     else {
@@ -1143,60 +1112,118 @@ public:
       if (parent == aRoot) {
         return nsnull;
       }
       cur = parent;
     }
     NS_NOTREACHED("How did we get here?");
   }
 
-  bool HasRenderingObservers() { return mNodeHasRenderingObservers; }
+  /**
+   * Boolean flags
+   */
+private:
+  enum BooleanFlag {
+    // Set if we're being used from -moz-element
+    NodeHasRenderingObservers,
+    // Set if our parent chain (including this node itself) terminates
+    // in a document
+    IsInDocument,
+    // Set if mParent is an nsIContent
+    ParentIsContent,
+    // Set if this node is an Element
+    NodeIsElement,
+    // Set if the element has a non-empty id attribute. This can in rare
+    // cases lie for nsXMLElement, such as when the node has been moved between
+    // documents with different id mappings.
+    ElementHasID,
+    // Set if the element might have inline style.
+    ElementMayHaveStyle,
+    // Set if the element has a name attribute set.
+    ElementHasName,
+    // Set if the element might have a contenteditable attribute set.
+    ElementMayHaveContentEditableAttr,
+    // Guard value
+    BooleanFlagCount
+  };
+
+  void SetBoolFlag(BooleanFlag name, bool value) {
+    PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
+    mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
+  }
+
+  void SetBoolFlag(BooleanFlag name) {
+    PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
+    mBoolFlags |= (1 << name);
+  }
+
+  void ClearBoolFlag(BooleanFlag name) {
+    PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
+    mBoolFlags &= ~(1 << name);
+  }
+
+  bool GetBoolFlag(BooleanFlag name) const {
+    PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
+    return mBoolFlags & (1 << name);
+  }
+
+public:
+  bool HasRenderingObservers() const
+    { return GetBoolFlag(NodeHasRenderingObservers); }
   void SetHasRenderingObservers(bool aValue)
-    { mNodeHasRenderingObservers = aValue; }
+    { SetBoolFlag(NodeHasRenderingObservers, aValue); }
+  bool HasID() const { return GetBoolFlag(ElementHasID); }
+  bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
+  bool HasName() const { return GetBoolFlag(ElementHasName); }
+  bool MayHaveContentEditableAttr() const
+    { return GetBoolFlag(ElementMayHaveContentEditableAttr); }
 
+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); }
+  void ClearHasID() { ClearBoolFlag(ElementHasID); }
+  void SetMayHaveStyle() { SetBoolFlag(ElementMayHaveStyle); }
+  void SetHasName() { SetBoolFlag(ElementHasName); }
+  void ClearHasName() { ClearBoolFlag(ElementHasName); }
+  void SetMayHaveContentEditableAttr()
+    { SetBoolFlag(ElementMayHaveContentEditableAttr); }
+
+public:
   // Optimized way to get classinfo.
   virtual nsXPCClassInfo* GetClassInfo() = 0;
 protected:
 
   // Override this function to create a custom slots class.
   virtual nsINode::nsSlots* CreateSlots();
 
   PRBool HasSlots() const
   {
-    return !(mFlagsOrSlots & NODE_DOESNT_HAVE_SLOTS);
-  }
-
-  nsSlots* FlagsAsSlots() const
-  {
-    NS_ASSERTION(HasSlots(), "check HasSlots first");
-    return reinterpret_cast<nsSlots*>(mFlagsOrSlots);
+    return mSlots != nsnull;
   }
 
   nsSlots* GetExistingSlots() const
   {
-    return HasSlots() ? FlagsAsSlots() : nsnull;
+    return mSlots;
   }
 
   nsSlots* GetSlots()
   {
-    if (HasSlots()) {
-      return FlagsAsSlots();
+    if (!HasSlots()) {
+      mSlots = CreateSlots();
     }
-
-    nsSlots* newSlots = CreateSlots();
-    if (newSlots) {
-      mFlagsOrSlots = reinterpret_cast<PtrBits>(newSlots);
-    }
-
-    return newSlots;
+    return GetExistingSlots();
   }
 
   nsTObserverArray<nsIMutationObserver*> *GetMutationObservers()
   {
-    return HasSlots() ? &FlagsAsSlots()->mMutationObservers : nsnull;
+    return HasSlots() ? &GetExistingSlots()->mMutationObservers : nsnull;
   }
 
   PRBool IsEditableInternal() const;
   virtual PRBool IsEditableExternal() const
   {
     return IsEditableInternal();
   }
 
@@ -1263,35 +1290,31 @@ protected:
    * @param aNotify Whether to notify.
    * @param aChildArray The child array to work with
    */
   nsresult doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                            PRBool aNotify, nsAttrAndChildArray& aChildArray);
 
   nsCOMPtr<nsINodeInfo> mNodeInfo;
 
-  enum { PARENT_BIT_INDOCUMENT = 1 << 0, PARENT_BIT_PARENT_IS_CONTENT = 1 << 1 };
-  enum { kParentBitMask = 0x3 };
+  nsINode* mParent;
 
-  PtrBits mParentPtrBits;
+  PRUint32 mFlags;
 
-  /**
-   * Used for either storing flags for this node or a pointer to
-   * this contents nsContentSlots. See the definition of the
-   * NODE_* macros for the layout of the bits in this
-   * member.
-   */
-  PtrBits mFlagsOrSlots;
+private:
+  // Boolean flags.
+  PRUint32 mBoolFlags;
 
+protected:
   nsIContent* mNextSibling;
   nsIContent* mPreviousSibling;
   nsIContent* mFirstChild;
 
-  // More flags
-  bool mNodeHasRenderingObservers : 1;
+  // Storage for more members that are usually not needed; allocated lazily.
+  nsSlots* mSlots;
 };
 
 
 extern const nsIID kThisPtrOffsetsSID;
 
 // _implClass is the class to use to cast to nsISupports
 #define NS_OFFSET_AND_INTERFACE_TABLE_BEGIN_AMBIGUOUS(_class, _implClass)     \
   static const QITableEntry offsetAndQITable[] = {                            \
--- a/content/base/src/nsDocumentFragment.cpp
+++ b/content/base/src/nsDocumentFragment.cpp
@@ -182,17 +182,17 @@ NS_NewDocumentFragment(nsIDOMDocumentFra
   NS_ADDREF(*aInstancePtrResult = it);
 
   return NS_OK;
 }
 
 nsDocumentFragment::nsDocumentFragment(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericElement(aNodeInfo)
 {
-  UnsetFlags(NODE_IS_ELEMENT);
+  ClearIsElement();
 }
 
 nsDocumentFragment::~nsDocumentFragment()
 {
 }
 
 PRBool
 nsDocumentFragment::IsNodeOfType(PRUint32 aFlags) const
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -518,29 +518,29 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
     slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
     if (aParent->IsInNativeAnonymousSubtree()) {
       SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
     }
   }
 
   // Set parent
   if (aParent) {
-    mParentPtrBits =
-      reinterpret_cast<PtrBits>(aParent) | PARENT_BIT_PARENT_IS_CONTENT;
+    mParent = aParent;
   }
   else {
-    mParentPtrBits = reinterpret_cast<PtrBits>(aDocument);
+    mParent = aDocument;
   }
+  SetParentIsContent(aParent);
 
   // XXXbz sXBL/XBL2 issue!
 
   // Set document
   if (aDocument) {
     // XXX See the comment in nsGenericElement::BindToTree
-    mParentPtrBits |= PARENT_BIT_INDOCUMENT;
+    SetInDocument();
     if (mText.IsBidi()) {
       aDocument->SetBidiEnabled();
     }
     // Clear the lazy frame construction bits.
     UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
   }
 
   nsNodeUtils::ParentChainChanged(this);
@@ -565,17 +565,21 @@ nsGenericDOMDataNode::UnbindFromTree(PRB
   nsIDocument *document = GetCurrentDoc();
   if (document) {
     // Notify XBL- & nsIAnonymousContentCreator-generated
     // anonymous content that the document is changing.
     // This is needed to update the insertion point.
     document->BindingManager()->RemovedFromDocument(this, document);
   }
 
-  mParentPtrBits = aNullParent ? 0 : mParentPtrBits & ~PARENT_BIT_INDOCUMENT;
+  if (aNullParent) {
+    mParent = nsnull;
+    SetParentIsContent(false);
+  }
+  ClearInDocument();
 
   nsDataSlots *slots = GetExistingDataSlots();
   if (slots) {
     slots->mBindingParent = nsnull;
   }
 
   nsNodeUtils::ParentChainChanged(this);
 }
@@ -778,17 +782,17 @@ nsGenericDOMDataNode::IsLink(nsIURI** aU
 {
   *aURI = nsnull;
   return PR_FALSE;
 }
 
 nsINode::nsSlots*
 nsGenericDOMDataNode::CreateSlots()
 {
-  return new nsDataSlots(mFlagsOrSlots);
+  return new nsDataSlots();
 }
 
 //----------------------------------------------------------------------
 
 // Implementation of the nsIDOMText interface
 
 nsresult
 nsGenericDOMDataNode::SplitData(PRUint32 aOffset, nsIContent** aReturn,
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -296,18 +296,18 @@ protected:
    * through the DOM. Rather than burn actual slots in the content
    * objects for each of these instance variables, we put them off
    * in a side structure that's only allocated when the content is
    * accessed through the DOM.
    */
   class nsDataSlots : public nsINode::nsSlots
   {
   public:
-    nsDataSlots(PtrBits aFlags)
-      : nsINode::nsSlots(aFlags),
+    nsDataSlots()
+      : nsINode::nsSlots(),
         mBindingParent(nsnull)
     {
     }
 
     /**
      * The nearest enclosing content node with a binding that created us.
      * @see nsIContent::GetBindingParent
      */
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -268,17 +268,17 @@ nsGenericElement::GetSystemEventGroup(ns
   nsIEventListenerManager* elm = GetListenerManager(PR_TRUE);
   NS_ENSURE_STATE(elm);
   return elm->GetSystemEventGroupLM(aGroup);
 }
 
 nsINode::nsSlots*
 nsINode::CreateSlots()
 {
-  return new nsSlots(mFlagsOrSlots);
+  return new nsSlots();
 }
 
 PRBool
 nsINode::IsEditableInternal() const
 {
   if (HasFlag(NODE_IS_EDITABLE)) {
     // The node is in an editable contentEditable subtree.
     return PR_TRUE;
@@ -2133,18 +2133,18 @@ nsNodeSelectorTearoff::QuerySelector(con
 NS_IMETHODIMP
 nsNodeSelectorTearoff::QuerySelectorAll(const nsAString& aSelector,
                                         nsIDOMNodeList **aReturn)
 {
   return nsGenericElement::doQuerySelectorAll(mNode, aSelector, aReturn);
 }
 
 //----------------------------------------------------------------------
-nsGenericElement::nsDOMSlots::nsDOMSlots(PtrBits aFlags)
-  : nsINode::nsSlots(aFlags),
+nsGenericElement::nsDOMSlots::nsDOMSlots()
+  : nsINode::nsSlots(),
     mBindingParent(nsnull)
 {
 }
 
 nsGenericElement::nsDOMSlots::~nsDOMSlots()
 {
   if (mAttributeMap) {
     mAttributeMap->DropReference();
@@ -2155,18 +2155,18 @@ nsGenericElement::nsDOMSlots::~nsDOMSlot
   }
 }
 
 nsGenericElement::nsGenericElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : Element(aNodeInfo)
 {
   // Set the default scriptID to JS - but skip SetScriptTypeID as it
   // does extra work we know isn't necessary here...
-  SetFlags(NODE_IS_ELEMENT |
-           (nsIProgrammingLanguage::JAVASCRIPT << NODE_SCRIPT_TYPE_OFFSET));
+  SetFlags((nsIProgrammingLanguage::JAVASCRIPT << NODE_SCRIPT_TYPE_OFFSET));
+  SetIsElement();
 }
 
 nsGenericElement::~nsGenericElement()
 {
   NS_PRECONDITION(!IsInDoc(),
                   "Please remove this from the document properly");
 }
 
@@ -2938,41 +2938,42 @@ nsGenericElement::BindToTree(nsIDocument
   if (aParent && aParent->IsInNativeAnonymousSubtree()) {
     SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
   }
 
   PRBool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
 
   // Now set the parent and set the "Force attach xbl" flag if needed.
   if (aParent) {
-    mParentPtrBits = reinterpret_cast<PtrBits>(aParent) | PARENT_BIT_PARENT_IS_CONTENT;
+    mParent = aParent;
 
     if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
       SetFlags(NODE_FORCE_XBL_BINDINGS);
     }
   }
   else {
-    mParentPtrBits = reinterpret_cast<PtrBits>(aDocument);
-  }
+    mParent = aDocument;
+  }
+  SetParentIsContent(aParent);
 
   // XXXbz sXBL/XBL2 issue!
 
   // Finally, set the document
   if (aDocument) {
     // Notify XBL- & nsIAnonymousContentCreator-generated
     // anonymous content that the document is changing.
     // XXXbz ordering issues here?  Probably not, since ChangeDocumentFor is
     // just pretty broken anyway....  Need to get it working.
     // XXXbz XBL doesn't handle this (asserts), and we don't really want
     // to be doing this during parsing anyway... sort this out.    
     //    aDocument->BindingManager()->ChangeDocumentFor(this, nsnull,
     //                                                   aDocument);
 
     // Being added to a document.
-    mParentPtrBits |= PARENT_BIT_INDOCUMENT;
+    SetInDocument();
 
     // Unset this flag since we now really are in a document.
     UnsetFlags(NODE_FORCE_XBL_BINDINGS |
                // And clear the lazy frame construction bits.
                NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
                // And the restyle bits
                ELEMENT_ALL_RESTYLE_FLAGS);
   }
@@ -3044,17 +3045,21 @@ nsGenericElement::UnbindFromTree(PRBool 
 {
   NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
                   "Shallow unbind won't clear document and binding parent on "
                   "kids!");
   // Make sure to unbind this node before doing the kids
   nsIDocument *document =
     HasFlag(NODE_FORCE_XBL_BINDINGS) ? GetOwnerDoc() : GetCurrentDoc();
 
-  mParentPtrBits = aNullParent ? 0 : mParentPtrBits & ~PARENT_BIT_INDOCUMENT;
+  if (aNullParent) {
+    mParent = nsnull;
+    SetParentIsContent(false);
+  }
+  ClearInDocument();
 
   if (document) {
     // Notify XBL- & nsIAnonymousContentCreator-generated
     // anonymous content that the document is changing.
     document->BindingManager()->RemovedFromDocument(this, document);
 
     document->ClearBoxObjectFor(this);
   }
@@ -5282,17 +5287,17 @@ PRInt32
 nsGenericElement::IndexOf(nsINode* aPossibleChild) const
 {
   return mAttrsAndChildren.IndexOfChild(aPossibleChild);
 }
 
 nsINode::nsSlots*
 nsGenericElement::CreateSlots()
 {
-  return new nsDOMSlots(mFlagsOrSlots);
+  return new nsDOMSlots();
 }
 
 PRBool
 nsGenericElement::CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor,
                                                        nsIURI** aURI) const
 {
   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
       !NS_IS_TRUSTED_EVENT(aVisitor.mEvent) ||
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -938,17 +938,17 @@ public:
    * through the DOM. Rather than burn actual slots in the content
    * objects for each of these instance variables, we put them off
    * in a side structure that's only allocated when the content is
    * accessed through the DOM.
    */
   class nsDOMSlots : public nsINode::nsSlots
   {
   public:
-    nsDOMSlots(PtrBits aFlags);
+    nsDOMSlots();
     virtual ~nsDOMSlots();
 
     /**
      * The .style attribute (an interface that forwards to the actual
      * style rules)
      * @see nsGenericHTMLElement::GetStyle */
     nsCOMPtr<nsICSSDeclaration> mStyle;
 
@@ -1019,24 +1019,24 @@ protected:
       doc->UnregisterFreezableElement(this);
     }
   }
 
   /**
    * Add/remove this element to the documents id cache
    */
   void AddToIdTable(nsIAtom* aId) {
-    NS_ASSERTION(HasFlag(NODE_HAS_ID), "Node lacking NODE_HAS_ID flag");
+    NS_ASSERTION(HasID(), "Node doesn't have an ID?");
     nsIDocument* doc = GetCurrentDoc();
     if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) {
       doc->AddToIdTable(this, aId);
     }
   }
   void RemoveFromIdTable() {
-    if (HasFlag(NODE_HAS_ID)) {
+    if (HasID()) {
       nsIDocument* doc = GetCurrentDoc();
       if (doc) {
         nsIAtom* id = DoGetID();
         // id can be null during mutation events evilness. Also, XUL elements
         // loose their proto attributes during cc-unlink, so this can happen
         // during cc-unlink too.
         if (id) {
           doc->RemoveFromIdTable(this, DoGetID());
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -247,19 +247,18 @@ 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));
     }
 
-    PtrBits flags = slots->mFlags | NODE_DOESNT_HAVE_SLOTS;
     delete slots;
-    aNode->mFlagsOrSlots = flags;
+    aNode->mSlots = nsnull;
   }
 
   // Kill properties first since that may run external code, so we want to
   // be in as complete state as possible at that time.
   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     // Delete all properties before tearing down the document. Some of the
     // properties are bound to nsINode objects and the destructor functions of
     // the properties may want to use the owner document of the nsINode.
--- a/content/base/src/nsStyledElement.cpp
+++ b/content/base/src/nsStyledElement.cpp
@@ -58,115 +58,121 @@
 #endif
 
 namespace css = mozilla::css;
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 nsIAtom*
-nsStyledElement::GetClassAttributeName() const
+nsStyledElementNotElementCSSInlineStyle::GetClassAttributeName() const
 {
   return nsGkAtoms::_class;
 }
 
 nsIAtom*
-nsStyledElement::GetIDAttributeName() const
+nsStyledElementNotElementCSSInlineStyle::GetIDAttributeName() const
 {
   return nsGkAtoms::id;
 }
 
 nsIAtom*
-nsStyledElement::DoGetID() const
+nsStyledElementNotElementCSSInlineStyle::DoGetID() const
 {
-  NS_ASSERTION(HasFlag(NODE_HAS_ID), "Unexpected call");
+  NS_ASSERTION(HasID(), "Unexpected call");
 
   // The nullcheck here is needed because nsGenericElement::UnsetAttr calls
   // out to various code between removing the attribute and we get a chance to
-  // clear the NODE_HAS_ID flag.
+  // ClearHasID().
 
   const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsGkAtoms::id);
 
   return attr ? attr->GetAtomValue() : nsnull;
 }
 
 const nsAttrValue*
-nsStyledElement::DoGetClasses() const
+nsStyledElementNotElementCSSInlineStyle::DoGetClasses() const
 {
   NS_ASSERTION(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
   return mAttrsAndChildren.GetAttr(nsGkAtoms::_class);
 }
 
 PRBool
-nsStyledElement::ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
-                                const nsAString& aValue, nsAttrValue& aResult)
+nsStyledElementNotElementCSSInlineStyle::ParseAttribute(PRInt32 aNamespaceID,
+                                                        nsIAtom* aAttribute,
+                                                        const nsAString& aValue,
+                                                        nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::style) {
-      SetFlags(NODE_MAY_HAVE_STYLE);
+      SetMayHaveStyle();
       ParseStyleAttribute(aValue, aResult, PR_FALSE);
       return PR_TRUE;
     }
     if (aAttribute == nsGkAtoms::_class) {
       SetFlags(NODE_MAY_HAVE_CLASS);
       aResult.ParseAtomArray(aValue);
       return PR_TRUE;
     }
     if (aAttribute == nsGkAtoms::id) {
       // Store id as an atom.  id="" means that the element has no id,
       // not that it has an emptystring as the id.
       RemoveFromIdTable();
       if (aValue.IsEmpty()) {
-        UnsetFlags(NODE_HAS_ID);
+        ClearHasID();
         return PR_FALSE;
       }
       aResult.ParseAtom(aValue);
-      SetFlags(NODE_HAS_ID);
+      SetHasID();
       AddToIdTable(aResult.GetAtomValue());
       return PR_TRUE;
     }
   }
 
   return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                              aResult);
 }
 
 nsresult
-nsStyledElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
-                           PRBool aNotify)
+nsStyledElementNotElementCSSInlineStyle::UnsetAttr(PRInt32 aNameSpaceID,
+                                                   nsIAtom* aAttribute,
+                                                   PRBool aNotify)
 {
   nsAutoRemovableScriptBlocker scriptBlocker;
   if (aAttribute == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
     // Have to do this before clearing flag. See RemoveFromIdTable
     RemoveFromIdTable();
   }
 
   return nsGenericElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
 }
 
 nsresult
-nsStyledElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aAttribute,
-                              const nsAString* aValue, PRBool aNotify)
+nsStyledElementNotElementCSSInlineStyle::AfterSetAttr(PRInt32 aNamespaceID,
+                                                      nsIAtom* aAttribute,
+                                                      const nsAString* aValue,
+                                                      PRBool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_None && !aValue &&
       aAttribute == nsGkAtoms::id) {
     // The id has been removed when calling UnsetAttr but we kept it because
     // the id is used for some layout stuff between UnsetAttr and AfterSetAttr.
     // Now. the id is really removed so it would not be safe to keep this flag.
-    UnsetFlags(NODE_HAS_ID);
+    ClearHasID();
   }
 
   return nsGenericElement::AfterSetAttr(aNamespaceID, aAttribute, aValue,
                                         aNotify);
 }
 
 NS_IMETHODIMP
-nsStyledElement::SetInlineStyleRule(css::StyleRule* aStyleRule, PRBool aNotify)
+nsStyledElementNotElementCSSInlineStyle::SetInlineStyleRule(css::StyleRule* aStyleRule,
+                                                            PRBool aNotify)
 {
-  SetFlags(NODE_MAY_HAVE_STYLE);
+  SetMayHaveStyle();
   PRBool modification = PR_FALSE;
   nsAutoString oldValueStr;
 
   PRBool hasListeners = aNotify &&
     nsContentUtils::HasMutationListeners(this,
                                          NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
                                          this);
 
@@ -193,67 +199,69 @@ nsStyledElement::SetInlineStyleRule(css:
     static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
 
   return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nsnull,
                           oldValueStr, attrValue, modType, hasListeners,
                           aNotify, nsnull);
 }
 
 css::StyleRule*
-nsStyledElement::GetInlineStyleRule()
+nsStyledElementNotElementCSSInlineStyle::GetInlineStyleRule()
 {
-  if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
+  if (!MayHaveStyle()) {
     return nsnull;
   }
   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
 
   if (attrVal && attrVal->Type() == nsAttrValue::eCSSStyleRule) {
     return attrVal->GetCSSStyleRuleValue();
   }
 
   return nsnull;
 }
 
 nsresult
-nsStyledElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
-                            nsIContent* aBindingParent,
-                            PRBool aCompileEventHandlers)
+nsStyledElementNotElementCSSInlineStyle::BindToTree(nsIDocument* aDocument,
+                                                    nsIContent* aParent,
+                                                    nsIContent* aBindingParent,
+                                                    PRBool aCompileEventHandlers)
 {
   nsresult rv = nsStyledElementBase::BindToTree(aDocument, aParent,
                                                 aBindingParent,
                                                 aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (aDocument && HasFlag(NODE_HAS_ID) && !GetBindingParent()) {
+  if (aDocument && HasID() && !GetBindingParent()) {
     aDocument->AddToIdTable(this, DoGetID());
   }
 
   if (!IsXUL()) {
     // XXXbz if we already have a style attr parsed, this won't do
     // anything... need to fix that.
     ReparseStyleAttribute(PR_FALSE);
   }
 
   return NS_OK;
 }
 
 void
-nsStyledElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
+nsStyledElementNotElementCSSInlineStyle::UnbindFromTree(PRBool aDeep,
+                                                        PRBool aNullParent)
 {
   RemoveFromIdTable();
 
   nsStyledElementBase::UnbindFromTree(aDeep, aNullParent);
 }
 
 
 // ---------------------------------------------------------------
 // Others and helpers
 
 nsIDOMCSSStyleDeclaration*
-nsStyledElement::GetStyle(nsresult* retval)
+nsStyledElementNotElementCSSInlineStyle::GetStyle(nsresult* retval)
 {
   nsXULElement* xulElement = nsXULElement::FromContent(this);
   if (xulElement) {
     nsresult rv = xulElement->EnsureLocalStyle();
     if (NS_FAILED(rv)) {
       *retval = rv;
       return nsnull;
     }
@@ -265,27 +273,27 @@ nsStyledElement::GetStyle(nsresult* retv
     // Just in case...
     ReparseStyleAttribute(PR_TRUE);
 
     slots->mStyle = new nsDOMCSSAttributeDeclaration(this
 #ifdef MOZ_SMIL
                                                      , PR_FALSE
 #endif // MOZ_SMIL
                                                      );
-    SetFlags(NODE_MAY_HAVE_STYLE);
+    SetMayHaveStyle();
   }
 
   *retval = NS_OK;
   return slots->mStyle;
 }
 
 nsresult
-nsStyledElement::ReparseStyleAttribute(PRBool aForceInDataDoc)
+nsStyledElementNotElementCSSInlineStyle::ReparseStyleAttribute(PRBool aForceInDataDoc)
 {
-  if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
+  if (!MayHaveStyle()) {
     return NS_OK;
   }
   const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
   
   if (oldVal && oldVal->Type() != nsAttrValue::eCSSStyleRule) {
     nsAttrValue attrValue;
     nsAutoString stringValue;
     oldVal->ToString(stringValue);
@@ -295,19 +303,19 @@ nsStyledElement::ReparseStyleAttribute(P
     nsresult rv = mAttrsAndChildren.SetAndTakeAttr(nsGkAtoms::style, attrValue);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   
   return NS_OK;
 }
 
 void
-nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
-                                     nsAttrValue& aResult,
-                                     PRBool aForceInDataDoc)
+nsStyledElementNotElementCSSInlineStyle::ParseStyleAttribute(const nsAString& aValue,
+                                                             nsAttrValue& aResult,
+                                                             PRBool aForceInDataDoc)
 {
   nsIDocument* doc = GetOwnerDoc();
 
   if (doc && (aForceInDataDoc ||
               !doc->IsLoadedAsData() ||
               doc->IsStaticDocument())) {
     PRBool isCSS = PR_TRUE; // assume CSS until proven otherwise
 
--- a/content/base/src/nsStyledElement.h
+++ b/content/base/src/nsStyledElement.h
@@ -52,22 +52,22 @@
 namespace mozilla {
 namespace css {
 class StyleRule;
 }
 }
 
 typedef nsGenericElement nsStyledElementBase;
 
-class nsStyledElement : public nsStyledElementBase
+class nsStyledElementNotElementCSSInlineStyle : public nsStyledElementBase
 {
 
 protected:
 
-  inline nsStyledElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+  inline nsStyledElementNotElementCSSInlineStyle(already_AddRefed<nsINodeInfo> aNodeInfo)
     : nsStyledElementBase(aNodeInfo)
   {}
 
 public:
 
   // nsIContent interface methods
   virtual nsIAtom* GetClassAttributeName() const;
   virtual nsIAtom* GetIDAttributeName() const;
@@ -109,9 +109,16 @@ protected:
    * Create the style struct from the style attr.  Used when an element is
    * first put into a document.  Only has an effect if the old value is a
    * string.  If aForceInDataDoc is true, will reparse even if we're in a data
    * document.
    */
   nsresult  ReparseStyleAttribute(PRBool aForceInDataDoc);
 };
 
+class nsStyledElement : public nsStyledElementNotElementCSSInlineStyle {
+protected:
+  inline nsStyledElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+    : nsStyledElementNotElementCSSInlineStyle(aNodeInfo)
+  {}
+};
+
 #endif // __NS_STYLEDELEMENT_H_
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -210,28 +210,30 @@ nsTextNode::CloneDataNode(nsINodeInfo *a
 
 nsresult
 nsTextNode::BindToAttribute(nsIAttribute* aAttr)
 {
   NS_ASSERTION(!IsInDoc(), "Unbind before binding!");
   NS_ASSERTION(!GetNodeParent(), "Unbind before binding!");
   NS_ASSERTION(HasSameOwnerDoc(aAttr), "Wrong owner document!");
 
-  mParentPtrBits = reinterpret_cast<PtrBits>(aAttr);
+  mParent = aAttr;
+  SetParentIsContent(false);
+  ClearInDocument();
   return NS_OK;
 }
 
 nsresult
 nsTextNode::UnbindFromAttribute()
 {
   NS_ASSERTION(GetNodeParent(), "Bind before unbinding!");
   NS_ASSERTION(GetNodeParent() &&
                GetNodeParent()->IsNodeOfType(nsINode::eATTRIBUTE),
                "Use this method only to unbind from an attribute!");
-  mParentPtrBits = 0;
+  mParent = nsnull;
   return NS_OK;
 }
 
 #ifdef DEBUG
 void
 nsTextNode::List(FILE* out, PRInt32 aIndent) const
 {
   PRInt32 index;
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -1114,16 +1114,17 @@ nsCanvasRenderingContext2D::SetDimension
     }
     if (surface) {
         if (gCanvasMemoryReporter == nsnull) {
             gCanvasMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasMemory);
             NS_RegisterMemoryReporter(gCanvasMemoryReporter);
         }
 
         gCanvasMemoryUsed += width * height * 4;
+        JS_updateMallocCounter(nsContentUtils::GetCurrentJSContext(), width * height * 4);
     }
 
     return InitializeWithSurface(NULL, surface, width, height);
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height) {
     Reset();
@@ -3839,42 +3840,61 @@ nsCanvasRenderingContext2D::GetImageData
     if (mCanvasElement &&
         HTMLCanvasElement()->IsWriteOnly() &&
         !nsContentUtils::IsCallerTrustedForRead())
     {
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_DOM_SECURITY_ERR;
     }
 
-    if (w == 0 || h == 0)
+    if (w == 0 || h == 0 || aDataLen != w * h * 4)
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    if (!CanvasUtils::CheckSaneSubrectSize (x, y, w, h, mWidth, mHeight))
-        return NS_ERROR_DOM_SYNTAX_ERR;
-
-    PRUint32 len = w * h * 4;
-    if (aDataLen != len)
+    CheckedInt32 rightMost = CheckedInt32(x) + w;
+    CheckedInt32 bottomMost = CheckedInt32(y) + h;
+
+    if (!rightMost.valid() || !bottomMost.valid())
         return NS_ERROR_DOM_SYNTAX_ERR;
 
     /* Copy the surface contents to the buffer */
-    nsRefPtr<gfxImageSurface> tmpsurf = new gfxImageSurface(aData,
-                                                            gfxIntSize(w, h),
-                                                            w * 4,
-                                                            gfxASurface::ImageFormatARGB32);
-    if (!tmpsurf || tmpsurf->CairoStatus())
+    nsRefPtr<gfxImageSurface> tmpsurf =
+        new gfxImageSurface(aData,
+                            gfxIntSize(w, h),
+                            w * 4,
+                            gfxASurface::ImageFormatARGB32);
+
+    if (tmpsurf->CairoStatus())
         return NS_ERROR_FAILURE;
 
     nsRefPtr<gfxContext> tmpctx = new gfxContext(tmpsurf);
 
-    if (!tmpctx || tmpctx->HasError())
+    if (tmpctx->HasError())
         return NS_ERROR_FAILURE;
 
-    tmpctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-    tmpctx->SetSource(mSurface, gfxPoint(-(int)x, -(int)y));
-    tmpctx->Paint();
+    gfxRect srcRect(0, 0, mWidth, mHeight);
+    gfxRect destRect(x, y, w, h);
+
+    bool finishedPainting = false;
+    // In the common case, we want to avoid the Rectangle call.
+    if (!srcRect.Contains(destRect)) {
+        // If the requested area is entirely outside the canvas, we're done.
+        gfxRect tmp = srcRect.Intersect(destRect);
+        finishedPainting = tmp.IsEmpty();
+
+        // Set clipping region if necessary.
+        if (!finishedPainting) {
+            tmpctx->Rectangle(tmp);
+        }
+    }
+
+    if (!finishedPainting) {
+        tmpctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+        tmpctx->SetSource(mSurface, gfxPoint(-x, -y));
+        tmpctx->Paint();
+    }
 
     // make sure sUnpremultiplyTable has been created
     EnsureUnpremultiplyTable();
 
     // NOTE! dst is the same as src, and this relies on reading
     // from src and advancing that ptr before writing to dst.
     PRUint8 *src = aData;
     PRUint8 *dst = aData;
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -7952,40 +7952,36 @@ var ctx = canvas.getContext('2d');
 var _thrown_outer = false;
 try {
 
 ctx.fillStyle = '#000';
 ctx.fillRect(0, 0, 100, 50);
 ctx.fillStyle = '#fff';
 ctx.fillRect(20, 10, 60, 10);
 
-try {
-  var imgdata1 = ctx.getImageData(85, 25, -10, -10);
-  ok(imgdata1.data[0] === 255, "imgdata1.data[\""+(0)+"\"] === 255");
-  ok(imgdata1.data[1] === 255, "imgdata1.data[\""+(1)+"\"] === 255");
-  ok(imgdata1.data[2] === 255, "imgdata1.data[\""+(2)+"\"] === 255");
-  ok(imgdata1.data[3] === 255, "imgdata1.data[\""+(3)+"\"] === 255");
-  ok(imgdata1.data[imgdata1.data.length-4+0] === 0, "imgdata1.data[imgdata1.data.length-4+0] === 0");
-  ok(imgdata1.data[imgdata1.data.length-4+1] === 0, "imgdata1.data[imgdata1.data.length-4+1] === 0");
-  ok(imgdata1.data[imgdata1.data.length-4+2] === 0, "imgdata1.data[imgdata1.data.length-4+2] === 0");
-  ok(imgdata1.data[imgdata1.data.length-4+3] === 255, "imgdata1.data[imgdata1.data.length-4+3] === 255");
-} catch (e) {
-  ok(false, "Unexpected exception in first part of test_2d_imageData_get_source_negative()", e);
-}
+var imgdata1 = ctx.getImageData(85, 25, -10, -10);
+ok(imgdata1.data[0] === 255, "imgdata1.data[\""+(0)+"\"] === 255");
+ok(imgdata1.data[1] === 255, "imgdata1.data[\""+(1)+"\"] === 255");
+ok(imgdata1.data[2] === 255, "imgdata1.data[\""+(2)+"\"] === 255");
+ok(imgdata1.data[3] === 255, "imgdata1.data[\""+(3)+"\"] === 255");
+ok(imgdata1.data[imgdata1.data.length-4+0] === 0, "imgdata1.data[imgdata1.data.length-4+0] === 0");
+ok(imgdata1.data[imgdata1.data.length-4+1] === 0, "imgdata1.data[imgdata1.data.length-4+1] === 0");
+ok(imgdata1.data[imgdata1.data.length-4+2] === 0, "imgdata1.data[imgdata1.data.length-4+2] === 0");
+ok(imgdata1.data[imgdata1.data.length-4+3] === 255, "imgdata1.data[imgdata1.data.length-4+3] === 255");
 
 var imgdata2 = ctx.getImageData(0, 0, -1, -1);
 ok(imgdata2.data[0] === 0, "imgdata2.data[\""+(0)+"\"] === 0");
 ok(imgdata2.data[1] === 0, "imgdata2.data[\""+(1)+"\"] === 0");
 ok(imgdata2.data[2] === 0, "imgdata2.data[\""+(2)+"\"] === 0");
 ok(imgdata2.data[3] === 0, "imgdata2.data[\""+(3)+"\"] === 0");
 
 } catch (e) {
     _thrown_outer = true;
 }
-todo(!_thrown_outer, 'should not throw exception');
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.get.source.outside.html ]]] -->
 
 <p>Canvas test: 2d.imageData.get.source.outside</p>
@@ -8023,20 +8019,54 @@ ok(imgdata3.data[2] === 0, "imgdata3.dat
 ok(imgdata3.data[3] === 0, "imgdata3.data[\""+(3)+"\"] === 0");
 
 var imgdata4 = ctx.getImageData(10, 60, 1, 1);
 ok(imgdata4.data[0] === 0, "imgdata4.data[\""+(0)+"\"] === 0");
 ok(imgdata4.data[1] === 0, "imgdata4.data[\""+(1)+"\"] === 0");
 ok(imgdata4.data[2] === 0, "imgdata4.data[\""+(2)+"\"] === 0");
 ok(imgdata4.data[3] === 0, "imgdata4.data[\""+(3)+"\"] === 0");
 
-} catch (e) {
-    _thrown_outer = true;
-}
-todo(!_thrown_outer, 'should not throw exception');
+var imgdata5 = ctx.getImageData(100, 10, 1, 1);
+ok(imgdata5.data[0] === 0, "imgdata5.data[\""+(0)+"\"] === 0");
+ok(imgdata5.data[1] === 0, "imgdata5.data[\""+(1)+"\"] === 0");
+ok(imgdata5.data[2] === 0, "imgdata5.data[\""+(2)+"\"] === 0");
+ok(imgdata5.data[3] === 0, "imgdata5.data[\""+(3)+"\"] === 0");
+
+var imgdata6 = ctx.getImageData(0, 10, 1, 1);
+ok(imgdata6.data[0] === 0, "imgdata6.data[\""+(0)+"\"] === 0");
+ok(imgdata6.data[1] === 136, "imgdata6.data[\""+(1)+"\"] === 136");
+ok(imgdata6.data[2] === 255, "imgdata6.data[\""+(2)+"\"] === 255");
+ok(imgdata6.data[3] === 255, "imgdata6.data[\""+(3)+"\"] === 255");
+
+var imgdata7 = ctx.getImageData(-10, 10, 20, 20);
+ok(imgdata7.data[ 0*4+0] === 0, "imgdata7.data[ 0*4+0] === 0");
+ok(imgdata7.data[ 0*4+1] === 0, "imgdata7.data[ 0*4+1] === 0");
+ok(imgdata7.data[ 0*4+2] === 0, "imgdata7.data[ 0*4+2] === 0");
+ok(imgdata7.data[ 0*4+3] === 0, "imgdata7.data[ 0*4+3] === 0");
+ok(imgdata7.data[ 9*4+0] === 0, "imgdata7.data[ 9*4+0] === 0");
+ok(imgdata7.data[ 9*4+1] === 0, "imgdata7.data[ 9*4+1] === 0");
+ok(imgdata7.data[ 9*4+2] === 0, "imgdata7.data[ 9*4+2] === 0");
+ok(imgdata7.data[ 9*4+3] === 0, "imgdata7.data[ 9*4+3] === 0");
+ok(imgdata7.data[10*4+0] === 0, "imgdata7.data[10*4+0] === 0");
+ok(imgdata7.data[10*4+1] === 136, "imgdata7.data[10*4+1] === 136");
+ok(imgdata7.data[10*4+2] === 255, "imgdata7.data[10*4+2] === 255");
+ok(imgdata7.data[10*4+3] === 255, "imgdata7.data[10*4+3] === 255");
+ok(imgdata7.data[19*4+0] === 0, "imgdata7.data[19*4+0] === 0");
+ok(imgdata7.data[19*4+1] === 136, "imgdata7.data[19*4+1] === 136");
+ok(imgdata7.data[19*4+2] === 255, "imgdata7.data[19*4+2] === 255");
+ok(imgdata7.data[19*4+3] === 255, "imgdata7.data[19*4+3] === 255");
+ok(imgdata7.data[20*4+0] === 0, "imgdata7.data[20*4+0] === 0");
+ok(imgdata7.data[20*4+1] === 0, "imgdata7.data[20*4+1] === 0");
+ok(imgdata7.data[20*4+2] === 0, "imgdata7.data[20*4+2] === 0");
+ok(imgdata7.data[20*4+3] === 0, "imgdata7.data[20*4+3] === 0");
+
+} catch (e) {
+    _thrown_outer = true;
+}
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.get.source.size.html ]]] -->
 
 <p>Canvas test: 2d.imageData.get.source.size</p>
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -943,17 +943,17 @@ nsGenericHTMLElement::BindToTree(nsIDocu
                                  PRBool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElementBase::BindToTree(aDocument, aParent,
                                                      aBindingParent,
                                                      aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDocument) {
-    if (HasFlag(NODE_HAS_NAME)) {
+    if (HasName()) {
       aDocument->
         AddToNameTable(this, GetParsedAttr(nsGkAtoms::name)->GetAtomValue());
     }
     if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue) {
       nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
       if (htmlDocument) {
         htmlDocument->ChangeContentEditableCount(this, +1);
       }
@@ -1183,17 +1183,17 @@ nsGenericHTMLElement::SetAttr(PRInt32 aN
                               nsIAtom* aPrefix, const nsAString& aValue,
                               PRBool aNotify)
 {
   PRBool contentEditable = aNameSpaceID == kNameSpaceID_None &&
                            aName == nsGkAtoms::contenteditable;
   PRInt32 change;
   if (contentEditable) {
     change = GetContentEditableValue() == eTrue ? -1 : 0;
-    SetFlags(NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR);
+    SetMayHaveContentEditableAttr();
   }
 
   nsresult rv = nsStyledElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                          aNotify);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (contentEditable) {
     if (aValue.IsEmpty() || aValue.LowerCaseEqualsLiteral("true")) {
@@ -1213,17 +1213,17 @@ nsGenericHTMLElement::UnsetAttr(PRInt32 
   PRBool contentEditable = PR_FALSE;
   PRInt32 contentEditableChange;
 
   // Check for event handlers
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::name) {
       // Have to do this before clearing flag. See RemoveFromNameTable
       RemoveFromNameTable();
-      UnsetFlags(NODE_HAS_NAME);
+      ClearHasName();
     }
     else if (aAttribute == nsGkAtoms::contenteditable) {
       contentEditable = PR_TRUE;
       contentEditableChange = GetContentEditableValue() == eTrue ? -1 : 0;
     }
     else if (nsContentUtils::IsEventAttributeName(aAttribute,
                                                   EventNameType_HTML)) {
       nsIEventListenerManager* manager = GetListenerManager(PR_FALSE);
@@ -1282,24 +1282,24 @@ nsGenericHTMLElement::ParseAttribute(PRI
       return aResult.ParseIntWithBounds(aValue, -32768, 32767);
     }
 
     if (aAttribute == nsGkAtoms::name) {
       // Store name as an atom.  name="" means that the element has no name,
       // not that it has an emptystring as the name.
       RemoveFromNameTable();
       if (aValue.IsEmpty()) {
-        UnsetFlags(NODE_HAS_NAME);
+        ClearHasName();
         return PR_FALSE;
       }
 
       aResult.ParseAtom(aValue);
 
       if (CanHaveName(Tag())) {
-        SetFlags(NODE_HAS_NAME);
+        SetHasName();
         AddToNameTable(aResult.GetAtomValue());
       }
       
       return PR_TRUE;
     }
 
     if (aAttribute == nsGkAtoms::contenteditable) {
       aResult.ParseAtom(aValue);
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -522,24 +522,24 @@ public:
     return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
   }
 
 protected:
   /**
    * Add/remove this element to the documents name cache
    */
   void AddToNameTable(nsIAtom* aName) {
-    NS_ASSERTION(HasFlag(NODE_HAS_NAME), "Node lacking NODE_HAS_NAME flag");
+    NS_ASSERTION(HasName(), "Node doesn't have name?");
     nsIDocument* doc = GetCurrentDoc();
     if (doc && !IsInAnonymousSubtree()) {
       doc->AddToNameTable(this, aName);
     }
   }
   void RemoveFromNameTable() {
-    if (HasFlag(NODE_HAS_NAME)) {
+    if (HasName()) {
       nsIDocument* doc = GetCurrentDoc();
       if (doc) {
         doc->RemoveFromNameTable(this, GetParsedAttr(nsGkAtoms::name)->
                                          GetAtomValue());
       }
     }
   }
 
@@ -786,17 +786,17 @@ protected:
    * contentEditable attribute and its value is "false". Otherwise returns
    * eInherit.
    */
   NS_HIDDEN_(ContentEditableTristate) GetContentEditableValue() const
   {
     static const nsIContent::AttrValuesArray values[] =
       { &nsGkAtoms::_false, &nsGkAtoms::_true, &nsGkAtoms::_empty, nsnull };
 
-    if (!HasFlag(NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR))
+    if (!MayHaveContentEditableAttr())
       return eInherit;
 
     PRInt32 value = FindAttrValueIn(kNameSpaceID_None,
                                     nsGkAtoms::contenteditable, values,
                                     eIgnoreCase);
 
     return value > 0 ? eTrue : (value == 0 ? eFalse : eInherit);
   }
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2608,17 +2608,17 @@ static void
 FindNamedItems(nsIAtom* aName, nsIContent *aContent,
                nsIdentifierMapEntry* aEntry)
 {
   NS_ASSERTION(aEntry->HasNameContentList(),
                "Entry w/o content list passed to FindNamedItems()!");
   NS_ASSERTION(!aEntry->IsInvalidName(),
                "Entry that should never have a list passed to FindNamedItems()!");
 
-  if (aContent->HasFlag(NODE_HAS_NAME)) {
+  if (aContent->HasName()) {
     NS_ASSERTION(nsGenericHTMLElement::FromContent(aContent),
                  "Only HTML Elements should have a name");
   
     nsGenericHTMLElement* elm = static_cast<nsGenericHTMLElement*>(aContent);
     if (elm->GetParsedAttr(nsGkAtoms::name)->GetAtomValue() == aName) {
       aEntry->AddNameElement(elm);
     }
   }
--- a/content/media/nsMediaStream.cpp
+++ b/content/media/nsMediaStream.cpp
@@ -65,17 +65,18 @@ using namespace mozilla;
 
 nsMediaChannelStream::nsMediaChannelStream(nsMediaDecoder* aDecoder,
     nsIChannel* aChannel, nsIURI* aURI)
   : nsMediaStream(aDecoder, aChannel, aURI),
     mOffset(0), mSuspendCount(0),
     mReopenOnError(PR_FALSE), mIgnoreClose(PR_FALSE),
     mCacheStream(this),
     mLock("nsMediaChannelStream.mLock"),
-    mCacheSuspendCount(0)
+    mCacheSuspendCount(0),
+    mIgnoreResume(PR_FALSE)
 {
 }
 
 nsMediaChannelStream::~nsMediaChannelStream()
 {
   if (mListener) {
     // Kill its reference to us since we're going away
     mListener->Revoke();
@@ -271,17 +272,20 @@ nsMediaChannelStream::OnStartRequest(nsI
     MutexAutoLock lock(mLock);
     mChannelStatistics.Start(TimeStamp::Now());
   }
 
   mReopenOnError = PR_FALSE;
   mIgnoreClose = PR_FALSE;
   if (mSuspendCount > 0) {
     // Re-suspend the channel if it needs to be suspended
+    // No need to call PossiblySuspend here since the channel is
+    // definitely in the right state for us in OneStartRequest.
     mChannel->Suspend();
+    mIgnoreResume = PR_FALSE;
   }
 
   // Fires an initial progress event and sets up the stall counter so stall events
   // fire if no download occurs within the required time frame.
   mDecoder->Progress(PR_FALSE);
 
   return NS_OK;
 }
@@ -551,17 +555,17 @@ void nsMediaChannelStream::CloseChannel(
   if (mListener) {
     mListener->Revoke();
     mListener = nsnull;
   }
 
   if (mChannel) {
     if (mSuspendCount > 0) {
       // Resume the channel before we cancel it
-      mChannel->Resume();
+      PossiblyResume();
     }
     // The status we use here won't be passed to the decoder, since
     // we've already revoked the listener. It can however be passed
     // to DocumentViewerImpl::LoadComplete if our channel is the one
     // that kicked off creation of a video document. We don't want that
     // document load to think there was an error.
     // NS_ERROR_PARSED_DATA_CACHED is the best thing we have for that
     // at the moment.
@@ -621,17 +625,17 @@ void nsMediaChannelStream::Suspend(PRBoo
       mIgnoreClose = PR_TRUE;
       CloseChannel();
       element->DownloadSuspended();
     } else if (mSuspendCount == 0) {
       {
         MutexAutoLock lock(mLock);
         mChannelStatistics.Stop(TimeStamp::Now());
       }
-      mChannel->Suspend();
+      PossiblySuspend();
       element->DownloadSuspended();
     }
   }
 
   ++mSuspendCount;
 }
 
 void nsMediaChannelStream::Resume()
@@ -652,17 +656,17 @@ void nsMediaChannelStream::Resume()
       // Just wake up our existing channel
       {
         MutexAutoLock lock(mLock);
         mChannelStatistics.Start(TimeStamp::Now());
       }
       // if an error occurs after Resume, assume it's because the server
       // timed out the connection and we should reopen it.
       mReopenOnError = PR_TRUE;
-      mChannel->Resume();
+      PossiblyResume();
       element->DownloadResumed();
     } else {
       PRInt64 totalLength = mCacheStream.GetLength();
       // If mOffset is at the end of the stream, then we shouldn't try to
       // seek to it. The seek will fail and be wasted anyway. We can leave
       // the channel dead; if the media cache wants to read some other data
       // in the future, it will call CacheClientSeek itself which will reopen the
       // channel.
@@ -862,16 +866,39 @@ nsMediaChannelStream::GetDownloadRate(PR
 }
 
 PRInt64
 nsMediaChannelStream::GetLength()
 {
   return mCacheStream.GetLength();
 }
 
+void
+nsMediaChannelStream::PossiblySuspend()
+{
+  PRBool isPending = PR_FALSE;
+  nsresult rv = mChannel->IsPending(&isPending);
+  if (NS_SUCCEEDED(rv) && isPending) {
+    mChannel->Suspend();
+    mIgnoreResume = PR_FALSE;
+  } else {
+    mIgnoreResume = PR_TRUE;
+  }
+}
+
+void
+nsMediaChannelStream::PossiblyResume()
+{
+  if (!mIgnoreResume) {
+    mChannel->Resume();
+  } else {
+    mIgnoreResume = PR_FALSE;
+  }
+}
+
 class nsMediaFileStream : public nsMediaStream
 {
 public:
   nsMediaFileStream(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
     nsMediaStream(aDecoder, aChannel, aURI), mSize(-1),
     mLock("nsMediaFileStream.mLock")
   {
   }
--- a/content/media/nsMediaStream.h
+++ b/content/media/nsMediaStream.h
@@ -447,16 +447,24 @@ protected:
 
   static NS_METHOD CopySegmentToCache(nsIInputStream *aInStream,
                                       void *aClosure,
                                       const char *aFromSegment,
                                       PRUint32 aToOffset,
                                       PRUint32 aCount,
                                       PRUint32 *aWriteCount);
 
+  // Suspend the channel only if the channels is currently downloading data.
+  // If it isn't we set a flag, mIgnoreResume, so that PossiblyResume knows
+  // whether to acutually resume or not.
+  void PossiblySuspend();
+
+  // Resume from a suspend if we actually suspended (See PossiblySuspend).
+  void PossiblyResume();
+
   // Main thread access only
   PRInt64            mOffset;
   nsRefPtr<Listener> mListener;
   // A data received event for the decoder that has been dispatched but has
   // not yet been processed.
   nsRevocableEventPtr<nsRunnableMethod<nsMediaChannelStream, void, false> > mDataReceivedEvent;
   PRUint32           mSuspendCount;
   // When this flag is set, if we get a network error we should silently
@@ -468,11 +476,16 @@ protected:
 
   // Any thread access
   nsMediaCacheStream mCacheStream;
 
   // This lock protects mChannelStatistics and mCacheSuspendCount
   Mutex               mLock;
   nsChannelStatistics mChannelStatistics;
   PRUint32            mCacheSuspendCount;
+
+  // PR_TRUE if we couldn't suspend the stream and we therefore don't want
+  // to resume later. This is usually due to the channel not being in the
+  // isPending state at the time of the suspend request.
+  PRPackedBool mIgnoreResume;
 };
 
 #endif
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -87,16 +87,31 @@ namespace mozilla {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGLengthList)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLengthList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
 NS_INTERFACE_MAP_END
 
 
+nsIDOMSVGLength*
+DOMSVGLengthList::GetItemWithoutAddRef(PRUint32 aIndex)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  if (aIndex < Length()) {
+    EnsureItemAt(aIndex);
+    return mItems[aIndex];
+  }
+  return nsnull;
+}
+
 void
 DOMSVGLengthList::InternalListLengthWillChange(PRUint32 aNewLength)
 {
   PRUint32 oldLength = mItems.Length();
 
   if (aNewLength > DOMSVGLength::MaxListIndex()) {
     // It's safe to get out of sync with our internal list as long as we have
     // FEWER items than it does.
@@ -205,28 +220,22 @@ DOMSVGLengthList::Initialize(nsIDOMSVGLe
   Clear();
   return InsertItemBefore(newItem, 0, _retval);
 }
 
 NS_IMETHODIMP
 DOMSVGLengthList::GetItem(PRUint32 index,
                           nsIDOMSVGLength **_retval)
 {
-#ifdef MOZ_SMIL
-  if (IsAnimValList()) {
-    Element()->FlushAnimations();
+  *_retval = GetItemWithoutAddRef(index);
+  if (!*_retval) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
-#endif
-  if (index < Length()) {
-    EnsureItemAt(index);
-    NS_ADDREF(*_retval = mItems[index]);
-    return NS_OK;
-  }
-  *_retval = nsnull;
-  return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  NS_ADDREF(*_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
                                    PRUint32 index,
                                    nsIDOMSVGLength **_retval)
 {
   *_retval = nsnull;
@@ -362,16 +371,22 @@ DOMSVGLengthList::RemoveItem(PRUint32 in
 
 NS_IMETHODIMP
 DOMSVGLengthList::AppendItem(nsIDOMSVGLength *newItem,
                              nsIDOMSVGLength **_retval)
 {
   return InsertItemBefore(newItem, Length(), _retval);
 }
 
+NS_IMETHODIMP
+DOMSVGLengthList::GetLength(PRUint32 *aNumberOfItems)
+{
+  return GetNumberOfItems(aNumberOfItems);
+}
+
 void
 DOMSVGLengthList::EnsureItemAt(PRUint32 aIndex)
 {
   if (!mItems[aIndex]) {
     mItems[aIndex] = new DOMSVGLength(this, AttrEnum(), aIndex, IsAnimValList());
   }
 }
 
--- a/content/svg/content/src/DOMSVGLengthList.h
+++ b/content/svg/content/src/DOMSVGLengthList.h
@@ -104,16 +104,18 @@ public:
   PRUint32 Length() const {
     NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
                       mItems.Length() ==
                         const_cast<DOMSVGLengthList*>(this)->InternalList().Length(),
                       "DOM wrapper's list length is out of sync");
     return mItems.Length();
   }
 
+  nsIDOMSVGLength* GetItemWithoutAddRef(PRUint32 aIndex);
+
   /// Called to notify us to syncronize our length and detach excess items.
   void InternalListLengthWillChange(PRUint32 aNewLength);
 
 private:
 
   nsSVGElement* Element() {
     return mAList->mElement;
   }
--- a/content/svg/content/src/DOMSVGNumberList.cpp
+++ b/content/svg/content/src/DOMSVGNumberList.cpp
@@ -87,16 +87,31 @@ namespace mozilla {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGNumberList)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGNumberList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumberList)
 NS_INTERFACE_MAP_END
 
 
+nsIDOMSVGNumber*
+DOMSVGNumberList::GetItemWithoutAddRef(PRUint32 aIndex)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  if (aIndex < Length()) {
+    EnsureItemAt(aIndex);
+    return mItems[aIndex];
+  }
+  return nsnull;
+}
+
 void
 DOMSVGNumberList::InternalListLengthWillChange(PRUint32 aNewLength)
 {
   PRUint32 oldLength = mItems.Length();
 
   if (aNewLength > DOMSVGNumber::MaxListIndex()) {
     // It's safe to get out of sync with our internal list as long as we have
     // FEWER items than it does.
@@ -205,28 +220,22 @@ DOMSVGNumberList::Initialize(nsIDOMSVGNu
   Clear();
   return InsertItemBefore(newItem, 0, _retval);
 }
 
 NS_IMETHODIMP
 DOMSVGNumberList::GetItem(PRUint32 index,
                           nsIDOMSVGNumber **_retval)
 {
-#ifdef MOZ_SMIL
-  if (IsAnimValList()) {
-    Element()->FlushAnimations();
+  *_retval = GetItemWithoutAddRef(index);
+  if (!*_retval) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
-#endif
-  if (index < Length()) {
-    EnsureItemAt(index);
-    NS_ADDREF(*_retval = mItems[index]);
-    return NS_OK;
-  }
-  *_retval = nsnull;
-  return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  NS_ADDREF(*_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGNumberList::InsertItemBefore(nsIDOMSVGNumber *newItem,
                                    PRUint32 index,
                                    nsIDOMSVGNumber **_retval)
 {
   *_retval = nsnull;
@@ -362,16 +371,22 @@ DOMSVGNumberList::RemoveItem(PRUint32 in
 
 NS_IMETHODIMP
 DOMSVGNumberList::AppendItem(nsIDOMSVGNumber *newItem,
                              nsIDOMSVGNumber **_retval)
 {
   return InsertItemBefore(newItem, Length(), _retval);
 }
 
+NS_IMETHODIMP
+DOMSVGNumberList::GetLength(PRUint32 *aNumberOfItems)
+{
+  return GetNumberOfItems(aNumberOfItems);
+}
+
 void
 DOMSVGNumberList::EnsureItemAt(PRUint32 aIndex)
 {
   if (!mItems[aIndex]) {
     mItems[aIndex] = new DOMSVGNumber(this, AttrEnum(), aIndex, IsAnimValList());
   }
 }
 
--- a/content/svg/content/src/DOMSVGNumberList.h
+++ b/content/svg/content/src/DOMSVGNumberList.h
@@ -103,16 +103,18 @@ public:
   PRUint32 Length() const {
     NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
                       mItems.Length() ==
                         const_cast<DOMSVGNumberList*>(this)->InternalList().Length(),
                       "DOM wrapper's list length is out of sync");
     return mItems.Length();
   }
 
+  nsIDOMSVGNumber* GetItemWithoutAddRef(PRUint32 aIndex);
+
   /// Called to notify us to syncronize our length and detach excess items.
   void InternalListLengthWillChange(PRUint32 aNewLength);
 
 private:
 
   nsSVGElement* Element() {
     return mAList->mElement;
   }
--- a/content/svg/content/src/DOMSVGPathSegList.cpp
+++ b/content/svg/content/src/DOMSVGPathSegList.cpp
@@ -91,16 +91,31 @@ DOMSVGPathSegList::~DOMSVGPathSegList()
   // There are now no longer any references to us held by script or list items.
   // Note we must use GetAnimValKey/GetBaseValKey here, NOT InternalList()!
   void *key = mIsAnimValList ?
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPathSegListTearoffTable.RemoveTearoff(key);
 }
 
+nsIDOMSVGPathSeg*
+DOMSVGPathSegList::GetItemWithoutAddRef(PRUint32 aIndex)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  if (aIndex < Length()) {
+    EnsureItemAt(aIndex);
+    return ItemAt(aIndex);
+  }
+  return nsnull;
+}
+
 void
 DOMSVGPathSegList::InternalListWillChangeTo(const SVGPathData& aNewValue)
 {
   // When the number of items in our internal counterpart changes, we MUST stay
   // in sync. Everything in the scary comment in
   // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here just as
   // much, but we have the additional issue that failing to stay in sync would
   // mean that - assuming we aren't reading bad memory - we would likely end up
@@ -300,28 +315,22 @@ DOMSVGPathSegList::Initialize(nsIDOMSVGP
   Clear();
   return InsertItemBefore(aNewItem, 0, _retval);
 }
 
 NS_IMETHODIMP
 DOMSVGPathSegList::GetItem(PRUint32 aIndex,
                            nsIDOMSVGPathSeg **_retval)
 {
-#ifdef MOZ_SMIL
-  if (IsAnimValList()) {
-    Element()->FlushAnimations();
+  *_retval = GetItemWithoutAddRef(aIndex);
+  if (!*_retval) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
-#endif
-  if (aIndex < Length()) {
-    EnsureItemAt(aIndex);
-    NS_ADDREF(*_retval = ItemAt(aIndex));
-    return NS_OK;
-  }
-  *_retval = nsnull;
-  return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  NS_ADDREF(*_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGPathSegList::InsertItemBefore(nsIDOMSVGPathSeg *aNewItem,
                                     PRUint32 aIndex,
                                     nsIDOMSVGPathSeg **_retval)
 {
   *_retval = nsnull;
@@ -493,16 +502,22 @@ DOMSVGPathSegList::RemoveItem(PRUint32 a
 
 NS_IMETHODIMP
 DOMSVGPathSegList::AppendItem(nsIDOMSVGPathSeg *aNewItem,
                               nsIDOMSVGPathSeg **_retval)
 {
   return InsertItemBefore(aNewItem, Length(), _retval);
 }
 
+NS_IMETHODIMP
+DOMSVGPathSegList::GetLength(PRUint32 *aNumberOfItems)
+{
+  return GetNumberOfItems(aNumberOfItems);
+}
+
 void
 DOMSVGPathSegList::EnsureItemAt(PRUint32 aIndex)
 {
   if (!ItemAt(aIndex)) {
     ItemAt(aIndex) = DOMSVGPathSeg::CreateFor(this, aIndex, IsAnimValList());
   }
 }
 
--- a/content/svg/content/src/DOMSVGPathSegList.h
+++ b/content/svg/content/src/DOMSVGPathSegList.h
@@ -121,16 +121,18 @@ public:
   PRUint32 Length() const {
     NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
                       mItems.Length() ==
                         const_cast<DOMSVGPathSegList*>(this)->InternalList().CountItems(),
                       "DOM wrapper's list length is out of sync");
     return mItems.Length();
   }
 
+  nsIDOMSVGPathSeg* GetItemWithoutAddRef(PRUint32 aIndex);
+
   /**
    * WATCH OUT! If you add code to call this on a baseVal wrapper, then you
    * must also call it on the animVal wrapper too if necessary!! See other
    * callers!
    *
    * Called by internal code to notify us when we need to sync the length of
    * this DOM list with its internal list. This is called immediately prior to
    * the length of the internal list being changed so that any DOM list items
--- a/content/svg/content/src/DOMSVGPointList.cpp
+++ b/content/svg/content/src/DOMSVGPointList.cpp
@@ -111,16 +111,31 @@ DOMSVGPointList::~DOMSVGPointList()
   // There are now no longer any references to us held by script or list items.
   // Note we must use GetAnimValKey/GetBaseValKey here, NOT InternalList()!
   void *key = mIsAnimValList ?
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPointListTearoffTable.RemoveTearoff(key);
 }
 
+nsIDOMSVGPoint*
+DOMSVGPointList::GetItemWithoutAddRef(PRUint32 aIndex)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  if (aIndex < Length()) {
+    EnsureItemAt(aIndex);
+    return mItems[aIndex];
+  }
+  return nsnull;
+}
+
 void
 DOMSVGPointList::InternalListWillChangeTo(const SVGPointList& aNewValue)
 {
   // When the number of items in our internal counterpart changes, we MUST stay
   // in sync. Everything in the scary comment in
   // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here too!
 
   PRUint32 oldLength = mItems.Length();
@@ -256,28 +271,22 @@ DOMSVGPointList::Initialize(nsIDOMSVGPoi
   Clear();
   return InsertItemBefore(aNewItem, 0, _retval);
 }
 
 NS_IMETHODIMP
 DOMSVGPointList::GetItem(PRUint32 aIndex,
                          nsIDOMSVGPoint **_retval)
 {
-#ifdef MOZ_SMIL
-  if (IsAnimValList()) {
-    Element()->FlushAnimations();
+  *_retval = GetItemWithoutAddRef(aIndex);
+  if (!*_retval) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
-#endif
-  if (aIndex < Length()) {
-    EnsureItemAt(aIndex);
-    NS_ADDREF(*_retval = mItems[aIndex]);
-    return NS_OK;
-  }
-  *_retval = nsnull;
-  return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  NS_ADDREF(*_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGPointList::InsertItemBefore(nsIDOMSVGPoint *aNewItem,
                                   PRUint32 aIndex,
                                   nsIDOMSVGPoint **_retval)
 {
   *_retval = nsnull;
@@ -413,16 +422,22 @@ DOMSVGPointList::RemoveItem(PRUint32 aIn
 
 NS_IMETHODIMP
 DOMSVGPointList::AppendItem(nsIDOMSVGPoint *aNewItem,
                             nsIDOMSVGPoint **_retval)
 {
   return InsertItemBefore(aNewItem, Length(), _retval);
 }
 
+NS_IMETHODIMP
+DOMSVGPointList::GetLength(PRUint32 *aNumberOfItems)
+{
+  return GetNumberOfItems(aNumberOfItems);
+}
+
 void
 DOMSVGPointList::EnsureItemAt(PRUint32 aIndex)
 {
   if (!mItems[aIndex]) {
     mItems[aIndex] = new DOMSVGPoint(this, aIndex, IsAnimValList());
   }
 }
 
--- a/content/svg/content/src/DOMSVGPointList.h
+++ b/content/svg/content/src/DOMSVGPointList.h
@@ -121,16 +121,18 @@ public:
   PRUint32 Length() const {
     NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
                       mItems.Length() ==
                         const_cast<DOMSVGPointList*>(this)->InternalList().Length(),
                       "DOM wrapper's list length is out of sync");
     return mItems.Length();
   }
 
+  nsIDOMSVGPoint* GetItemWithoutAddRef(PRUint32 aIndex);
+
   /**
    * WATCH OUT! If you add code to call this on a baseVal wrapper, then you
    * must also call it on the animVal wrapper too if necessary!! See other
    * callers!
    *
    * Called by internal code to notify us when we need to sync the length of
    * this DOM list with its internal list. This is called immediately prior to
    * the length of the internal list being changed so that any DOM list items
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -119,28 +119,27 @@ SVGPathData::AppendSeg(PRUint32 aType, .
   }
   va_end(args);
   return NS_OK;
 }
 
 float
 SVGPathData::GetPathLength() const
 {
-  float length = 0.0;
   SVGPathTraversalState state;
 
   PRUint32 i = 0;
   while (i < mData.Length()) {
-    length += SVGPathSegUtils::GetLength(&mData[i], state);
+    SVGPathSegUtils::TraversePathSegment(&mData[i], state);
     i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
   }
 
   NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
 
-  return length;
+  return state.length;
 }
 
 #ifdef DEBUG
 PRUint32
 SVGPathData::CountItems() const
 {
   PRUint32 i = 0, count = 0;
 
@@ -158,54 +157,55 @@ SVGPathData::CountItems() const
 PRBool
 SVGPathData::GetSegmentLengths(nsTArray<double> *aLengths) const
 {
   aLengths->Clear();
   SVGPathTraversalState state;
 
   PRUint32 i = 0;
   while (i < mData.Length()) {
-    if (!aLengths->AppendElement(SVGPathSegUtils::GetLength(&mData[i], state))) {
+    state.length = 0.0;
+    SVGPathSegUtils::TraversePathSegment(&mData[i], state);
+    if (!aLengths->AppendElement(state.length)) {
       aLengths->Clear();
       return PR_FALSE;
     }
     i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
   }
 
   NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
 
   return PR_TRUE;
 }
 
 PRBool
 SVGPathData::GetDistancesFromOriginToEndsOfVisibleSegments(nsTArray<double> *aOutput) const
 {
-  double distRunningTotal = 0.0;
   SVGPathTraversalState state;
 
   aOutput->Clear();
 
   PRUint32 i = 0;
   while (i < mData.Length()) {
     PRUint32 segType = SVGPathSegUtils::DecodeType(mData[i]);
+    SVGPathSegUtils::TraversePathSegment(&mData[i], state);
 
     // We skip all moveto commands except an initial moveto. See the text 'A
     // "move to" command does not count as an additional point when dividing up
     // the duration...':
     //
     // http://www.w3.org/TR/SVG11/animate.html#AnimateMotionElement
     //
     // This is important in the non-default case of calcMode="linear". In
     // this case an equal amount of time is spent on each path segment,
     // except on moveto segments which are jumped over immediately.
 
     if (i == 0 || (segType != nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS &&
                    segType != nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL)) {
-      distRunningTotal += SVGPathSegUtils::GetLength(&mData[i], state);
-      if (!aOutput->AppendElement(distRunningTotal)) {
+      if (!aOutput->AppendElement(state.length)) {
         return PR_FALSE;
       }
     }
     i += 1 + SVGPathSegUtils::ArgCountForType(segType);
   }
 
   NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt?");
 
@@ -215,23 +215,22 @@ SVGPathData::GetDistancesFromOriginToEnd
 PRUint32
 SVGPathData::GetPathSegAtLength(float aDistance) const
 {
   // TODO [SVGWG issue] get specified what happen if 'aDistance' < 0, or
   // 'aDistance' > the length of the path, or the seg list is empty.
   // Return -1? Throwing would better help authors avoid tricky bugs (DOM
   // could do that if we return -1).
 
-  double distRunningTotal = 0.0;
   PRUint32 i = 0, segIndex = 0;
   SVGPathTraversalState state;
 
   while (i < mData.Length()) {
-    distRunningTotal += SVGPathSegUtils::GetLength(&mData[i], state);
-    if (distRunningTotal >= aDistance) {
+    SVGPathSegUtils::TraversePathSegment(&mData[i], state);
+    if (state.length >= aDistance) {
       return segIndex;
     }
     i += 1 + SVGPathSegUtils::ArgCountForType(mData[i]);
     segIndex++;
   }
 
   NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
 
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -100,33 +100,34 @@ class SVGPathData
   friend class SVGAnimatedPathSegList;
   friend class DOMSVGPathSegList;
   friend class DOMSVGPathSeg;
   friend class ::nsSVGPathDataParserToInternal;
   // nsSVGPathDataParserToInternal will not keep wrappers in sync, so consumers
   // are responsible for that!
 
 public:
+  typedef const float* const_iterator;
 
   SVGPathData(){}
   ~SVGPathData(){}
 
   // Only methods that don't make/permit modification to this list are public.
   // Only our friend classes can access methods that may change us.
 
   /// This may return an incomplete string on OOM, but that's acceptable.
   void GetValueAsString(nsAString& aValue) const;
 
   PRBool IsEmpty() const {
     return mData.IsEmpty();
   }
 
 #ifdef DEBUG
   /**
-   * This method iterates over the encoded segment data and countes the number
+   * This method iterates over the encoded segment data and counts the number
    * of segments we currently have.
    */
   PRUint32 CountItems() const;
 #endif
 
   /**
    * Returns the number of *floats* in the encoding array, and NOT the number
    * of segments encoded in this object. (For that, see CountItems() above.)
@@ -173,24 +174,28 @@ public:
    */
   PRBool GetDistancesFromOriginToEndsOfVisibleSegments(nsTArray<double> *aArray) const;
 
   already_AddRefed<gfxFlattenedPath>
   ToFlattenedPath(const gfxMatrix& aMatrix) const;
 
   void ConstructPath(gfxContext *aCtx) const;
 
+  const_iterator begin() const { return mData.Elements(); }
+  const_iterator end() const { return mData.Elements() + mData.Length(); }
+
   // Access to methods that can modify objects of this type is deliberately
   // limited. This is to reduce the chances of someone modifying objects of
   // this type without taking the necessary steps to keep DOM wrappers in sync.
   // If you need wider access to these methods, consider adding a method to
   // SVGAnimatedPathSegList and having that class act as an intermediary so it
   // can take care of keeping DOM wrappers in sync.
 
 protected:
+  typedef float* iterator;
 
   /**
    * This may fail on OOM if the internal capacity needs to be increased, in
    * which case the list will be left unmodified.
    */
   nsresult CopyFrom(const SVGPathData& rhs);
 
   float& operator[](PRUint32 aIndex) {
@@ -216,32 +221,34 @@ protected:
   //
   // * InsertItem(PRUint32 aDataIndex, PRUint32 aType, const float *aArgs);
   // * ReplaceItem(PRUint32 aDataIndex, PRUint32 aType, const float *aArgs);
   // * RemoveItem(PRUint32 aDataIndex);
   // * PRBool AppendItem(PRUint32 aType, const float *aArgs);
 
   nsresult AppendSeg(PRUint32 aType, ...); // variable number of float args
 
+  iterator begin() { return mData.Elements(); }
+  iterator end() { return mData.Elements() + mData.Length(); }
+
   nsTArray<float> mData;
 };
 
 
 /**
  * This SVGPathData subclass is for SVGPathSegListSMILType which needs to
  * have write access to the lists it works with.
  *
  * Instances of this class do not have DOM wrappers that need to be kept in
  * sync, so we can safely expose any protected base class methods required by
  * the SMIL code.
  */
 class SVGPathDataAndOwner : public SVGPathData
 {
 public:
-
   SVGPathDataAndOwner(nsSVGElement *aElement = nsnull)
     : mElement(aElement)
   {}
 
   void SetElement(nsSVGElement *aElement) {
     mElement = aElement;
   }
 
@@ -254,28 +261,24 @@ public:
     return SVGPathData::CopyFrom(rhs);
   }
 
   /**
    * Exposed so that SVGPathData baseVals can be copied to
    * SVGPathDataAndOwner objects. Note that callers should also call
    * SetElement() when using this method!
    */
-  nsresult CopyFrom(const SVGPathData& rhs) {
-    return SVGPathData::CopyFrom(rhs);
-  }
-  const float& operator[](PRUint32 aIndex) const {
-    return SVGPathData::operator[](aIndex);
-  }
-  float& operator[](PRUint32 aIndex) {
-    return SVGPathData::operator[](aIndex);
-  }
-  PRBool SetLength(PRUint32 aNumberOfItems) {
-    return SVGPathData::SetLength(aNumberOfItems);
-  }
+  using SVGPathData::CopyFrom;
+
+  // Exposed since SVGPathData objects can be modified.
+  using SVGPathData::iterator;
+  using SVGPathData::operator[];
+  using SVGPathData::SetLength;
+  using SVGPathData::begin;
+  using SVGPathData::end;
 
 private:
   // We must keep a strong reference to our element because we may belong to a
   // cached baseVal nsSMILValue. See the comments starting at:
   // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15
   nsRefPtr<nsSVGElement> mElement;
 };
 
--- a/content/svg/content/src/SVGPathSegListSMILType.cpp
+++ b/content/svg/content/src/SVGPathSegListSMILType.cpp
@@ -84,59 +84,290 @@ SVGPathSegListSMILType::IsEqual(const ns
 {
   NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
   NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
 
   return *static_cast<const SVGPathDataAndOwner*>(aLeft.mU.mPtr) ==
          *static_cast<const SVGPathDataAndOwner*>(aRight.mU.mPtr);
 }
 
+static PRBool
+ArcFlagsDiffer(SVGPathDataAndOwner::const_iterator aPathData1,
+               SVGPathDataAndOwner::const_iterator aPathData2)
+{
+  NS_ABORT_IF_FALSE
+    (SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData1[0])),
+                                "ArcFlagsDiffer called with non-arc segment");
+  NS_ABORT_IF_FALSE
+    (SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData2[0])),
+                                "ArcFlagsDiffer called with non-arc segment");
+
+  return aPathData1[4] != aPathData2[4] ||  // large arc flag
+         aPathData1[5] != aPathData2[5];    // sweep flag
+}
+
+enum PathInterpolationResult {
+  eCannotInterpolate,
+  eRequiresConversion,
+  eCanInterpolate
+};
+
+static PathInterpolationResult
+CanInterpolate(const SVGPathDataAndOwner& aStart,
+               const SVGPathDataAndOwner& aEnd)
+{
+  if (aStart.IsEmpty()) {
+    return eCanInterpolate;
+  }
+
+  if (aStart.Length() != aEnd.Length()) {
+    return eCannotInterpolate;
+  }
+
+  PathInterpolationResult result = eCanInterpolate;
+
+  SVGPathDataAndOwner::const_iterator pStart = aStart.begin();
+  SVGPathDataAndOwner::const_iterator pEnd = aEnd.begin();
+  SVGPathDataAndOwner::const_iterator pStartDataEnd = aStart.end();
+  SVGPathDataAndOwner::const_iterator pEndDataEnd = aEnd.end();
+
+  while (pStart < pStartDataEnd && pEnd < pEndDataEnd) {
+    PRUint32 startType = SVGPathSegUtils::DecodeType(*pStart);
+    PRUint32 endType = SVGPathSegUtils::DecodeType(*pEnd);
+
+    if (SVGPathSegUtils::IsArcType(startType) &&
+        SVGPathSegUtils::IsArcType(endType) &&
+        ArcFlagsDiffer(pStart, pEnd)) {
+      return eCannotInterpolate;
+    }
+
+    if (startType != endType) {
+      if (!SVGPathSegUtils::SameTypeModuloRelativeness(startType, endType)) {
+        return eCannotInterpolate;
+      }
+
+      result = eRequiresConversion;
+    }
+
+    pStart += 1 + SVGPathSegUtils::ArgCountForType(startType);
+    pEnd += 1 + SVGPathSegUtils::ArgCountForType(endType);
+  }
+
+  NS_ABORT_IF_FALSE(pStart <= pStartDataEnd && pEnd <= pEndDataEnd,
+                    "Iterated past end of buffer! (Corrupt path data?)");
+
+  if (pStart != pStartDataEnd || pEnd != pEndDataEnd) {
+    return eCannotInterpolate;
+  }
+
+  return result;
+}
+
+static void
+InterpolatePathSegmentData(SVGPathDataAndOwner::const_iterator& aStart,
+                           SVGPathDataAndOwner::const_iterator& aEnd,
+                           SVGPathDataAndOwner::iterator& aResult,
+                           float aUnitDistance)
+{
+  PRUint32 startType = SVGPathSegUtils::DecodeType(*aStart);
+  PRUint32 endType = SVGPathSegUtils::DecodeType(*aEnd);
+
+  NS_ABORT_IF_FALSE
+    (startType == endType,
+     "InterpolatePathSegmentData expects segment types to be the same!");
+
+  NS_ABORT_IF_FALSE
+    (!(SVGPathSegUtils::IsArcType(startType) && ArcFlagsDiffer(aStart, aEnd)),
+     "InterpolatePathSegmentData cannot interpolate arc segments with different flag values!");
+
+  PRUint32 argCount = SVGPathSegUtils::ArgCountForType(startType);
+
+  // Copy over segment type.
+  *aResult++ = *aStart++;
+  ++aEnd;
+
+  // Interpolate the arguments.
+  SVGPathDataAndOwner::const_iterator startSegEnd = aStart + argCount;
+  while (aStart != startSegEnd) {
+    *aResult = *aStart + (*aEnd - *aStart) * aUnitDistance;
+    ++aStart;
+    ++aEnd;
+    ++aResult;
+  }
+}
+
+enum RelativenessAdjustmentType {
+  eAbsoluteToRelative,
+  eRelativeToAbsolute
+};
+
+static inline void
+AdjustSegmentForRelativeness(RelativenessAdjustmentType aAdjustmentType,
+                             const SVGPathDataAndOwner::iterator& aSegmentToAdjust,
+                             const SVGPathTraversalState& aState)
+{
+  if (aAdjustmentType == eAbsoluteToRelative) {
+    aSegmentToAdjust[0] -= aState.pos.x;
+    aSegmentToAdjust[1] -= aState.pos.y;
+  } else {
+    aSegmentToAdjust[0] += aState.pos.x;
+    aSegmentToAdjust[1] += aState.pos.y;
+  }
+}
+
+static void
+ConvertPathSegmentData(SVGPathDataAndOwner::const_iterator& aStart,
+                       SVGPathDataAndOwner::const_iterator& aEnd,
+                       SVGPathDataAndOwner::iterator& aResult,
+                       SVGPathTraversalState& aState)
+{
+  PRUint32 startType = SVGPathSegUtils::DecodeType(*aStart);
+  PRUint32 endType = SVGPathSegUtils::DecodeType(*aEnd);
+
+  PRUint32 segmentLengthIncludingType =
+      1 + SVGPathSegUtils::ArgCountForType(startType);
+
+  SVGPathDataAndOwner::const_iterator pResultSegmentBegin = aResult;
+
+  if (startType == endType) {
+    // No conversion need, just directly copy aStart.
+    aEnd += segmentLengthIncludingType;
+    while (segmentLengthIncludingType) {
+      *aResult++ = *aStart++;
+      --segmentLengthIncludingType;
+    }
+    SVGPathSegUtils::TraversePathSegment(pResultSegmentBegin, aState);
+    return;
+  }
+
+  NS_ABORT_IF_FALSE
+      (SVGPathSegUtils::SameTypeModuloRelativeness(startType, endType),
+       "Incompatible path segment types passed to ConvertPathSegmentData!");
+
+  RelativenessAdjustmentType adjustmentType =
+    SVGPathSegUtils::IsRelativeType(startType) ? eRelativeToAbsolute
+                                               : eAbsoluteToRelative;
+
+  NS_ABORT_IF_FALSE
+    (segmentLengthIncludingType ==
+       1 + SVGPathSegUtils::ArgCountForType(endType),
+     "Compatible path segment types for interpolation had different lengths!");
+
+  aResult[0] = aEnd[0];
+
+  switch (endType) {
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
+      aResult[1] = aStart[1] +
+        (adjustmentType == eRelativeToAbsolute ? 1 : -1) * aState.pos.x;
+      break;
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
+      aResult[1] = aStart[1] +
+        (adjustmentType == eRelativeToAbsolute  ? 1 : -1) * aState.pos.y;
+      break;
+    case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
+      aResult[1] = aStart[1];
+      aResult[2] = aStart[2];
+      aResult[3] = aStart[3];
+      aResult[4] = aStart[4];
+      aResult[5] = aStart[5];
+      aResult[6] = aStart[6];
+      aResult[7] = aStart[7];
+      AdjustSegmentForRelativeness(adjustmentType, aResult + 6, aState);
+      break;
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
+      aResult[5] = aStart[5];
+      aResult[6] = aStart[6];
+      AdjustSegmentForRelativeness(adjustmentType, aResult + 5, aState);
+      // fall through
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+      aResult[3] = aStart[3];
+      aResult[4] = aStart[4];
+      AdjustSegmentForRelativeness(adjustmentType, aResult + 3, aState);
+      // fall through
+    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
+    case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
+      aResult[1] = aStart[1];
+      aResult[2] = aStart[2];
+      AdjustSegmentForRelativeness(adjustmentType, aResult + 1, aState);
+      break;
+  }
+
+  SVGPathSegUtils::TraversePathSegment(pResultSegmentBegin, aState);
+  aStart += segmentLengthIncludingType;
+  aEnd += segmentLengthIncludingType;
+  aResult += segmentLengthIncludingType;
+}
+
+static void
+ConvertAllPathSegmentData(SVGPathDataAndOwner::const_iterator aStart,
+                          SVGPathDataAndOwner::const_iterator aStartDataEnd,
+                          SVGPathDataAndOwner::const_iterator aEnd,
+                          SVGPathDataAndOwner::const_iterator aEndDataEnd,
+                          SVGPathDataAndOwner::iterator aResult)
+{
+  SVGPathTraversalState state;
+  state.mode = SVGPathTraversalState::eUpdateOnlyStartAndCurrentPos;
+  while (aStart < aStartDataEnd && aEnd < aEndDataEnd) {
+    ConvertPathSegmentData(aStart, aEnd, aResult, state);
+  }
+  NS_ABORT_IF_FALSE(aStart == aStartDataEnd && aEnd == aEndDataEnd,
+                    "Failed to convert all path segment data! (Corrupt?)");
+}
+
 nsresult
 SVGPathSegListSMILType::Add(nsSMILValue& aDest,
                             const nsSMILValue& aValueToAdd,
                             PRUint32 aCount) const
 {
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
   NS_PRECONDITION(aValueToAdd.mType == this, "Incompatible SMIL type");
 
   SVGPathDataAndOwner& dest =
     *static_cast<SVGPathDataAndOwner*>(aDest.mU.mPtr);
   const SVGPathDataAndOwner& valueToAdd =
     *static_cast<const SVGPathDataAndOwner*>(aValueToAdd.mU.mPtr);
 
-  if (dest.Length() != valueToAdd.Length()) {
-    // Allow addition to empty dest:
-    if (dest.Length() == 0) {
-      return dest.CopyFrom(valueToAdd);
-    }
-    // For now we only support animation to a list with the same number of
-    // items (and with the same segment types).
-    // nsSVGUtils::ReportToConsole
+  // Allow addition to empty dest.
+  if (dest.IsEmpty()) {
+    return dest.CopyFrom(valueToAdd);
+  }
+
+  PathInterpolationResult check = CanInterpolate(dest, valueToAdd);
+
+  if (check == eCannotInterpolate) {
+    // nsSVGUtils::ReportToConsole - can't add path segment lists with different
+    // numbers of segments, with arcs with different flag values, or with
+    // incompatible segment types.
     return NS_ERROR_FAILURE;
   }
 
+  if (check == eRequiresConversion) {
+    ConvertAllPathSegmentData(dest.begin(), dest.end(),
+                              valueToAdd.begin(), valueToAdd.end(),
+                              dest.begin());
+  }
+
   PRUint32 i = 0;
   while (i < dest.Length()) {
     PRUint32 type = SVGPathSegUtils::DecodeType(dest[i]);
-    if (type != SVGPathSegUtils::DecodeType(valueToAdd[i])) {
-      // nsSVGUtils::ReportToConsole - can't yet animate between different
-      // types, although it would make sense to allow animation between
-      // some.
-      return NS_ERROR_FAILURE;
-    }
     i++;
-    if ((type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
-         type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) &&
-        (dest[i+3] != valueToAdd[i+3] || dest[i+4] != valueToAdd[i+4])) {
-      // boolean args largeArcFlag and sweepFlag must be the same
-      return NS_ERROR_FAILURE;
-    }
     PRUint32 segEnd = i + SVGPathSegUtils::ArgCountForType(type);
     for (; i < segEnd; ++i) {
-      dest[i] += valueToAdd[i];
+      dest[i] += valueToAdd[i] * aCount;
     }
   }
 
   NS_ABORT_IF_FALSE(i == dest.Length(), "Very, very bad - path data corrupt");
 
   // For now we only support pure 'to' animation.
   // nsSVGUtils::ReportToConsole
   return NS_OK;
@@ -170,73 +401,71 @@ SVGPathSegListSMILType::Interpolate(cons
 
   const SVGPathDataAndOwner& start =
     *static_cast<const SVGPathDataAndOwner*>(aStartVal.mU.mPtr);
   const SVGPathDataAndOwner& end =
     *static_cast<const SVGPathDataAndOwner*>(aEndVal.mU.mPtr);
   SVGPathDataAndOwner& result =
     *static_cast<SVGPathDataAndOwner*>(aResult.mU.mPtr);
 
-  if (start.Length() != end.Length() && start.Length() != 0) {
-    // For now we only support animation to a list with the same number of
-    // items (and with the same segment types).
-    // nsSVGUtils::ReportToConsole
+  PathInterpolationResult check = CanInterpolate(start, end); 
+
+  if (check == eCannotInterpolate) {
+    // nsSVGUtils::ReportToConsole - can't interpolate path segment lists with
+    // different numbers of segments, with arcs with different flag values, or
+    // with incompatible segment types.
     return NS_ERROR_FAILURE;
   }
 
   if (!result.SetLength(end.Length())) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  PRUint32 i = 0;
-
-  if (start.Length() == 0) { // identity path
+  if (start.IsEmpty()) { // identity path
+    PRUint32 i = 0;
     while (i < end.Length()) {
       PRUint32 type = SVGPathSegUtils::DecodeType(end[i]);
       result[i] = end[i];
       i++;
       PRUint32 segEnd = i + SVGPathSegUtils::ArgCountForType(type);
-      if ((type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
-           type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL)) {
+      if (SVGPathSegUtils::IsArcType(type)) {
         result[i] = end[i] * aUnitDistance;
         result[i+1] = end[i+1] * aUnitDistance;
         result[i+2] = end[i+2] * aUnitDistance;
         // boolean args largeArcFlag and sweepFlag must be the same
         result[i+3] = end[i+3];
         result[i+4] = end[i+4];
         result[i+5] = end[i+5] * aUnitDistance;
         result[i+6] = end[i+6] * aUnitDistance;
         i = segEnd;
       } else {
         for (; i < segEnd; ++i) {
           result[i] = end[i] * aUnitDistance;
         }
       }
     }
+    NS_ABORT_IF_FALSE(i == end.Length() && i == result.Length(),
+                      "Very, very bad - path data corrupt");
   } else {
-    while (i < end.Length()) {
-      PRUint32 type = SVGPathSegUtils::DecodeType(end[i]);
-      if (type != SVGPathSegUtils::DecodeType(start[i])) {
-        // nsSVGUtils::ReportToConsole - can't yet interpolate between different
-        // types, although it would make sense to allow interpolation between
-        // some.
-        return NS_ERROR_FAILURE;
-      }
-      result[i] = end[i];
-      i++;
-      if ((type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
-           type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) &&
-          (start[i+3] != end[i+3] || start[i+4] != end[i+4])) {
-        // boolean args largeArcFlag and sweepFlag must be the same
-        return NS_ERROR_FAILURE;
-      }
-      PRUint32 segEnd = i + SVGPathSegUtils::ArgCountForType(type);
-      for (; i < segEnd; ++i) {
-        result[i] = start[i] + (end[i] - start[i]) * aUnitDistance;
-      }
+    SVGPathDataAndOwner::const_iterator pStart = start.begin();
+    SVGPathDataAndOwner::const_iterator pStartDataEnd = start.end();
+    SVGPathDataAndOwner::const_iterator pEnd = end.begin();
+    SVGPathDataAndOwner::const_iterator pEndDataEnd = end.end();
+    SVGPathDataAndOwner::iterator pResult = result.begin();
+
+    if (check == eRequiresConversion) {
+      ConvertAllPathSegmentData(pStart, pStartDataEnd, pEnd, pEndDataEnd,
+                                pResult);
+      pStart = pResult;
+      pStartDataEnd = result.end();
     }
-  }
+
+    while (pStart != pStartDataEnd && pEnd != pEndDataEnd) {
+      InterpolatePathSegmentData(pStart, pEnd, pResult, aUnitDistance);
+    }
 
-  NS_ABORT_IF_FALSE(i == end.Length(), "Very, very bad - path data corrupt");
+    NS_ABORT_IF_FALSE(pStart == pStartDataEnd && pEnd == pEndDataEnd &&
+                      pResult == result.end(),
+                      "Very, very bad - path data corrupt");
+  }
 
   return NS_OK;
 }
-
--- a/content/svg/content/src/SVGPathSegUtils.cpp
+++ b/content/svg/content/src/SVGPathSegUtils.cpp
@@ -49,27 +49,28 @@
 
 using namespace mozilla;
 
 static const float PATH_SEG_LENGTH_TOLERANCE = 0.0000001f;
 static const PRUint32 MAX_RECURSION = 10;
 
 
 /* static */ void
-SVGPathSegUtils::GetValueAsString(const float *aSeg, nsAString& aValue)
+SVGPathSegUtils::GetValueAsString(const float* aSeg, nsAString& aValue)
 {
   // Adding new seg type? Is the formatting below acceptable for the new types?
+  PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
+                     nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
   PR_STATIC_ASSERT(NS_SVG_PATH_SEG_MAX_ARGS == 7);
 
   PRUint32 type = DecodeType(aSeg[0]);
   PRUnichar typeAsChar = GetPathSegTypeAsLetter(type);
 
   // Special case arcs:
-  if (type == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
-      type == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) {
+  if (IsArcType(type)) {
     PRBool largeArcFlag = aSeg[4] != 0.0f;
     PRBool sweepFlag = aSeg[5] != 0.0f;
     nsTextFormatter::ssprintf(aValue,
                               NS_LITERAL_STRING("%c%g,%g %g %d,%d %g,%g").get(),
                               typeAsChar, aSeg[1], aSeg[2], aSeg[3],
                               largeArcFlag, sweepFlag, aSeg[6], aSeg[7]);
   } else {
 
@@ -114,348 +115,371 @@ SVGPathSegUtils::GetValueAsString(const 
   //
   if (aValue[aValue.Length() - 1] == PRUnichar('\0')) {
     aValue.SetLength(aValue.Length() - 1);
   }
 }
 
 
 static float
-CalcDistanceBetweenPoints(const gfxPoint &p1, const gfxPoint &p2)
+CalcDistanceBetweenPoints(const gfxPoint& aP1, const gfxPoint& aP2)
 {
-  return NS_hypot(p2.x - p1.x, p2.y - p1.y);
+  return NS_hypot(aP2.x - aP1.x, aP2.y - aP1.y);
 }
 
 
-static void SplitQuadraticBezier(const gfxPoint *curve,
-                                 gfxPoint *left,
-                                 gfxPoint *right)
+static void
+SplitQuadraticBezier(const gfxPoint* aCurve, gfxPoint* aLeft, gfxPoint* aRight)
 {
-  left[0].x = curve[0].x;
-  left[0].y = curve[0].y;
-  right[2].x = curve[2].x;
-  right[2].y = curve[2].y;
-  left[1].x = (curve[0].x + curve[1].x) / 2;
-  left[1].y = (curve[0].y + curve[1].y) / 2;
-  right[1].x = (curve[1].x + curve[2].x) / 2;
-  right[1].y = (curve[1].y + curve[2].y) / 2;
-  left[2].x = right[0].x = (left[1].x + right[1].x) / 2;
-  left[2].y = right[0].y = (left[1].y + right[1].y) / 2;
+  aLeft[0].x = aCurve[0].x;
+  aLeft[0].y = aCurve[0].y;
+  aRight[2].x = aCurve[2].x;
+  aRight[2].y = aCurve[2].y;
+  aLeft[1].x = (aCurve[0].x + aCurve[1].x) / 2;
+  aLeft[1].y = (aCurve[0].y + aCurve[1].y) / 2;
+  aRight[1].x = (aCurve[1].x + aCurve[2].x) / 2;
+  aRight[1].y = (aCurve[1].y + aCurve[2].y) / 2;
+  aLeft[2].x = aRight[0].x = (aLeft[1].x + aRight[1].x) / 2;
+  aLeft[2].y = aRight[0].y = (aLeft[1].y + aRight[1].y) / 2;
 }
 
-static void SplitCubicBezier(const gfxPoint *curve,
-                             gfxPoint *left,
-                             gfxPoint *right)
+static void
+SplitCubicBezier(const gfxPoint* aCurve, gfxPoint* aLeft, gfxPoint* aRight)
 {
   gfxPoint tmp;
-  tmp.x = (curve[1].x + curve[2].x) / 4;
-  tmp.y = (curve[1].y + curve[2].y) / 4;
-  left[0].x = curve[0].x;
-  left[0].y = curve[0].y;
-  right[3].x = curve[3].x;
-  right[3].y = curve[3].y;
-  left[1].x = (curve[0].x + curve[1].x) / 2;
-  left[1].y = (curve[0].y + curve[1].y) / 2;
-  right[2].x = (curve[2].x + curve[3].x) / 2;
-  right[2].y = (curve[2].y + curve[3].y) / 2;
-  left[2].x = left[1].x / 2 + tmp.x;
-  left[2].y = left[1].y / 2 + tmp.y;
-  right[1].x = right[2].x / 2 + tmp.x;
-  right[1].y = right[2].y / 2 + tmp.y;
-  left[3].x = right[0].x = (left[2].x + right[1].x) / 2;
-  left[3].y = right[0].y = (left[2].y + right[1].y) / 2;
+  tmp.x = (aCurve[1].x + aCurve[2].x) / 4;
+  tmp.y = (aCurve[1].y + aCurve[2].y) / 4;
+  aLeft[0].x = aCurve[0].x;
+  aLeft[0].y = aCurve[0].y;
+  aRight[3].x = aCurve[3].x;
+  aRight[3].y = aCurve[3].y;
+  aLeft[1].x = (aCurve[0].x + aCurve[1].x) / 2;
+  aLeft[1].y = (aCurve[0].y + aCurve[1].y) / 2;
+  aRight[2].x = (aCurve[2].x + aCurve[3].x) / 2;
+  aRight[2].y = (aCurve[2].y + aCurve[3].y) / 2;
+  aLeft[2].x = aLeft[1].x / 2 + tmp.x;
+  aLeft[2].y = aLeft[1].y / 2 + tmp.y;
+  aRight[1].x = aRight[2].x / 2 + tmp.x;
+  aRight[1].y = aRight[2].y / 2 + tmp.y;
+  aLeft[3].x = aRight[0].x = (aLeft[2].x + aRight[1].x) / 2;
+  aLeft[3].y = aRight[0].y = (aLeft[2].y + aRight[1].y) / 2;
 }
 
-static gfxFloat CalcBezLengthHelper(gfxPoint *curve, PRUint32 numPts,
-                                    PRUint32 recursion_count,
-                                    void (*split)(const gfxPoint*, gfxPoint*, gfxPoint*))
+static gfxFloat
+CalcBezLengthHelper(gfxPoint* aCurve, PRUint32 aNumPts,
+                    PRUint32 aRecursionCount,
+                    void (*aSplit)(const gfxPoint*, gfxPoint*, gfxPoint*))
 {
   gfxPoint left[4];
   gfxPoint right[4];
   gfxFloat length = 0, dist;
-  for (PRUint32 i = 0; i < numPts - 1; i++) {
-    length += CalcDistanceBetweenPoints(curve[i], curve[i+1]);
+  for (PRUint32 i = 0; i < aNumPts - 1; i++) {
+    length += CalcDistanceBetweenPoints(aCurve[i], aCurve[i+1]);
   }
-  dist = CalcDistanceBetweenPoints(curve[0], curve[numPts - 1]);
-  if (length - dist > PATH_SEG_LENGTH_TOLERANCE && recursion_count < MAX_RECURSION) {
-    split(curve, left, right);
-    ++recursion_count;
-    return CalcBezLengthHelper(left, numPts, recursion_count, split) +
-           CalcBezLengthHelper(right, numPts, recursion_count, split);
+  dist = CalcDistanceBetweenPoints(aCurve[0], aCurve[aNumPts - 1]);
+  if (length - dist > PATH_SEG_LENGTH_TOLERANCE &&
+      aRecursionCount < MAX_RECURSION) {
+    aSplit(aCurve, left, right);
+    ++aRecursionCount;
+    return CalcBezLengthHelper(left, aNumPts, aRecursionCount, aSplit) +
+           CalcBezLengthHelper(right, aNumPts, aRecursionCount, aSplit);
   }
   return length;
 }
 
 static inline gfxFloat
-CalcLengthOfCubicBezier(const gfxPoint &pos, const gfxPoint &cp1,
-                        const gfxPoint &cp2, const gfxPoint &to)
+CalcLengthOfCubicBezier(const gfxPoint& aPos, const gfxPoint &aCP1,
+                        const gfxPoint& aCP2, const gfxPoint &aTo)
 {
-  gfxPoint curve[4] = { pos, cp1, cp2, to };
+  gfxPoint curve[4] = { aPos, aCP1, aCP2, aTo };
   return CalcBezLengthHelper(curve, 4, 0, SplitCubicBezier);
 }
 
 static inline gfxFloat
-CalcLengthOfQuadraticBezier(const gfxPoint &pos, const gfxPoint &cp,
-                            const gfxPoint &to)
+CalcLengthOfQuadraticBezier(const gfxPoint& aPos, const gfxPoint& aCP,
+                            const gfxPoint& aTo)
 {
-  gfxPoint curve[3] = { pos, cp, to };
+  gfxPoint curve[3] = { aPos, aCP, aTo };
   return CalcBezLengthHelper(curve, 3, 0, SplitQuadraticBezier);
 }
 
 
-static float GetLengthOfClosePath(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseClosePath(const float* aArgs, SVGPathTraversalState& aState)
 {
-  float dist = CalcDistanceBetweenPoints(aState.pos, aState.start);
-  aState.pos = aState.cp1 = aState.cp2 = aState.start;
-  return dist;
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    aState.length += CalcDistanceBetweenPoints(aState.pos, aState.start);
+    aState.cp1 = aState.cp2 = aState.start;
+  }
+  aState.pos = aState.start;
 }
 
-static float GetLengthOfMovetoAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseMovetoAbs(const float* aArgs, SVGPathTraversalState& aState)
 {
-  aState.start = aState.pos = aState.cp1 = aState.cp2 = gfxPoint(aArgs[0], aArgs[1]);
-  return 0.0;
-}
-
-static float GetLengthOfMovetoRel(const float *aArgs, SVGPathTraversalState &aState)
-{
-  // aState.pos must be second from right due to +=
-  aState.start = aState.cp1 = aState.cp2 = aState.pos += gfxPoint(aArgs[0], aArgs[1]);
-  return 0.0;
+  aState.start = aState.pos = gfxPoint(aArgs[0], aArgs[1]);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    // aState.length is unchanged, since move commands don't affect path length.
+    aState.cp1 = aState.cp2 = aState.start;
+  }
 }
 
-static float GetLengthOfLinetoAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseMovetoRel(const float* aArgs, SVGPathTraversalState& aState)
+{
+  aState.start = aState.pos += gfxPoint(aArgs[0], aArgs[1]);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    // aState.length is unchanged, since move commands don't affect path length.
+    aState.cp1 = aState.cp2 = aState.start;
+  }
+}
+
+static void
+TraverseLinetoAbs(const float* aArgs, SVGPathTraversalState& aState)
 {
   gfxPoint to(aArgs[0], aArgs[1]);
-  float dist = CalcDistanceBetweenPoints(aState.pos, to);
-  aState.pos = aState.cp1 = aState.cp2 = to;
-  return dist;
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    aState.length += CalcDistanceBetweenPoints(aState.pos, to);
+    aState.cp1 = aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float GetLengthOfLinetoRel(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseLinetoRel(const float* aArgs, SVGPathTraversalState& aState)
 {
   gfxPoint to = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
-  float dist = CalcDistanceBetweenPoints(aState.pos, to);
-  aState.pos = aState.cp1 = aState.cp2 = to;
-  return dist;
-}
-
-static float
-GetLengthOfLinetoHorizontalAbs(const float *aArgs, SVGPathTraversalState &aState)
-{
-  gfxPoint to(aArgs[0], aState.pos.y);
-  float dist = fabs(to.x - aState.pos.x);
-  aState.pos = aState.cp1 = aState.cp2 = to;
-  return dist;
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    aState.length += CalcDistanceBetweenPoints(aState.pos, to);
+    aState.cp1 = aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfLinetoHorizontalRel(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseLinetoHorizontalAbs(const float* aArgs, SVGPathTraversalState& aState)
 {
-  aState.cp1 = aState.cp2 = aState.pos += gfxPoint(aArgs[0], 0.0);
-  return fabs(aArgs[0]);
+  gfxPoint to(aArgs[0], aState.pos.y);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    aState.length += fabs(to.x - aState.pos.x);
+    aState.cp1 = aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfLinetoVerticalAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseLinetoHorizontalRel(const float* aArgs, SVGPathTraversalState& aState)
+{
+  aState.pos.x += aArgs[0];
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    aState.length += fabs(aArgs[0]);
+    aState.cp1 = aState.cp2 = aState.pos;
+  }
+}
+
+static void
+TraverseLinetoVerticalAbs(const float* aArgs, SVGPathTraversalState& aState)
 {
   gfxPoint to(aState.pos.x, aArgs[0]);
-  float dist = fabs(to.y - aState.pos.y);
-  aState.pos = aState.cp1 = aState.cp2 = to;
-  return dist;
-}
-
-static float
-GetLengthOfLinetoVerticalRel(const float *aArgs, SVGPathTraversalState &aState)
-{
-  aState.cp1 = aState.cp2 = aState.pos += gfxPoint(0.0, aArgs[0]);
-  return fabs(aArgs[0]);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    aState.length += fabs(to.y - aState.pos.y);
+    aState.cp1 = aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float GetLengthOfCurvetoCubicAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseLinetoVerticalRel(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint cp1(aArgs[0], aArgs[1]);
-  gfxPoint cp2(aArgs[2], aArgs[3]);
-  gfxPoint to(aArgs[4], aArgs[5]);
-
-  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
-
-  aState.cp2 = cp2;
-  aState.pos = aState.cp1 = to;
-
-  return dist;
+  aState.pos.y += aArgs[0];
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    aState.length += fabs(aArgs[0]);
+    aState.cp1 = aState.cp2 = aState.pos;
+  }
 }
 
-static float
-GetLengthOfCurvetoCubicSmoothAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseCurvetoCubicAbs(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
-  gfxPoint cp2(aArgs[0], aArgs[1]);
-  gfxPoint to(aArgs[2], aArgs[3]);
+  gfxPoint to(aArgs[4], aArgs[5]);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp1(aArgs[0], aArgs[1]);
+    gfxPoint cp2(aArgs[2], aArgs[3]);
+    aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+    aState.cp2 = cp2;
+    aState.cp1 = to;
+  }
+  aState.pos = to;
+}
 
-  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
-
-  aState.cp2 = cp2;
-  aState.pos = aState.cp1 = to;
-
-  return dist;
+static void
+TraverseCurvetoCubicSmoothAbs(const float* aArgs, SVGPathTraversalState& aState)
+{
+  gfxPoint to(aArgs[2], aArgs[3]);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
+    gfxPoint cp2(aArgs[0], aArgs[1]);
+    aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+    aState.cp2 = cp2;
+    aState.cp1 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfCurvetoCubicRel(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseCurvetoCubicRel(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint cp1 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
-  gfxPoint cp2 = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
-  gfxPoint to  = aState.pos + gfxPoint(aArgs[4], aArgs[5]);
-
-  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
-
-  aState.cp2 = cp2;
-  aState.pos = aState.cp1 = to;
-
-  return dist;
+  gfxPoint to = aState.pos + gfxPoint(aArgs[4], aArgs[5]);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp1 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+    gfxPoint cp2 = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
+    aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+    aState.cp2 = cp2;
+    aState.cp1 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfCurvetoCubicSmoothRel(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseCurvetoCubicSmoothRel(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
-  gfxPoint cp2 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
-  gfxPoint to  = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
-
-  float dist = (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
-
-  aState.cp2 = cp2;
-  aState.pos = aState.cp1 = to;
-
-  return dist;
+  gfxPoint to = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp1 = aState.pos - (aState.cp2 - aState.pos);
+    gfxPoint cp2 = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+    aState.length += (float)CalcLengthOfCubicBezier(aState.pos, cp1, cp2, to);
+    aState.cp2 = cp2;
+    aState.cp1 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfCurvetoQuadraticAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseCurvetoQuadraticAbs(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint cp(aArgs[0], aArgs[1]);
   gfxPoint to(aArgs[2], aArgs[3]);
-
-  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
-
-  aState.cp1 = cp;
-  aState.pos = aState.cp2 = to;
-
-  return dist;
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp(aArgs[0], aArgs[1]);
+    aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+    aState.cp1 = cp;
+    aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfCurvetoQuadraticSmoothAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseCurvetoQuadraticSmoothAbs(const float* aArgs,
+                                  SVGPathTraversalState& aState)
 {
-  gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
   gfxPoint to(aArgs[0], aArgs[1]);
-
-  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
-
-  aState.cp1 = cp;
-  aState.pos = aState.cp2 = to;
-
-  return dist;
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
+    aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+    aState.cp1 = cp;
+    aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfCurvetoQuadraticRel(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseCurvetoQuadraticRel(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint cp = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
   gfxPoint to = aState.pos + gfxPoint(aArgs[2], aArgs[3]);
-
-  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
-
-  aState.cp1 = cp;
-  aState.pos = aState.cp2 = to;
-
-  return dist;
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
+    aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+    aState.cp1 = cp;
+    aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfCurvetoQuadraticSmoothRel(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseCurvetoQuadraticSmoothRel(const float* aArgs,
+                                  SVGPathTraversalState& aState)
 {
-  gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
   gfxPoint to = aState.pos + gfxPoint(aArgs[0], aArgs[1]);
-
-  float dist = (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
-
-  aState.cp1 = cp;
-  aState.pos = aState.cp2 = to;
-
-  return dist;
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    gfxPoint cp = aState.pos - (aState.cp1 - aState.pos);
+    aState.length += (float)CalcLengthOfQuadraticBezier(aState.pos, cp, to);
+    aState.cp1 = cp;
+    aState.cp2 = to;
+  }
+  aState.pos = to;
 }
 
-static float
-GetLengthOfArcAbs(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseArcAbs(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint radii(aArgs[0], aArgs[1]);
   gfxPoint to(aArgs[5], aArgs[6]);
-  gfxPoint bez[4] = { aState.pos, gfxPoint(0,0), gfxPoint(0,0), gfxPoint(0,0) };
-  nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
-                              aArgs[3] != 0, aArgs[4] != 0);
-  float dist = 0;
-  while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3]))
-  {
-    dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
-    bez[0] = bez[3];
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    float dist = 0;
+    gfxPoint radii(aArgs[0], aArgs[1]);
+    gfxPoint bez[4] = { aState.pos, gfxPoint(0, 0),
+                        gfxPoint(0, 0), gfxPoint(0, 0) };
+    nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
+                                aArgs[3] != 0, aArgs[4] != 0);
+    while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3])) {
+      dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
+      bez[0] = bez[3];
+    }
+    aState.length += dist;
+    aState.cp1 = aState.cp2 = to;
   }
-  aState.pos = aState.cp1 = aState.cp2 = to;
-  return dist;
+  aState.pos = to;
 }
 
-static float
-GetLengthOfArcRel(const float *aArgs, SVGPathTraversalState &aState)
+static void
+TraverseArcRel(const float* aArgs, SVGPathTraversalState& aState)
 {
-  gfxPoint radii(aArgs[0], aArgs[1]);
   gfxPoint to = aState.pos + gfxPoint(aArgs[5], aArgs[6]);
-  gfxPoint bez[4] = { aState.pos, gfxPoint(0,0), gfxPoint(0,0), gfxPoint(0,0) };
-  nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
-                              aArgs[3] != 0, aArgs[4] != 0);
-  float dist = 0;
-  while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3]))
-  {
-    dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
-    bez[0] = bez[3];
+  if (aState.ShouldUpdateLengthAndControlPoints()) {
+    float dist = 0;
+    gfxPoint radii(aArgs[0], aArgs[1]);
+    gfxPoint bez[4] = { aState.pos, gfxPoint(0, 0),
+                        gfxPoint(0, 0), gfxPoint(0, 0) };
+    nsSVGArcConverter converter(aState.pos, to, radii, aArgs[2],
+                                aArgs[3] != 0, aArgs[4] != 0);
+    while (converter.GetNextSegment(&bez[1], &bez[2], &bez[3])) {
+      dist += CalcBezLengthHelper(bez, 4, 0, SplitCubicBezier);
+      bez[0] = bez[3];
+    }
+    aState.length += dist;
+    aState.cp1 = aState.cp2 = to;
   }
-  aState.pos = aState.cp1 = aState.cp2 = to;
-  return dist;
+  aState.pos = to;
 }
 
 
-typedef float (*getLengthFunc)(const float*, SVGPathTraversalState&);
-
-/* static */ float
-SVGPathSegUtils::GetLength(const float *seg, SVGPathTraversalState &aState)
-{
-  PRUint32 type = DecodeType(seg[0]);
+typedef void (*TraverseFunc)(const float*, SVGPathTraversalState&);
 
-  static getLengthFunc lengthFuncTable[20] = {
-    nsnull, //  0 == PATHSEG_UNKNOWN
-    GetLengthOfClosePath,
-    GetLengthOfMovetoAbs,
-    GetLengthOfMovetoRel,
-    GetLengthOfLinetoAbs,
-    GetLengthOfLinetoRel,
-    GetLengthOfCurvetoCubicAbs,
-    GetLengthOfCurvetoCubicRel,
-    GetLengthOfCurvetoQuadraticAbs,
-    GetLengthOfCurvetoQuadraticRel,
-    GetLengthOfArcAbs,
-    GetLengthOfArcRel,
-    GetLengthOfLinetoHorizontalAbs,
-    GetLengthOfLinetoHorizontalRel,
-    GetLengthOfLinetoVerticalAbs,
-    GetLengthOfLinetoVerticalRel,
-    GetLengthOfCurvetoCubicSmoothAbs,
-    GetLengthOfCurvetoCubicSmoothRel,
-    GetLengthOfCurvetoQuadraticSmoothAbs,
-    GetLengthOfCurvetoQuadraticSmoothRel
-  };
+static TraverseFunc gTraverseFuncTable[NS_SVG_PATH_SEG_TYPE_COUNT] = {
+  nsnull, //  0 == PATHSEG_UNKNOWN
+  TraverseClosePath,
+  TraverseMovetoAbs,
+  TraverseMovetoRel,
+  TraverseLinetoAbs,
+  TraverseLinetoRel,
+  TraverseCurvetoCubicAbs,
+  TraverseCurvetoCubicRel,
+  TraverseCurvetoQuadraticAbs,
+  TraverseCurvetoQuadraticRel,
+  TraverseArcAbs,
+  TraverseArcRel,
+  TraverseLinetoHorizontalAbs,
+  TraverseLinetoHorizontalRel,
+  TraverseLinetoVerticalAbs,
+  TraverseLinetoVerticalRel,
+  TraverseCurvetoCubicSmoothAbs,
+  TraverseCurvetoCubicSmoothRel,
+  TraverseCurvetoQuadraticSmoothAbs,
+  TraverseCurvetoQuadraticSmoothRel
+};
 
-  NS_ABORT_IF_FALSE(IsValidType(type), "Seg type not recognized");
-
-  NS_ABORT_IF_FALSE(type > 0 && type < NS_ARRAY_LENGTH(lengthFuncTable),
-                    "Seg type not recognized");
-
-  return lengthFuncTable[type](seg + 1, aState);
+/* static */ void
+SVGPathSegUtils::TraversePathSegment(const float* aData,
+                                     SVGPathTraversalState& aState)
+{
+  PR_STATIC_ASSERT(NS_ARRAY_LENGTH(gTraverseFuncTable) ==
+                     NS_SVG_PATH_SEG_TYPE_COUNT);
+  PRUint32 type = DecodeType(aData[0]);
+  gTraverseFuncTable[type](aData + 1, aState);
 }
-
--- a/content/svg/content/src/SVGPathSegUtils.h
+++ b/content/svg/content/src/SVGPathSegUtils.h
@@ -38,45 +38,61 @@
 #define MOZILLA_SVGPATHSEGUTILS_H__
 
 #include "nsIDOMSVGPathSeg.h"
 #include "nsIContent.h"
 #include "nsAString.h"
 #include "nsContentUtils.h"
 #include "gfxPoint.h"
 
-#define NS_SVG_PATH_SEG_MAX_ARGS 7
+#define NS_SVG_PATH_SEG_MAX_ARGS         7
+#define NS_SVG_PATH_SEG_FIRST_VALID_TYPE nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH
+#define NS_SVG_PATH_SEG_LAST_VALID_TYPE  nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
+#define NS_SVG_PATH_SEG_TYPE_COUNT       (NS_SVG_PATH_SEG_LAST_VALID_TYPE + 1)
 
 namespace mozilla {
 
 /**
  * Code that works with path segments can use an instance of this class to
  * store/provide information about the start of the current subpath and the
  * last path segment (if any).
  */
 struct SVGPathTraversalState
 {
+  enum TraversalMode {
+    eUpdateAll,
+    eUpdateOnlyStartAndCurrentPos
+  };
+
   SVGPathTraversalState()
     : start(0.0, 0.0)
     , pos(0.0, 0.0)
     , cp1(0.0, 0.0)
     , cp2(0.0, 0.0)
+    , length(0.0)
+    , mode(eUpdateAll)
   {}
 
+  PRBool ShouldUpdateLengthAndControlPoints() { return mode == eUpdateAll; }
+
   gfxPoint start; // start point of current sub path (reset each moveto)
 
   gfxPoint pos;   // current position (end point of previous segment)
 
   gfxPoint cp1;   // quadratic control point - if the previous segment was a
                   // quadratic bezier curve then this is set to the absolute
                   // position of its control point, otherwise its set to pos
 
   gfxPoint cp2;   // cubic control point - if the previous segment was a cubic
                   // bezier curve then this is set to the absolute position of
                   // its second control point, otherwise it's set to pos
+
+  float length;   // accumulated path length
+
+  TraversalMode mode;  // indicates what to track while traversing a path
 };
 
 
 /**
  * This class is just a collection of static methods - it doesn't have any data
  * members, and it's not possible to create instances of this class. This class
  * exists purely as a convenient place to gather together a bunch of methods
  * related to manipulating and answering questions about path segments.
@@ -139,16 +155,17 @@ public:
       PRUnichar('h'),  // 13 == PATHSEG_LINETO_HORIZONTAL_REL
       PRUnichar('V'),  // 14 == PATHSEG_LINETO_VERTICAL_ABS
       PRUnichar('v'),  // 15 == PATHSEG_LINETO_VERTICAL_REL
       PRUnichar('S'),  // 16 == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS
       PRUnichar('s'),  // 17 == PATHSEG_CURVETO_CUBIC_SMOOTH_REL
       PRUnichar('T'),  // 18 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS
       PRUnichar('t')   // 19 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
     };
+    PR_STATIC_ASSERT(NS_ARRAY_LENGTH(table) == NS_SVG_PATH_SEG_TYPE_COUNT);
 
     return table[aType];
   }
 
   static PRUint32 ArgCountForType(PRUint32 aType) {
     NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
 
     static const PRUint8 table[] = {
@@ -168,50 +185,101 @@ public:
       1,  // 13 == PATHSEG_LINETO_HORIZONTAL_REL
       1,  // 14 == PATHSEG_LINETO_VERTICAL_ABS
       1,  // 15 == PATHSEG_LINETO_VERTICAL_REL
       4,  // 16 == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS
       4,  // 17 == PATHSEG_CURVETO_CUBIC_SMOOTH_REL
       2,  // 18 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS
       2   // 19 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
     };
+    PR_STATIC_ASSERT(NS_ARRAY_LENGTH(table) == NS_SVG_PATH_SEG_TYPE_COUNT);
 
     return table[aType];
   }
 
   /**
    * Convenience so that callers can pass a float containing an encoded type
    * and have it decoded implicitly.
    */
   static PRUint32 ArgCountForType(float aType) {
     return ArgCountForType(DecodeType(aType));
   }
 
-  static inline PRBool IsValidType(PRUint32 aType) {
-    return aType >= nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH &&
-           aType <= nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
+  static PRBool IsValidType(PRUint32 aType) {
+    return aType >= NS_SVG_PATH_SEG_FIRST_VALID_TYPE &&
+           aType <= NS_SVG_PATH_SEG_LAST_VALID_TYPE;
   }
 
-  static inline PRBool IsCubicType(PRUint32 aType) {
+  static PRBool IsCubicType(PRUint32 aType) {
     return aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL ||
            aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS ||
            aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
            aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
   }
 
-  static inline PRBool IsQuadraticType(PRUint32 aType) {
+  static PRBool IsQuadraticType(PRUint32 aType) {
     return aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL ||
            aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS ||
            aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
            aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
   }
 
+  static PRBool IsArcType(PRUint32 aType) {
+    return aType == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS || 
+           aType == nsIDOMSVGPathSeg::PATHSEG_ARC_REL;
+  }
+
+  static PRBool IsRelativeOrAbsoluteType(PRUint32 aType) {
+    NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
+
+    // When adding a new path segment type, ensure that the returned condition
+    // below is still correct.
+    PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
+                       nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
+
+    return aType >= nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS;
+  }
+
+  static PRBool IsRelativeType(PRUint32 aType) {
+    NS_ABORT_IF_FALSE
+      (IsRelativeOrAbsoluteType(aType),
+       "IsRelativeType called with segment type that does not come in relative and absolute forms");
+
+    // When adding a new path segment type, ensure that the returned condition
+    // below is still correct.
+    PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
+                       nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
+
+    return aType & 1;
+  }
+
+  static PRUint32 RelativeVersionOfType(PRUint32 aType) {
+    NS_ABORT_IF_FALSE
+      (IsRelativeOrAbsoluteType(aType),
+       "RelativeVersionOfType called with segment type that does not come in relative and absolute forms");
+
+    // When adding a new path segment type, ensure that the returned condition
+    // below is still correct.
+    PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
+                       nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
+
+    return aType | 1;
+  }
+
+  static PRUint32 SameTypeModuloRelativeness(PRUint32 aType1, PRUint32 aType2) {
+    if (!IsRelativeOrAbsoluteType(aType1)) {
+      return aType1 == aType2;
+    }
+
+    return RelativeVersionOfType(aType1) == RelativeVersionOfType(aType2);
+  }
+
   /**
-   * Returns the user unit length of tracing along the path segment.
+   * Traverse the given path segment and update the SVGPathTraversalState
+   * object.
    */
-  static float GetLength(const float *aSeg, SVGPathTraversalState &aState);
-
-  static void ToString(const float *aSeg, nsAString& aValue);
+  static void TraversePathSegment(const float* aData,
+                                  SVGPathTraversalState& aState);
 };
 
 } // namespace mozilla
 
 #endif // MOZILLA_SVGPATHSEGUTILS_H__
--- a/content/svg/content/src/nsSVGAnimationElement.cpp
+++ b/content/svg/content/src/nsSVGAnimationElement.cpp
@@ -142,17 +142,18 @@ nsSVGAnimationElement::GetTargetElementC
   if (HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)) {
     return mHrefTarget.get();
   }
   NS_ABORT_IF_FALSE(!mHrefTarget.get(),
                     "We shouldn't have an xlink:href target "
                     "if we don't have an xlink:href attribute");
 
   // No "xlink:href" attribute --> I should target my parent.
-  return nsSVGUtils::GetParentElement(this);
+  nsIContent* parent = GetFlattenedTreeParent();
+  return parent && parent->IsElement() ? parent->AsElement() : nsnull;
 }
 
 PRBool
 nsSVGAnimationElement::GetTargetAttributeName(PRInt32 *aNamespaceID,
                                               nsIAtom **aLocalName) const
 {
   const nsAttrValue* nameAttr
     = mAttrsAndChildren.GetAttr(nsGkAtoms::attributeName);
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -234,17 +234,17 @@ nsSVGElement::BindToTree(nsIDocument* aD
                          nsIContent* aBindingParent,
                          PRBool aCompileEventHandlers)
 {
   nsresult rv = nsSVGElementBase::BindToTree(aDocument, aParent,
                                              aBindingParent,
                                              aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
+  if (!MayHaveStyle()) {
     return NS_OK;
   }
   const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
 
   if (oldVal && oldVal->Type() == nsAttrValue::eCSSStyleRule) {
     // we need to force a reparse because the baseURI of the document
     // may have changed, and in particular because we may be clones of
     // XBL anonymous content now being bound to the document we should
@@ -283,17 +283,17 @@ nsSVGElement::AfterSetAttr(PRInt32 aName
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aNamespaceID == kNameSpaceID_None &&
       (aName == nsGkAtoms::requiredFeatures ||
        aName == nsGkAtoms::requiredExtensions ||
        aName == nsGkAtoms::systemLanguage)) {
 
-    nsIContent* parent = nsSVGUtils::GetParentElement(this);
+    nsIContent* parent = GetFlattenedTreeParent();
   
     if (parent &&
         parent->NodeInfo()->Equals(nsGkAtoms::svgSwitch, kNameSpaceID_SVG)) {
       static_cast<nsSVGSwitchElement*>(parent)->MaybeInvalidate();
     }
   }
 
   return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aNotify);
@@ -1406,27 +1406,27 @@ nsIAtom* nsSVGElement::GetEventNameForAt
 #endif // MOZ_SMIL
 
   return aAttr;
 }
 
 nsSVGSVGElement *
 nsSVGElement::GetCtx()
 {
-  dom::Element* ancestor = nsSVGUtils::GetParentElement(this);
+  nsIContent* ancestor = GetFlattenedTreeParent();
 
   while (ancestor && ancestor->GetNameSpaceID() == kNameSpaceID_SVG) {
     nsIAtom* tag = ancestor->Tag();
     if (tag == nsGkAtoms::foreignObject) {
       return nsnull;
     }
     if (tag == nsGkAtoms::svg) {
       return static_cast<nsSVGSVGElement*>(ancestor);
     }
-    ancestor = nsSVGUtils::GetParentElement(ancestor);
+    ancestor = ancestor->GetFlattenedTreeParent();
   }
 
   // we don't have an ancestor <svg> element...
   return nsnull;
 }
 
 /* virtual */ gfxMatrix
 nsSVGElement::PrependLocalTransformTo(const gfxMatrix &aMatrix)
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -75,17 +75,17 @@ class SVGAnimatedNumberList;
 class SVGNumberList;
 class SVGAnimatedLengthList;
 class SVGUserUnitList;
 class SVGAnimatedPointList;
 class SVGAnimatedPathSegList;
 class SVGAnimatedPreserveAspectRatio;
 }
 
-typedef nsStyledElement nsSVGElementBase;
+typedef nsStyledElementNotElementCSSInlineStyle nsSVGElementBase;
 
 class nsSVGElement : public nsSVGElementBase,    // nsIContent
                      public nsISVGValueObserver  // :nsISupportsWeakReference
 {
 protected:
   nsSVGElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   nsresult Init();
   virtual ~nsSVGElement();
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -314,19 +314,19 @@ inline static void DidAnimateAttr(Elemen
   if (frame) {
     nsSVGEffects::InvalidateRenderingObservers(frame);
   }
 }
 
 inline static void DidAnimateAttrViaParent(Element *aFilterPrimitive) {
   // No frame, use parent's
   NS_ASSERTION(!aFilterPrimitive->GetPrimaryFrame(), "Not expecting a frame");
-  Element *parent = nsSVGUtils::GetParentElement(aFilterPrimitive);
-  if (parent) {
-    DidAnimateAttr(parent);
+  nsIContent *parent = aFilterPrimitive->GetFlattenedTreeParent();
+  if (parent && parent->IsElement()) {
+    DidAnimateAttr(parent->AsElement());
   }
 }
 
 void
 nsSVGFE::DidAnimateLength(PRUint8 aAttrEnum)
 {
   DidAnimateAttr(this);
 }
--- a/content/svg/content/src/nsSVGSVGElement.h
+++ b/content/svg/content/src/nsSVGSVGElement.h
@@ -267,17 +267,17 @@ protected:
     return IsInDoc() && !GetParent();
   }
 
   /**
    * Returns true if this is an SVG <svg> element that is the child of
    * another non-foreignObject SVG element.
    */
   PRBool IsInner() {
-    const mozilla::dom::Element *parent = nsSVGUtils::GetParentElement(this);
+    const nsIContent *parent = GetFlattenedTreeParent();
     return parent && parent->GetNameSpaceID() == kNameSpaceID_SVG &&
            parent->Tag() != nsGkAtoms::foreignObject;
   }
 
 #ifdef MOZ_SMIL
   /* 
    * While binding to the tree we need to determine if we will be the outermost
    * <svg> element _before_ the children are bound (as they want to know what
--- a/content/svg/content/src/nsSVGTransformList.h
+++ b/content/svg/content/src/nsSVGTransformList.h
@@ -73,16 +73,17 @@ public:
   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
                                      modificationType aModType);
   
   // nsISupportsWeakReference
   // implementation inherited from nsSupportsWeakReference
 
   
   // other methods:
+  nsIDOMSVGTransform* GetItemWithoutAddRef(PRInt32 index);
   nsIDOMSVGTransform* ElementAt(PRInt32 index);
   PRBool AppendElement(nsIDOMSVGTransform* aElement);
   static already_AddRefed<nsIDOMSVGMatrix>
   GetConsolidationMatrix(nsIDOMSVGTransformList *transforms);
   
 protected:
   PRInt32 ParseParameterList(char *paramstr, float *vars, PRInt32 nvars);
   void ReleaseTransforms();
--- a/content/svg/content/test/Makefile.in
+++ b/content/svg/content/test/Makefile.in
@@ -44,57 +44,59 @@ relativesrcdir  = content/svg/content/te
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 # Disabled:
 #		bbox-helper.svg \
 #		test_length.xhtml \
 
 _TEST_FILES = \
+		test_a_href_01.xhtml \
+		test_a_href_02.xhtml \
+		a_href_destination.svg \
+		a_href_helper_01.svg \
+		a_href_helper_02_03.svg \
+		a_href_helper_04.svg \
 		test_animLengthObjectIdentity.xhtml \
 		test_animLengthReadonly.xhtml \
 		test_animLengthRelativeUnits.xhtml \
 		test_animLengthUnits.xhtml \
 		test_bbox.xhtml \
 		bbox-helper.svg \
 		bounds-helper.svg \
 		test_dataTypes.html \
 		dataTypes-helper.svg \
 		getCTM-helper.svg \
 		test_getCTM.html \
 		test_getSubStringLength.xhtml \
 		getSubStringLength-helper.svg \
 		test_isSupported.xhtml \
 		test_nonAnimStrings.xhtml \
+		test_pathAnimInterpolation.xhtml \
 		test_pathSeg.xhtml \
 		test_pointer-events.xhtml \
 		test_pointer-events-2.xhtml \
 		test_scientific.html \
 		scientific-helper.svg \
 		test_SVGAnimatedImageSMILDisabled.html \
 		animated-svg-image-helper.html \
 		animated-svg-image-helper.svg \
 		test_SVGLengthList.xhtml \
 		test_SVGLengthList-2.xhtml \
 		test_SVGPathSegList.xhtml \
 		test_SVGStyleElement.xhtml \
 		test_SVGxxxList.xhtml \
+		test_SVGxxxListIndexing.xhtml \
 		test_switch.xhtml \
 		switch-helper.svg \
 		test_text.html \
 		text-helper.svg \
 		test_transform.xhtml \
 		test_valueAsString.xhtml \
 		test_valueLeaks.xhtml \
 		viewport-helper.svg \
 		test_viewport.html \
 		zoom-helper.svg \
 		test_zoom.xhtml \
-		test_a_href_01.xhtml \
-		test_a_href_02.xhtml \
-		a_href_destination.svg \
-		a_href_helper_01.svg \
-		a_href_helper_02_03.svg \
-		a_href_helper_04.svg \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/svg/content/test/test_SVGxxxListIndexing.xhtml
@@ -0,0 +1,83 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=631437
+-->
+<head>
+  <title>Tests the array indexing and .length on SVGXXXList objects</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=631437">Mozilla Bug 631437</a>
+<svg xmlns="http://www.w3.org/2000/svg" id="svg">
+  <text id="text" x="10 20 30" rotate="40 50 60">abcde</text>
+  <path id="path" d="M0,0 L100,100"/>
+  <polygon id="poly" points="50,50 70,70 90,50"/>
+</svg>
+<script type="text/javascript;version=1.8"><![CDATA[
+var text = document.getElementById("text"),
+    path = document.getElementById("path"),
+    poly = document.getElementById("poly");
+
+function CheckList(aListObject, aExpectedListLength, aListDescription)
+{
+  is(aListObject.numberOfItems, aExpectedListLength, aListDescription + ".numberOfItems");
+  is(aListObject.numberOfItems, aExpectedListLength, aListDescription + ".length");
+  for (let i = 0; i < aListObject.length; i++) {
+    let item = aListObject.getItem(i);
+    ok(aListObject[i] === item, aListDescription + "[" + i + "]");
+  }
+  ok(aListObject[aListObject.length] === void 0, aListDescription + "[outOfBounds]");
+}
+
+var tests = [
+  { element: text,
+    attribute: "x",
+    listProperty: "x.baseVal",
+    type: "SVGLengthList",
+    subtests: [ { values: null, length: 3 },
+                { values: "40", length: 1 },
+                { values: "1em 2em 3em 4em 5em", length: 5 } ] },
+  { element: text,
+    attribute: "rotate",
+    listProperty: "rotate.baseVal",
+    type: "SVGNumberList",
+    subtests: [ { values: null, length: 3 },
+                { values: "10", length: 1 },
+                { values: "1 2 3 4 5", length: 5 } ] },
+  { element: path,
+    attribute: "d",
+    listProperty: "pathSegList",
+    type: "SVGPathSegList",
+    subtests: [ { values: null, length: 2 },
+                { values: "M50,50", length: 1 },
+                { values: "M0,0 h10 v20 h30 v40", length: 5 } ] },
+  { element: poly,
+    attribute: "points",
+    listProperty: "animatedPoints",
+    type: "SVGPointList",
+    subtests: [ { values: null, length: 3 },
+                { values: "100,100", length: 1 },
+                { values: "0,0 10,10 20,0 30,10 40,0", length: 5 } ] }
+];
+
+for each (let test in tests) {
+  let list = test.element;
+  for each (let property in test.listProperty.split(".")) {
+    list = list[property];
+  }
+
+  for each (let subtest in test.subtests) {
+    if (subtest.values) {
+      test.element.setAttribute(test.attribute, subtest.values);
+    }
+
+    CheckList(list, subtest.length,
+              test.type + ": " + test.element.localName + "." +
+                test.listProperty);
+  }
+}
+]]></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/svg/content/test/test_pathAnimInterpolation.xhtml
@@ -0,0 +1,345 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=619498
+-->
+<head>
+  <title>Test interpolation between different path segment types</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=619498">Mozilla Bug 619498</a>
+<svg xmlns="http://www.w3.org/2000/svg" id="svg" visibility="hidden"
+     onload="this.pauseAnimations()"/>
+<script type="application/javascript;version=1.8"><![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var gSVG = document.getElementById("svg");
+
+// Array of all subtests to run.  This is populated by addTest.
+var gTests = [];
+
+// Array of all path segment types.
+var gTypes = "zMmLlCcQqAaHhVvSsTt".split("");
+
+// Property names on the SVGPathSeg objects for the given segment type, in the
+// order that they would appear in a path data string.
+var gArgumentNames = {
+  Z: [],
+  M: ['x', 'y'],
+  L: ['x', 'y'],
+  C: ['x1', 'y1', 'x2', 'y2', 'x', 'y'],
+  Q: ['x1', 'y1', 'x', 'y'],
+  A: ['r1', 'r2', 'angle', 'largeArcFlag', 'sweepFlag', 'x', 'y'],
+  H: ['x'],
+  V: ['y'],
+  S: ['x2', 'y2', 'x', 'y'],
+  T: ['x', 'y']
+};
+
+// All of these prefixes leave the current point at 100,100.  Some of them
+// affect the implied control point if followed by a smooth quadratic or
+// cubic segment, but no valid interpolations depend on those control points.
+var gPrefixes = [
+  [1, "M100,100"],
+  [2, "M50,50 M100,100"],
+  [2, "M50,50 m50,50"],
+  [2, "M50,50 L100,100"],
+  [2, "M50,50 l50,50"],
+  [3, "M50,50 H100 V100"],
+  [3, "M50,50 h50 V100"],
+  [3, "M50,50 H100 v50"],
+  [2, "M50,50 A10,10,10,0,0,100,100"],
+  [2, "M50,50 a10,10,10,0,0,50,50"],
+  [4, "M50,50 l50,50 z m50,50"],
+
+  // These leave the quadratic implied control point at 125,125.
+  [2, "M50,50 Q75,75,100,100"],
+  [2, "M50,50 q25,25,50,50"],
+  [2, "M75,75 T100,100"],
+  [2, "M75,75 t25,25"],
+  [3, "M50,50 T62.5,62.5 t37.5,37.5"],
+  [3, "M50,50 T62.5,62.5 T100,100"],
+  [3, "M50,50 t12.5,12.5 t37.5,37.5"],
+  [3, "M50,50 t12.5,12.5 T100,100"],
+  [3, "M50,50 Q50,50,62.5,62.5 t37.5,37.5"],
+  [3, "M50,50 Q50,50,62.5,62.5 T100,100"],
+  [3, "M50,50 q0,0,12.5,12.5 t37.5,37.5"],
+  [3, "M50,50 q0,0,12.5,12.5 T100,100"],
+
+  // These leave the cubic implied control point at 125,125.
+  [2, "M50,50 C10,10,75,75,100,100"],
+  [2, "M50,50 c10,10,25,25,50,50"],
+  [2, "M50,50 S75,75,100,100"],
+  [2, "M50,50 s25,25,50,50"],
+  [3, "M50,50 S10,10,75,75 S75,75,100,100"],
+  [3, "M50,50 S10,10,75,75 s0,0,25,25"],
+  [3, "M50,50 s10,10,25,25 S75,75,100,100"],
+  [3, "M50,50 s10,10,25,25 s0,0,25,25"],
+  [3, "M50,50 C10,10,20,20,75,75 S75,75,100,100"],
+  [3, "M50,50 C10,10,20,20,75,75 s0,0,25,25"],
+  [3, "M50,50 c10,10,20,20,25,25 S75,75,100,100"],
+  [3, "M50,50 c10,10,20,20,25,25 s0,0,25,25"]
+];
+
+// These are all of the suffixes whose result is not dependent on whether the
+// preceding segment types are quadratic or cubic types.  Each entry is:
+//
+//   "<fromType><toType>": [fromArguments,
+//                          toArguments,
+//                          expectedArguments,
+//                          expectedArgumentsAdditive]
+//
+// As an example:
+//
+//   "Mm": [[10, 20], [30, 40], [-30, -20], [-120, -100]]
+//
+// This will testing interpolating between "M10,20" and "m30,40". All of the
+// these tests assume that the current point is left at 100,100.  So the above
+// entry represents two kinds of tests, one where additive and one not:
+//
+//   <path d="... M10,20">
+//     <animate attributeName="d" from="... M10,20" to="... m30,40"/>
+//   </path>
+//
+// and
+//
+//   <path d="... M10,20">
+//     <animate attributeName="d" from="... M10,20" to="... m30,40"
+//              additive="sum"/>
+//   </path>
+//
+// where the "..." is some prefix that leaves the current point at 100,100.
+// Each of the suffixes here in gSuffixes will be paired with each of the
+// prefixes in gPrefixes, all of which leave the current point at 100,100.
+// (Thus the above two tests for interpolating between "M" and "m" will be
+// performed many times, with different preceding commands.)
+//
+// The expected result of the non-additive test is "m-30,-20".  Since the
+// animation is from an absolute moveto to a relative moveto, we first
+// convert the "M10,20" into its relative form, which is "m-90,-80" due to the
+// current point being 100,100.  Half way through the animation between
+// "m-90,-80" and "m30,40" is thus "m-30,-20".
+// 
+// The expected result of the additive test is "m-120,-100".  We take the
+// halfway value of the animation, "m-30,-20" and add it on to the underlying
+// value.  Since the underlying value "M10,20" is an absolute moveto, we first
+// convert it to relative, "m-90,-80", and then add the "m-30,-20" to it,
+// giving us the result "m-120,-100".
+var gSuffixes = {
+  // Same path segment type, no conversion required.
+  MM: [[10, 20], [30, 40], [20, 30], [30, 50]],
+  mm: [[10, 20], [30, 40], [20, 30], [30, 50]],
+  LL: [[10, 20], [30, 40], [20, 30], [30, 50]],
+  ll: [[10, 20], [30, 40], [20, 30], [30, 50]],
+  CC: [[10, 20, 30, 40, 50, 60], [70, 80, 90, 100, 110, 120],
+       [40, 50, 60, 70, 80, 90], [50, 70, 90, 110, 130, 150]],
+  cc: [[10, 20, 30, 40, 50, 60], [70, 80, 90, 100, 110, 120],
+       [40, 50, 60, 70, 80, 90], [50, 70, 90, 110, 130, 150]],
+  QQ: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]],
+  qq: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]],
+  AA: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100],
+       [35, 45, 55, 0, 0, 65, 75], [45, 65, 85, 0, 0, 105, 125]],
+  aa: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100],
+       [35, 45, 55, 0, 0, 65, 75], [45, 65, 85, 0, 0, 105, 125]],
+  HH: [[10], [20], [15], [25]],
+  hh: [[10], [20], [15], [25]],
+  VV: [[10], [20], [15], [25]],
+  vv: [[10], [20], [15], [25]],
+  SS: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]],
+  ss: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]],
+  TT: [[10, 20], [30, 40], [20, 30], [30, 50]],
+  tt: [[10, 20], [30, 40], [20, 30], [30, 50]],
+
+  // Relative <-> absolute conversion.
+  Mm: [[10, 20], [30, 40], [-30, -20], [-120, -100]],
+  mM: [[10, 20], [30, 40], [70, 80], [180, 200]],
+  Ll: [[10, 20], [30, 40], [-30, -20], [-120, -100]],
+  lL: [[10, 20], [30, 40], [70, 80], [180, 200]],
+  Cc: [[10, 20, 30, 40, 50, 60], [70, 80, 90, 100, 110, 120],
+       [-10, 0, 10, 20, 30, 40], [-100, -80, -60, -40, -20, 0]],
+  cC: [[10, 20, 30, 40, 50, 60], [70, 80, 90, 100, 110, 120],
+       [90, 100, 110, 120, 130, 140], [200, 220, 240, 260, 280, 300]],
+  Qq: [[10, 20, 30, 40], [50, 60, 70, 80],
+       [-20, -10, 0, 10], [-110, -90, -70, -50]],
+  qQ: [[10, 20, 30, 40], [50, 60, 70, 80],
+       [80, 90, 100, 110], [190, 210, 230, 250]],
+  Aa: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100],
+       [35, 45, 55, 0, 0, 15, 25], [45, 65, 85, 0, 0, -45, -25]],
+  aA: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100],
+       [35, 45, 55, 0, 0, 115, 125], [45, 65, 85, 0, 0, 255, 275]],
+  Hh: [[10], [20], [-35], [-125]],
+  hH: [[10], [20], [65], [175]],
+  Vv: [[10], [20], [-35], [-125]],
+  vV: [[10], [20], [65], [175]],
+  Tt: [[10, 20], [30, 40], [-30,-20], [-120, -100]],
+  tT: [[10, 20], [30, 40], [70, 80], [180, 200]],
+  Ss: [[10, 20, 30, 40], [50, 60, 70, 80],
+       [-20, -10, 0, 10], [-110, -90, -70, -50]],
+  sS: [[10, 20, 30, 40], [50, 60, 70, 80],
+       [80, 90, 100, 110], [190, 210, 230, 250]]
+};
+
+// Returns an array of property names that exist on an SVGPathSeg object
+// corresponding to the given segment type, in the order that they would
+// be present in a path data string.
+function argumentNames(aType)
+{
+  return gArgumentNames[aType.toUpperCase()];
+}
+
+// Creates and returns a new element and sets some attributes on it.
+function newElement(aNamespaceURI, aLocalName, aAttributes)
+{
+  var e = document.createElementNS(aNamespaceURI, aLocalName);
+  if (aAttributes) {
+    for (let [name, value] in Iterator(aAttributes)) {
+      e.setAttribute(name, value);
+    }
+  }
+  return e;
+}
+
+// Creates and returns a new SVG element and sets some attributes on it.
+function newSVGElement(aLocalName, aAttributes)
+{
+  return newElement("http://www.w3.org/2000/svg", aLocalName, aAttributes);
+}
+
+// Creates a subtest and adds it to the document.
+//
+// * aPrefixLength/aPrefix              the prefix to use
+// * aFromType/aFromArguments           the segment to interpolate from
+// * aToType/aToArguments               the segment to interpolate to
+// * aExpectedType/aExpectedArguments   the expected result of the interpolated
+//                                        segment half way through the animation
+//                                        duration
+// * aAdditive                          whether the subtest is for an additive
+//                                        animation
+function addTest(aPrefixLength, aPrefix, aFromType, aFromArguments,
+                 aToType, aToArguments, aExpectedType, aExpectedArguments,
+                 aAdditive)
+{
+  var fromPath = aPrefix + aFromType + aFromArguments,
+      toPath = aPrefix + aToType + aToArguments;
+
+  var path = newSVGElement("path", { d: fromPath });
+  var animate =
+    newSVGElement("animate", { attributeName: "d",
+                               from: fromPath,
+			       to: toPath,
+			       dur: "8s",
+			       additive: aAdditive ? "sum" : "replace" });
+  path.appendChild(animate);
+  gSVG.appendChild(path);
+
+  gTests.push({ element: path,
+                prefixLength: aPrefixLength,
+                from: fromPath,
+                to: toPath,
+                toType: aToType,
+                expectedType: aExpectedType,
+                expected: aExpectedArguments,
+                usesAddition: aAdditive });
+}
+
+// Generates an array of path segment arguments for the given type.  aOffset
+// is a number to add on to all non-Boolean segment arguments.
+function generatePathSegmentArguments(aType, aOffset)
+{
+  var args = new Array(argumentNames(aType).length);
+  for (let i = 0; i < args.length; i++) {
+    args[i] = i * 10 + aOffset;
+  }
+  if (aType == "A" || aType == "a") {
+    args[3] = 0;
+    args[4] = 0;
+  }
+  return args;
+}
+
+// Returns whether interpolating between the two given types is valid.
+function isValidInterpolation(aFromType, aToType)
+{
+  return aFromType.toUpperCase() == aToType.toUpperCase();
+}
+
+// Runs the test.
+function run()
+{
+  for each (let additive in [false, true]) {
+    let indexOfExpectedArguments = additive ? 3 : 2;
+
+    // Add subtests for each combination of prefix and suffix, and additive
+    // or not.
+    for (let [typePair, suffixEntry] in Iterator(gSuffixes)) {
+      let fromType = typePair[0],
+          toType = typePair[1],
+          fromArguments = suffixEntry[0],
+          toArguments = suffixEntry[1],
+          expectedArguments = suffixEntry[indexOfExpectedArguments];
+
+      for each (let prefixEntry in gPrefixes) {
+        let [prefixLength, prefix] = prefixEntry;
+        addTest(prefixLength, prefix, fromType, fromArguments,
+	        toType, toArguments, toType, expectedArguments, additive);
+      }
+    }
+
+    // Test that differences in arc flag parameters cause the
+    // interpolation/addition not to occur.
+    addTest(1, "M100,100",
+            "A", [10, 20, 30, 0, 0, 40, 50],
+            "a", [60, 70, 80, 0, 1, 90, 100],
+	    "a", [60, 70, 80, 0, 1, 90, 100], additive);
+    addTest(1, "M100,100",
+            "A", [10, 20, 30, 0, 0, 40, 50],
+            "a", [60, 70, 80, 1, 0, 90, 100],
+	    "a", [60, 70, 80, 1, 0, 90, 100], additive);
+
+    // Test all pairs of segment types that cannot be interpolated between.
+    for each (let fromType in gTypes) {
+      let fromArguments = generatePathSegmentArguments(fromType, 0);
+      for each (let toType in gTypes) {
+        if (!isValidInterpolation(fromType, toType)) {
+          let toArguments = generatePathSegmentArguments(toType, 1000);
+          addTest(1, "M100,100", fromType, fromArguments,
+	          toType, toArguments, toType, toArguments, additive);
+        }
+      }
+    }
+  }
+
+  // Move the document time to half way through the animations.
+  gSVG.setCurrentTime(4);
+
+  // Inspect the results of each subtest.
+  for each (let test in gTests) {
+    let list = test.element.animatedPathSegList;
+    is(list.numberOfItems, test.prefixLength + 1,
+       "Length of animatedPathSegList for interpolation " +
+         (test.usesAddition ? "with addition " : "") +
+	 " from " + test.from + " to " + test.to);
+
+    let seg = list.getItem(list.numberOfItems - 1);
+    let propertyNames = argumentNames(test.expectedType);
+
+    let actual = [];
+    for (let i = 0; i < test.expected.length; i++) {
+      actual.push(+seg[propertyNames[i]]);
+    }
+
+    is(seg.pathSegTypeAsLetter + actual, test.expectedType + test.expected,
+       "Path segment for interpolation " +
+         (test.usesAddition ? "with addition " : "") +
+         " from " + test.from + " to " + test.to);
+  }
+
+  SimpleTest.finish();
+}
+
+window.addEventListener("load", run, false);
+]]></script>
+</body>
+</html>
--- a/content/xml/content/src/nsXMLElement.cpp
+++ b/content/xml/content/src/nsXMLElement.cpp
@@ -84,60 +84,60 @@ nsXMLElement::UnsetAttr(PRInt32 aNameSpa
   nsMutationGuard guard;
 
   nsresult rv = nsGenericElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
 
   if (isId &&
       (!guard.Mutated(0) ||
        !mNodeInfo->GetIDAttributeAtom() ||
        !HasAttr(kNameSpaceID_None, GetIDAttributeName()))) {
-    UnsetFlags(NODE_HAS_ID);
+    ClearHasID();
   }
   
   return rv;
 }
 
 nsIAtom *
 nsXMLElement::GetIDAttributeName() const
 {
   return mNodeInfo->GetIDAttributeAtom();
 }
 
 nsIAtom*
 nsXMLElement::DoGetID() const
 {
-  NS_ASSERTION(HasFlag(NODE_HAS_ID), "Unexpected call");
+  NS_ASSERTION(HasID(), "Unexpected call");
 
   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(GetIDAttributeName());
   return attrVal ? attrVal->GetAtomValue() : nsnull;
 }
 
 void
 nsXMLElement::NodeInfoChanged(nsINodeInfo* aOldNodeInfo)
 {
   NS_ASSERTION(!IsInDoc() ||
                aOldNodeInfo->GetDocument() == mNodeInfo->GetDocument(),
                "Can only change document if we're not inside one");
   nsIDocument* doc = GetCurrentDoc();
 
-  if (HasFlag(NODE_HAS_ID) && doc) {
+  if (HasID() && doc) {
     const nsAttrValue* attrVal =
       mAttrsAndChildren.GetAttr(aOldNodeInfo->GetIDAttributeAtom());
     if (attrVal) {
       doc->RemoveFromIdTable(this, attrVal->GetAtomValue());
     }
   }
   
-  UnsetFlags(NODE_HAS_ID);
+  ClearHasID();
 
   nsIAtom* IDName = GetIDAttributeName();
   if (IDName) {
     const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(IDName);
     if (attrVal) {
-      SetFlags(NODE_HAS_ID);
+      SetHasID();
       if (attrVal->Type() == nsAttrValue::eString) {
         nsString idVal(attrVal->GetStringValue());
 
         // Create an atom from the value and set it into the attribute list. 
         const_cast<nsAttrValue*>(attrVal)->ParseAtom(idVal);
       }
       NS_ASSERTION(attrVal->Type() == nsAttrValue::eAtom,
                    "Should be atom by now");
@@ -155,21 +155,21 @@ nsXMLElement::ParseAttribute(PRInt32 aNa
                              nsAttrValue& aResult)
 {
   if (aAttribute == GetIDAttributeName() &&
       aNamespaceID == kNameSpaceID_None) {
     // Store id as an atom.  id="" means that the element has no id,
     // not that it has an emptystring as the id.
     RemoveFromIdTable();
     if (aValue.IsEmpty()) {
-      UnsetFlags(NODE_HAS_ID);
+      ClearHasID();
       return PR_FALSE;
     }
     aResult.ParseAtom(aValue);
-    SetFlags(NODE_HAS_ID);
+    SetHasID();
     AddToIdTable(aResult.GetAtomValue());
     return PR_TRUE;
   }
 
   return PR_FALSE;
 }
 
 nsresult
@@ -177,17 +177,17 @@ nsXMLElement::BindToTree(nsIDocument* aD
                          nsIContent* aBindingParent,
                          PRBool aCompileEventHandlers)
 {
   nsresult rv = nsGenericElement::BindToTree(aDocument, aParent,
                                              aBindingParent,
                                              aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (aDocument && HasFlag(NODE_HAS_ID) && !GetBindingParent()) {
+  if (aDocument && HasID() && !GetBindingParent()) {
     aDocument->AddToIdTable(this, DoGetID());
   }
 
   return NS_OK;
 }
 
 void
 nsXMLElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -243,54 +243,54 @@ NS_INTERFACE_MAP_END_AGGREGATED(mElement
 
 nsXULElement::nsXULElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : nsStyledElement(aNodeInfo),
       mBindingParent(nsnull)
 {
     XUL_PROTOTYPE_ATTRIBUTE_METER(gNumElements);
 }
 
-nsXULElement::nsXULSlots::nsXULSlots(PtrBits aFlags)
-    : nsXULElement::nsDOMSlots(aFlags)
+nsXULElement::nsXULSlots::nsXULSlots()
+    : nsXULElement::nsDOMSlots()
 {
 }
 
 nsXULElement::nsXULSlots::~nsXULSlots()
 {
     NS_IF_RELEASE(mControllers); // Forces release
     if (mFrameLoader) {
         mFrameLoader->Destroy();
     }
 }
 
 nsINode::nsSlots*
 nsXULElement::CreateSlots()
 {
-    return new nsXULSlots(mFlagsOrSlots);
+    return new nsXULSlots();
 }
 
 /* static */
 already_AddRefed<nsXULElement>
 nsXULElement::Create(nsXULPrototypeElement* aPrototype, nsINodeInfo *aNodeInfo,
                      PRBool aIsScriptable)
 {
     nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
     nsXULElement *element = new nsXULElement(ni.forget());
     if (element) {
         NS_ADDREF(element);
 
         element->mPrototype = aPrototype;
         if (aPrototype->mHasIdAttribute) {
-            element->SetFlags(NODE_HAS_ID);
+            element->SetHasID();
         }
         if (aPrototype->mHasClassAttribute) {
             element->SetFlags(NODE_MAY_HAVE_CLASS);
         }
         if (aPrototype->mHasStyleAttribute) {
-            element->SetFlags(NODE_MAY_HAVE_STYLE);
+            element->SetMayHaveStyle();
         }
 
         NS_ASSERTION(aPrototype->mScriptTypeID != nsIProgrammingLanguage::UNKNOWN,
                     "Need to know the language!");
         element->SetScriptTypeID(aPrototype->mScriptTypeID);
 
         if (aIsScriptable) {
             // Check each attribute on the prototype to see if we need to do
@@ -1403,17 +1403,17 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpa
     // on the element
     // https://bugzilla.mozilla.org/show_bug.cgi?id=296205
 
     // Deal with modification of magical attributes that side-effect
     // other things.
     // XXX Know how to remove POPUP event listeners when an attribute is unset?
 
     if (isId) {
-        UnsetFlags(NODE_HAS_ID);
+        ClearHasID();
     }
 
     if (aNameSpaceID == kNameSpaceID_None) {
         if (mNodeInfo->Equals(nsGkAtoms::window)) {
             if (aName == nsGkAtoms::hidechrome) {
                 HideWindowChrome(PR_FALSE);
             }
             else if (aName == nsGkAtoms::chromemargin) {
@@ -1773,25 +1773,25 @@ nsXULElement::GetBuilder(nsIXULTemplateB
 //----------------------------------------------------------------------
 // Implementation methods
 
 // XXX DoGetID and DoGetClasses must be defined here because we have proto
 // attributes.
 nsIAtom*
 nsXULElement::DoGetID() const
 {
-    NS_ASSERTION(HasFlag(NODE_HAS_ID), "Unexpected call");
+    NS_ASSERTION(HasID(), "Unexpected call");
     const nsAttrValue* attr =
         FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::id);
 
-    // We need the nullcheck here because during unlink the prototype looses
+    // We need the nullcheck here because during unlink the prototype loses
     // all of its attributes. We might want to change that.
     // The nullcheck would also be needed if we make UnsetAttr use
     // nsGenericElement::UnsetAttr as that calls out to various code between
-    // removing the attribute and clearing the NODE_HAS_ID flag.
+    // removing the attribute and calling ClearHasID().
 
     return attr ? attr->GetAtomValue() : nsnull;
 }
 
 const nsAttrValue*
 nsXULElement::DoGetClasses() const
 {
     NS_ASSERTION(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
@@ -1802,17 +1802,17 @@ NS_IMETHODIMP
 nsXULElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
 {
     return NS_OK;
 }
 
 css::StyleRule*
 nsXULElement::GetInlineStyleRule()
 {
-    if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
+    if (!MayHaveStyle()) {
         return nsnull;
     }
     // Fetch the cached style rule from the attributes.
     const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::style);
 
     if (attrVal && attrVal->Type() == nsAttrValue::eCSSStyleRule) {
         return attrVal->GetCSSStyleRuleValue();
     }
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -616,17 +616,17 @@ protected:
     // Helper routine that crawls a parent chain looking for a tree element.
     NS_IMETHOD GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement);
 
     nsresult AddPopupListener(nsIAtom* aName);
 
     class nsXULSlots : public nsGenericElement::nsDOMSlots
     {
     public:
-       nsXULSlots(PtrBits aFlags);
+       nsXULSlots();
        virtual ~nsXULSlots();
 
        nsRefPtr<nsFrameLoader> mFrameLoader;
     };
 
     virtual nsINode::nsSlots* CreateSlots();
 
     nsresult LoadSrc();
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -354,34 +354,33 @@
 #include "nsTreeColumns.h"
 #endif
 #include "nsIDOMXPathException.h"
 #include "nsIDOMXPathExpression.h"
 #include "nsIDOMNSXPathExpression.h"
 #include "nsIDOMXPathNSResolver.h"
 #include "nsIDOMXPathResult.h"
 
-#ifdef MOZ_SVG
 #include "nsIDOMGetSVGDocument.h"
 #include "nsIDOMSVGAElement.h"
 #include "nsIDOMSVGAltGlyphElement.h"
 #include "nsIDOMSVGAngle.h"
 #include "nsIDOMSVGAnimatedAngle.h"
 #include "nsIDOMSVGAnimatedBoolean.h"
 #include "nsIDOMSVGAnimatedEnum.h"
 #include "nsIDOMSVGAnimatedInteger.h"
 #include "nsIDOMSVGAnimatedLength.h"
 #include "nsIDOMSVGAnimatedLengthList.h"
 #include "nsIDOMSVGAnimatedNumber.h"
 #include "nsIDOMSVGAnimatedNumberList.h"
 #include "nsIDOMSVGAnimatedPathData.h"
 #include "nsIDOMSVGAnimatedPoints.h"
-#include "nsIDOMSVGAnimPresAspRatio.h"
 #include "nsIDOMSVGAnimatedRect.h"
 #include "nsIDOMSVGAnimatedString.h"
+#include "nsIDOMSVGAnimPresAspRatio.h"
 #ifdef MOZ_SMIL
 #include "nsIDOMSVGAnimateElement.h"
 #include "nsIDOMSVGAnimateTransformElement.h"
 #include "nsIDOMSVGAnimateMotionElement.h"
 #include "nsIDOMSVGMpathElement.h"
 #include "nsIDOMSVGSetElement.h"
 #include "nsIDOMSVGAnimationElement.h"
 #include "nsIDOMElementTimeControl.h"
@@ -434,22 +433,21 @@
 #include "nsIDOMSVGSymbolElement.h"
 #include "nsIDOMSVGTextElement.h"
 #include "nsIDOMSVGTextPathElement.h"
 #include "nsIDOMSVGTitleElement.h"
 #include "nsIDOMSVGTransform.h"
 #include "nsIDOMSVGTransformable.h"
 #include "nsIDOMSVGTransformList.h"
 #include "nsIDOMSVGTSpanElement.h"
+#include "nsIDOMSVGUnitTypes.h"
 #include "nsIDOMSVGURIReference.h"
 #include "nsIDOMSVGUseElement.h"
-#include "nsIDOMSVGUnitTypes.h"
 #include "nsIDOMSVGZoomAndPan.h"
 #include "nsIDOMSVGZoomEvent.h"
-#endif // MOZ_SVG
 
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "nsIDOMWebGLRenderingContext.h"
 
 #include "nsIImageDocument.h"
 
 // Storage includes
 #include "nsDOMStorage.h"
@@ -483,30 +481,35 @@
 #include "nsIDOMMozTouchEvent.h"
 
 #include "nsIEventListenerService.h"
 #include "nsIFrameMessageManager.h"
 #include "mozilla/dom/Element.h"
 #include "nsHTMLSelectElement.h"
 #include "nsHTMLLegendElement.h"
 
-using namespace mozilla::dom;
+#include "DOMSVGLengthList.h"
+#include "DOMSVGNumberList.h"
+#include "DOMSVGPathSegList.h"
+#include "DOMSVGPointList.h"
 
 #include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/indexedDB/IDBRequest.h"
 #include "mozilla/dom/indexedDB/IDBDatabase.h"
 #include "mozilla/dom/indexedDB/IDBEvents.h"
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
 #include "mozilla/dom/indexedDB/IDBTransaction.h"
 #include "mozilla/dom/indexedDB/IDBCursor.h"
 #include "mozilla/dom/indexedDB/IDBKeyRange.h"
 #include "mozilla/dom/indexedDB/IDBIndex.h"
 #include "nsIIDBDatabaseException.h"
 #include "nsIDOMEventException.h"
 
+using namespace mozilla::dom;
+
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
 
 // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
 //       are defined in nsIDOMClassInfo.h.
 
@@ -986,17 +989,16 @@ static nsDOMClassInfoData sClassInfoData
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(BeforeUnloadEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-#ifdef MOZ_SVG
   // SVG document
   NS_DEFINE_CLASSINFO_DATA(SVGDocument, nsDocumentSH,
                            DOCUMENT_SCRIPTABLE_FLAGS)
 
   // SVG element classes
   NS_DEFINE_CLASSINFO_DATA(SVGAElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGAltGlyphElement, nsElementSH,
@@ -1152,24 +1154,24 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(SVGAnimatedTransformList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGException, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGLength, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(SVGLengthList, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(SVGLengthList, nsSVGLengthListSH,
+                           ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGMatrix, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGNumber, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(SVGNumberList, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)    
+  NS_DEFINE_CLASSINFO_DATA(SVGNumberList, nsSVGNumberListSH,
+                           ARRAY_SCRIPTABLE_FLAGS)    
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegArcAbs, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegArcRel, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegClosePath, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegCurvetoCubicAbs, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1194,37 +1196,36 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegLinetoHorizontalRel, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegLinetoRel, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegLinetoVerticalAbs, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegLinetoVerticalRel, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(SVGPathSegList, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(SVGPathSegList, nsSVGPathSegListSH,
+                           ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegMovetoAbs, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPathSegMovetoRel, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPoint, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(SVGPointList, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(SVGPointList, nsSVGPointListSH,
+                           ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPreserveAspectRatio, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGRect, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGTransform, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGTransformList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGZoomEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-#endif // MOZ_SVG
 
   NS_DEFINE_CLASSINFO_DATA(HTMLCanvasElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasRenderingContext2D, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasGradient, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasPattern, nsDOMGenericSH,
@@ -1295,20 +1296,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(XMLHttpRequest, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(ClientRect, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(ClientRectList, nsClientRectListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 
-#ifdef MOZ_SVG
   NS_DEFINE_CLASSINFO_DATA(SVGForeignObjectElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
-#endif
 
   NS_DEFINE_CLASSINFO_DATA(XULCommandEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CommandEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(OfflineResourceList, nsOfflineResourceListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
@@ -2583,19 +2582,17 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLDivElement, nsIDOMHTMLDivElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDivElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLEmbedElement, nsIDOMHTMLEmbedElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLEmbedElement)
-#ifdef MOZ_SVG
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMGetSVGDocument)
-#endif
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLFieldSetElement, nsIDOMHTMLFieldSetElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLFieldSetElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
@@ -2640,19 +2637,17 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(HTMLHtmlElement, nsIDOMHTMLHtmlElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLHtmlElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLIFrameElement, nsIDOMHTMLIFrameElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLIFrameElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLFrameElement)
-#ifdef MOZ_SVG
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMGetSVGDocument)
-#endif
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLImageElement, nsIDOMHTMLImageElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLImageElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
@@ -2709,19 +2704,17 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLOListElement, nsIDOMHTMLOListElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLOListElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLObjectElement, nsIDOMHTMLObjectElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLObjectElement)
-#ifdef MOZ_SVG
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMGetSVGDocument)
-#endif
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLOptGroupElement, nsIDOMHTMLOptGroupElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLOptGroupElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
@@ -3040,17 +3033,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(BeforeUnloadEvent, nsIDOMBeforeUnloadEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBeforeUnloadEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
-#ifdef MOZ_SVG
 #define DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES    \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget) \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)   \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement)    \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)     \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)         \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
 
@@ -3697,17 +3689,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(SVGTransformList, nsIDOMSVGTransformList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTransformList)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGZoomEvent, nsIDOMSVGZoomEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGZoomEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
-#endif // MOZ_SVG
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLCanvasElement, nsIDOMHTMLCanvasElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLCanvasElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CanvasRenderingContext2D, nsIDOMCanvasRenderingContext2D)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCanvasRenderingContext2D)
@@ -3797,22 +3788,20 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XMLHttpProgressEvent, nsIDOMEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMLSProgressEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMProgressEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
-#ifdef MOZ_SVG
   DOM_CLASSINFO_MAP_BEGIN(SVGForeignObjectElement, nsIDOMSVGForeignObjectElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGForeignObjectElement)
     DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
-#endif
 
   DOM_CLASSINFO_MAP_BEGIN(XULCommandEvent, nsIDOMXULCommandEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CommandEvent, nsIDOMCommandEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCommandEvent)
@@ -7211,17 +7200,17 @@ nsNodeSH::PreCreate(nsISupports *nativeO
   
 #ifdef DEBUG
   {
     nsCOMPtr<nsINode> node_qi(do_QueryInterface(nativeObj));
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsINode pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(node_qi == node, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(node_qi == node, "Uh, fix QI!");
   }
 #endif
 
   // Make sure that we get the owner document of the content node, in case
   // we're in document teardown.  If we are, it's important to *not* use
   // globalObj as the nodes parent since that would give the node the
   // principal of globalObj (i.e. the principal of the document that's being
   // loaded) and not the principal of the document that's being unloaded.
@@ -7748,17 +7737,17 @@ nsElementSH::PreCreate(nsISupports *nati
 
 #ifdef DEBUG
   {
     nsCOMPtr<nsIContent> content_qi(do_QueryInterface(nativeObj));
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsIContent pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(content_qi == element, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(content_qi == element, "Uh, fix QI!");
   }
 #endif
 
   nsIDocument *doc = element->HasFlag(NODE_FORCE_XBL_BINDINGS) ?
                      element->GetOwnerDoc() :
                      element->GetCurrentDoc();
 
   if (!doc) {
@@ -7793,17 +7782,17 @@ nsElementSH::PostCreate(nsIXPConnectWrap
 
 #ifdef DEBUG
   {
     nsCOMPtr<nsIContent> content_qi(do_QueryWrappedNative(wrapper));
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsIContent pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(content_qi == element, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(content_qi == element, "Uh, fix QI!");
   }
 #endif
 
   nsIDocument* doc;
   if (element->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
     doc = element->GetOwnerDoc();
   }
   else {
@@ -8065,17 +8054,17 @@ nsNodeListSH::GetLength(nsIXPConnectWrap
   nsINodeList* list = static_cast<nsINodeList*>(GetNative(wrapper, obj));
 #ifdef DEBUG
   {
     nsCOMPtr<nsINodeList> list_qi = do_QueryWrappedNative(wrapper, obj);
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsINodeList pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(list_qi == list, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
   }
 #endif
 
   return list->GetLength(length);
 }
 
 nsISupports*
 nsNodeListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
@@ -8084,17 +8073,17 @@ nsNodeListSH::GetItemAt(nsISupports *aNa
   nsINodeList* list = static_cast<nsINodeList*>(aNative);
 #ifdef DEBUG
   {
     nsCOMPtr<nsINodeList> list_qi = do_QueryInterface(aNative);
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsINodeList pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(list_qi == list, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
   }
 #endif
 
   nsINode *node;
   *aCache = node = list->GetNodeAt(aIndex);
   return node;
 }
 
@@ -8247,17 +8236,17 @@ nsHTMLCollectionSH::GetLength(nsIXPConne
 #ifdef DEBUG
   {
     nsCOMPtr<nsIHTMLCollection> collection_qi =
       do_QueryWrappedNative(wrapper, obj);
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsIHTMLCollection pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(collection_qi == collection, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
   }
 #endif
 
   return collection->GetLength(length);
 }
 
 nsISupports*
 nsHTMLCollectionSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
@@ -8266,17 +8255,17 @@ nsHTMLCollectionSH::GetItemAt(nsISupport
   nsIHTMLCollection* collection = static_cast<nsIHTMLCollection*>(aNative);
 #ifdef DEBUG
   {
     nsCOMPtr<nsIHTMLCollection> collection_qi = do_QueryInterface(aNative);
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsIHTMLCollection pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(collection_qi == collection, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
   }
 #endif
 
   nsINode *item;
   *aCache = item = collection->GetNodeAt(aIndex, aResult);
   return item;
 }
 
@@ -8289,17 +8278,17 @@ nsHTMLCollectionSH::GetNamedItem(nsISupp
   nsIHTMLCollection* collection = static_cast<nsIHTMLCollection*>(aNative);
 #ifdef DEBUG
   {
     nsCOMPtr<nsIHTMLCollection> collection_qi = do_QueryInterface(aNative);
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsIHTMLCollection pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(collection_qi == collection, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
   }
 #endif
 
   return collection->GetNamedItem(aName, aCache, aResult);
 }
 
 
 // ContentList helper
@@ -10172,17 +10161,17 @@ nsCSSRuleListSH::GetItemAt(nsISupports *
   nsICSSRuleList* list = static_cast<nsICSSRuleList*>(aNative);
 #ifdef DEBUG
   {
     nsCOMPtr<nsICSSRuleList> list_qi = do_QueryInterface(aNative);
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsICSSRuleList pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
-    NS_ASSERTION(list_qi == list, "Uh, fix QI!");
+    NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
   }
 #endif
 
   return list->GetItemAt(aIndex, aResult);
 }
 
 // ClientRectList scriptable helper
 
@@ -10779,8 +10768,30 @@ nsOfflineResourceListSH::GetStringAt(nsI
 nsISupports*
 nsFileListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
                         nsWrapperCache **aCache, nsresult *aResult)
 {
   nsDOMFileList* list = nsDOMFileList::FromSupports(aNative);
 
   return list->GetItemAt(aIndex);
 }
+
+// Template for SVGXXXList helpers
+template<class ListInterfaceType, class ListType> nsISupports*
+nsSVGListSH<ListInterfaceType, ListType>::GetItemAt(nsISupports *aNative,
+                                                    PRUint32 aIndex,
+                                                    nsWrapperCache **aCache,
+                                                    nsresult *aResult)
+{
+  ListType* list = static_cast<ListType*>(static_cast<ListInterfaceType*>(aNative));
+#ifdef DEBUG
+  {
+    nsCOMPtr<ListInterfaceType> list_qi = do_QueryInterface(aNative);
+
+    // If this assertion fires the QI implementation for the object in
+    // question doesn't use the nsIDOMSVGXXXList pointer as the nsISupports
+    // pointer. That must be fixed, or we'll crash...
+    NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
+  }
+#endif
+
+  return list->GetItemWithoutAddRef(aIndex);
+}
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -44,24 +44,41 @@
 #include "nsIXPCScriptable.h"
 #include "jsapi.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptContext.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 #include "nsIScriptGlobalObject.h"
 #include "nsContentUtils.h"
 
-class nsIDOMWindow;
+namespace mozilla {
+class DOMSVGLengthList;
+class DOMSVGNumberList;
+class DOMSVGPathSegList;
+class DOMSVGPointList;
+}
+class nsGlobalWindow;
+class nsIDOMDocument;
 class nsIDOMNSHTMLOptionCollection;
-class nsIPluginInstance;
+class nsIDOMNodeList;
+class nsIDOMSVGLength;
+class nsIDOMSVGLengthList;
+class nsIDOMSVGNumber;
+class nsIDOMSVGNumberList;
+class nsIDOMSVGPathSeg;
+class nsIDOMSVGPathSegList;
+class nsIDOMSVGPoint;
+class nsIDOMSVGPointList;
+class nsIDOMSVGTransform;
+class nsIDOMSVGTransformList;
+class nsIDOMWindow;
 class nsIForm;
-class nsIDOMNodeList;
-class nsIDOMDocument;
 class nsIHTMLDocument;
-class nsGlobalWindow;
+class nsIPluginInstance;
+class nsSVGTransformList;
 
 struct nsDOMClassInfoData;
 
 typedef nsIClassInfo* (*nsDOMClassInfoConstructorFnc)
   (nsDOMClassInfoData* aData);
 
 typedef nsresult (*nsDOMConstructorFunc)(nsISupports** aNewObject);
 
@@ -1834,9 +1851,35 @@ public:
   }
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsWebGLViewportHandlerSH(aData);
   }
 };
 
+
+// Template for SVGXXXList helpers
+ 
+template<class ListInterfaceType, class ListType>
+class nsSVGListSH : public nsArraySH
+{
+protected:
+  nsSVGListSH(nsDOMClassInfoData* aData) : nsArraySH(aData)
+  {
+  }
+
+public:
+  virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
+                                 nsWrapperCache **aCache, nsresult *aResult);
+ 
+  static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
+  {
+    return new nsSVGListSH(aData);
+  }
+};
+
+typedef nsSVGListSH<nsIDOMSVGLengthList, mozilla::DOMSVGLengthList> nsSVGLengthListSH;
+typedef nsSVGListSH<nsIDOMSVGNumberList, mozilla::DOMSVGNumberList> nsSVGNumberListSH;
+typedef nsSVGListSH<nsIDOMSVGPathSegList, mozilla::DOMSVGPathSegList> nsSVGPathSegListSH;
+typedef nsSVGListSH<nsIDOMSVGPointList, mozilla::DOMSVGPointList> nsSVGPointListSH;
+
 #endif /* nsDOMClassInfo_h___ */
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -9,16 +9,17 @@ DOM_SRCDIRS = \
   dom/src/notification \
   dom/src/threads \
   content/xbl/src \
   content/xul/document/src \
   content/events/src \
   content/base/src \
   content/html/content/src \
   content/html/document/src \
+  content/svg/content/src \
   layout/generic \
   layout/style \
   layout/xul/base/src \
   layout/xul/base/src/tree/src \
   $(NULL)
 
 LOCAL_INCLUDES += $(DOM_SRCDIRS:%=-I$(topsrcdir)/%)
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/dom/interfaces/svg/nsIDOMSVGLengthList.idl
+++ b/dom/interfaces/svg/nsIDOMSVGLengthList.idl
@@ -35,29 +35,29 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIDOMSVGLength;
 
-[scriptable, uuid(a8760fcd-3de5-446a-a009-5cf877e7a4df)]
+[scriptable, uuid(f8c89734-d6b4-4a56-bdf5-1ce1104dc1ab)]
 interface nsIDOMSVGLengthList : nsISupports
 { 
   readonly attribute unsigned long numberOfItems;
+  readonly attribute unsigned long length;  // synonym for numberOfItems
 
   void clear();
           // raises(nsIDOMDOMException);
   nsIDOMSVGLength initialize(in nsIDOMSVGLength newItem );
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGLength getItem(in unsigned long index);
                     // raises(nsIDOMDOMException);
   nsIDOMSVGLength insertItemBefore(in nsIDOMSVGLength newItem, in unsigned long index);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGLength replaceItem(in nsIDOMSVGLength newItem, in unsigned long index);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGLength removeItem(in unsigned long index);
                     // raises(nsIDOMDOMException);
   nsIDOMSVGLength appendItem(in nsIDOMSVGLength newItem);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
 };
-
--- a/dom/interfaces/svg/nsIDOMSVGNumberList.idl
+++ b/dom/interfaces/svg/nsIDOMSVGNumberList.idl
@@ -35,29 +35,29 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIDOMSVGNumber;
 
-[scriptable, uuid(59364ec4-faf1-460f-bf58-e6a6a2769a3a)]
+[scriptable, uuid(8e303812-38b4-4780-9f8c-9ddbfcb26c81)]
 interface nsIDOMSVGNumberList : nsISupports
 { 
   readonly attribute unsigned long numberOfItems;
+  readonly attribute unsigned long length;  // synonym for numberOfItems
 
   void clear();
           // raises(nsIDOMDOMException);
   nsIDOMSVGNumber initialize(in nsIDOMSVGNumber newItem );
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGNumber getItem(in unsigned long index);
                     // raises(nsIDOMDOMException);
   nsIDOMSVGNumber insertItemBefore(in nsIDOMSVGNumber newItem, in unsigned long index);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGNumber replaceItem(in nsIDOMSVGNumber newItem, in unsigned long index);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGNumber removeItem(in unsigned long index);
                     // raises(nsIDOMDOMException);
   nsIDOMSVGNumber appendItem(in nsIDOMSVGNumber newItem);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
 };
-
--- a/dom/interfaces/svg/nsIDOMSVGPathSegList.idl
+++ b/dom/interfaces/svg/nsIDOMSVGPathSegList.idl
@@ -35,29 +35,29 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIDOMSVGPathSeg;
 
-[scriptable, uuid(94a6db98-3f34-4529-a35f-89ef49713795)]
+[scriptable, uuid(1e4efb5c-7b0f-4338-a92e-6ca5402b303c)]
 interface nsIDOMSVGPathSegList : nsISupports
 { 
   readonly attribute unsigned long numberOfItems;
+  readonly attribute unsigned long length;  // synonym for numberOfItems
 
   void clear();
           // raises(nsIDOMDOMException);
   nsIDOMSVGPathSeg initialize(in nsIDOMSVGPathSeg newItem );
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGPathSeg getItem(in unsigned long index);
                     // raises(nsIDOMDOMException);
   nsIDOMSVGPathSeg insertItemBefore(in nsIDOMSVGPathSeg newItem, in unsigned long index);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGPathSeg replaceItem(in nsIDOMSVGPathSeg newItem, in unsigned long index);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
   nsIDOMSVGPathSeg removeItem(in unsigned long index);
                     // raises(nsIDOMDOMException);
   nsIDOMSVGPathSeg appendItem(in nsIDOMSVGPathSeg newItem);
                     // raises(nsIDOMDOMException, nsIDOMSVGException);
 };
-
--- a/dom/interfaces/svg/nsIDOMSVGPointList.idl
+++ b/dom/interfaces/svg/nsIDOMSVGPointList.idl
@@ -35,20 +35,21 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIDOMSVGPoint;
 
-[scriptable, uuid(4c12af24-0fc2-4fe7-b71d-5d6b41d463c1)]
+[scriptable, uuid(7bb28750-7238-4083-b5f4-4def4646a637)]
 interface nsIDOMSVGPointList : nsISupports
 {
   readonly attribute unsigned long numberOfItems;
+  readonly attribute unsigned long length;  // synonym for numberOfItems
 
   void clear();
       // raises( DOMException );
   nsIDOMSVGPoint initialize(in nsIDOMSVGPoint newItem);
       // raises( DOMException, SVGException );
   nsIDOMSVGPoint getItem (in unsigned long index);
       // raises( DOMException );
   nsIDOMSVGPoint insertItemBefore(in nsIDOMSVGPoint newItem, in unsigned long index);
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -54,16 +54,18 @@ import android.view.inputmethod.*;
 import android.content.*;
 import android.content.res.*;
 import android.content.pm.*;
 import android.graphics.*;
 import android.widget.*;
 import android.hardware.*;
 import android.location.*;
 import android.webkit.MimeTypeMap;
+import android.media.MediaScannerConnection;
+import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 
 import android.util.*;
 import android.net.Uri;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 
 public class GeckoAppShell
 {
@@ -114,16 +116,41 @@ public class GeckoAppShell
             Looper.prepare();
             try {
                 mHandlerQueue.put(new Handler());
             } catch (InterruptedException ie) {}
             Looper.loop();
         }
     }
 
+    private static class GeckoMediaScannerClient implements MediaScannerConnectionClient {
+        private String mFile = "";
+        private String mMimeType = "";
+        private MediaScannerConnection mScanner = null;
+
+        public GeckoMediaScannerClient(Context aContext, String aFile, String aMimeType) {
+            mFile = aFile;
+            mMimeType = aMimeType;
+            mScanner = new MediaScannerConnection(aContext, this);
+            if (mScanner != null)
+                mScanner.connect();
+        }
+
+        public void onMediaScannerConnected() {
+            mScanner.scanFile(mFile, mMimeType);
+        }
+
+        public void onScanCompleted(String path, Uri uri) {
+            if(path.equals(mFile)) {
+                mScanner.disconnect();
+                mScanner = null;
+            }
+        }
+    }
+
     // Get a Handler for the main java thread
     public static Handler getMainHandler() {
         return GeckoApp.mAppContext.mMainHandler;
     }
 
     private static Handler sHandler = null;
 
     // Get a Handler for a looper thread, or create one if it doesn't exist yet
@@ -1060,9 +1087,14 @@ public class GeckoAppShell
     public static void waitForAnotherGeckoProc(){
         int countdown = 40;
         while (!checkForGeckoProcs() &&  --countdown > 0) {
             try {
                 Thread.currentThread().sleep(100);
             } catch (InterruptedException ie) {}
         }
     }
+
+    public static void scanMedia(String aFile, String aMimeType) {
+        Context context = GeckoApp.surfaceView.getContext();
+        GeckoMediaScannerClient client = new GeckoMediaScannerClient(context, aFile, aMimeType);
+    }
 }
--- a/extensions/spellcheck/hunspell/Makefile.in
+++ b/extensions/spellcheck/hunspell/Makefile.in
@@ -32,16 +32,27 @@
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ****** END LICENSE BLOCK ******
 
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
+relativesrcdir = extensions/spellcheck/hunspell
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= hunspell
-DIRS		= src
+DIRS = src
+
+XPCSHELL_TESTS = tests/unit
+
+ABS_topsrcdir = $(call core_abspath,$(topsrcdir))
+
+libs::
+	$(NSINSTALL) -D $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/tests/unit/data
+	cd $(srcdir)/tests; $(PYTHON) $(ABS_topsrcdir)/config/nsinstall.py \
+	  ./ \
+	  $(call core_abspath,$(DEPTH)/_tests/xpcshell/$(relativesrcdir)/tests/unit/data/)
 
 include $(topsrcdir)/config/rules.mk
 
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -356,38 +356,38 @@ mozHunspell::LoadDictionaryList()
     dictDirs->GetNext(getter_AddRefs(elem));
 
     dictDir = do_QueryInterface(elem);
     if (dictDir)
       LoadDictionariesFromDir(dictDir);
   }
 }
 
-void
+NS_IMETHODIMP
 mozHunspell::LoadDictionariesFromDir(nsIFile* aDir)
 {
   nsresult rv;
 
   PRBool check = PR_FALSE;
   rv = aDir->Exists(&check);
   if (NS_FAILED(rv) || !check)
-    return;
+    return NS_ERROR_UNEXPECTED;
 
   rv = aDir->IsDirectory(&check);
   if (NS_FAILED(rv) || !check)
-    return;
+    return NS_ERROR_UNEXPECTED;
 
   nsCOMPtr<nsISimpleEnumerator> e;
   rv = aDir->GetDirectoryEntries(getter_AddRefs(e));
   if (NS_FAILED(rv))
-    return;
+    return NS_ERROR_UNEXPECTED;
 
   nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e));
   if (!files)
-    return;
+    return NS_ERROR_UNEXPECTED;
 
   nsCOMPtr<nsIFile> file;
   while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file) {
     nsAutoString leafName;
     file->GetLeafName(leafName);
     if (!StringEndsWith(leafName, NS_LITERAL_STRING(".dic")))
       continue;
 
@@ -403,16 +403,18 @@ mozHunspell::LoadDictionariesFromDir(nsI
       continue;
 
 #ifdef DEBUG_bsmedberg
     printf("Adding dictionary: %s\n", NS_ConvertUTF16toUTF8(dict).get());
 #endif
 
     mDictionaries.Put(dict, file);
   }
+
+  return NS_OK;
 }
 
 nsresult mozHunspell::ConvertCharset(const PRUnichar* aStr, char ** aDst)
 {
   NS_ENSURE_ARG_POINTER(aDst);
   NS_ENSURE_TRUE(mEncoder, NS_ERROR_NULL_POINTER);
 
   PRInt32 outLength;
--- a/extensions/spellcheck/hunspell/src/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.h
@@ -88,17 +88,16 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozHunspell, mozISpellCheckingEngine)
 
   mozHunspell() : mHunspell(nsnull) { }
   virtual ~mozHunspell();
 
   nsresult Init();
 
   void LoadDictionaryList();
-  void LoadDictionariesFromDir(nsIFile* aDir);
 
   // helper method for converting a word to the charset of the dictionary
   nsresult ConvertCharset(const PRUnichar* aStr, char ** aDst);
 
 protected:
  
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
   nsCOMPtr<nsIUnicodeEncoder>      mEncoder; 
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589.aff
@@ -0,0 +1,3 @@
+# capitalized ngram suggestion test data for
+# Sf.net Bug ID 1463589, reported by Frederik Fouvry.
+MAXNGRAMSUGS 1
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589.dic
@@ -0,0 +1,2 @@
+1
+Khlschrank
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589.sug
@@ -0,0 +1,5 @@
+Khlschrank
+Khlschrank
+Khlschrank
+Khlschrank
+Khlschrank
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME -i ISO8859-1
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589.wrong
@@ -0,0 +1,5 @@
+kuhlschrank
+kuehlschrank
+khlschrank
+Kuhlschrank
+Kuehlschrank
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589_utf.aff
@@ -0,0 +1,4 @@
+# capitalized ngram suggestion test data (Unicode version) for
+# Sf.net Bug ID 1463589, reported by Frederik Fouvry.
+SET UTF-8
+MAXNGRAMSUGS 1
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589_utf.dic
@@ -0,0 +1,2 @@
+1
+Kühlschrank
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589_utf.sug
@@ -0,0 +1,5 @@
+Kühlschrank
+Kühlschrank
+Kühlschrank
+Kühlschrank
+Kühlschrank
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589_utf.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME -i utf-8
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1463589_utf.wrong
@@ -0,0 +1,5 @@
+kuhlschrank
+kuehlschrank
+kühlschrank
+Kuhlschrank
+Kuehlschrank
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1592880.aff
@@ -0,0 +1,20 @@
+# fix homonym handling for German dictionary project,
+# reported by Björn Jacke (sf.net Bug ID 1592880).
+SET ISO8859-1
+
+SFX N Y 1
+SFX N 0 n .
+
+SFX S Y 1
+SFX S 0 s .
+
+SFX P Y 1
+SFX P 0 en .
+
+SFX Q Y 2
+SFX Q 0 e .
+SFX Q 0 en .
+
+COMPOUNDEND z
+COMPOUNDPERMITFLAG c
+ONLYINCOMPOUND o
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1592880.dic
@@ -0,0 +1,4 @@
+3
+weg/Qoz
+weg/P
+wege
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1592880.good
@@ -0,0 +1,3 @@
+weg
+wege
+wegen
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1592880.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1695964.aff
@@ -0,0 +1,10 @@
+# fix NEEDAFFIX homonym suggestion.
+# Sf.net Bug ID 1695964, reported by Björn Jacke.
+TRY esianrtolcdugmphbyfvkwESIANRTOLCDUGMPHBYFVKW
+MAXNGRAMSUGS 0
+NEEDAFFIX h
+SFX S Y 1
+SFX S 0 s .
+
+SFX e Y 1
+SFX e 0 e .
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1695964.dic
@@ -0,0 +1,3 @@
+2
+Mull/he
+Mull/S
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1695964.sug
@@ -0,0 +1,3 @@
+Mull
+Mulle
+Mulls
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1695964.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1695964.wrong
@@ -0,0 +1,3 @@
+Mall
+Malle
+Malls
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1706659.aff
@@ -0,0 +1,13 @@
+# test COMPOUNDRULE bug reported by Björn Jacke
+SET ISO8859-1
+TRY esijanrtolcdugmphbyfvkwqxz
+
+SFX A Y 5
+SFX A 0 e .
+SFX A 0 er .
+SFX A 0 en .
+SFX A 0 em .
+SFX A 0 es .
+
+COMPOUNDRULE 1
+COMPOUNDRULE vw
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1706659.dic
@@ -0,0 +1,4 @@
+3
+arbeits/v
+scheu/Aw
+farbig/A
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1706659.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1706659.wrong
@@ -0,0 +1,3 @@
+arbeitsfarbig
+arbeitsfarbige
+arbeitsfarbiger
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1975530.aff
@@ -0,0 +1,6 @@
+SET	UTF-8
+IGNORE ٌٍَُِّْـ
+
+PFX x N 1
+PFX x	أ	ت	أ[^ي]
+
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1975530.dic
@@ -0,0 +1,3 @@
+2
+أرى/x
+أيار/x
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1975530.good
@@ -0,0 +1,3 @@
+أرى
+أيار
+ترى
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1975530.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME -i UTF-8
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/1975530.wrong
@@ -0,0 +1,1 @@
+تيار
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970240.aff
@@ -0,0 +1,5 @@
+# test words with three parts
+CHECKCOMPOUNDPATTERN 1
+CHECKCOMPOUNDPATTERN le fi
+COMPOUNDFLAG c
+
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970240.dic
@@ -0,0 +1,4 @@
+3
+first/c
+middle/c
+last/c
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970240.good
@@ -0,0 +1,1 @@
+firstmiddlelast
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970240.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970240.wrong
@@ -0,0 +1,1 @@
+lastmiddlefirst
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970242.aff
@@ -0,0 +1,4 @@
+CHECKCOMPOUNDPATTERN 1
+CHECKCOMPOUNDPATTERN /a /b
+COMPOUNDFLAG c
+
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970242.dic
@@ -0,0 +1,4 @@
+3
+foo/ac
+bar/c
+baz/bc
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970242.good
@@ -0,0 +1,5 @@
+foobar
+barfoo
+bazfoo
+barbaz
+bazbar
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970242.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2970242.wrong
@@ -0,0 +1,1 @@
+foobaz
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2999225.aff
@@ -0,0 +1,6 @@
+COMPOUNDRULE 1
+COMPOUNDRULE ab
+
+COMPOUNDBEGIN A
+COMPOUNDEND B
+
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2999225.dic
@@ -0,0 +1,4 @@
+3
+foo/aA
+bar/b
+baz/B
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2999225.good
@@ -0,0 +1,2 @@
+foobar
+foobaz
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/2999225.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/IJ.aff
@@ -0,0 +1,8 @@
+# check bad capitalisation of Dutch letter IJ.
+TRY i
+FORBIDDENWORD *
+PFX i N 1
+PFX i ij IJ ij
+
+REP 1
+REP ij IJ
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/IJ.dic
@@ -0,0 +1,3 @@
+1
+ijs/i
+Ijs/*
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/IJ.good
@@ -0,0 +1,2 @@
+ijs
+IJs
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/IJ.sug
@@ -0,0 +1,1 @@
+IJs, ijs
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/IJ.test
@@ -0,0 +1,4 @@
+#!/bin/sh
+DIR="`dirname $0`"
+NAME="`basename $0 .test`"
+$DIR/test.sh $NAME
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/IJ.wrong
@@ -0,0 +1,1 @@
+Ijs
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/Makefile.am
@@ -0,0 +1,693 @@
+## Process this file with automake to create Makefile.in
+
+SUBDIRS = suggestiontest
+
+XFAIL_TESTS = @XFAILED@
+
+TESTS =	\
+affixes.test \
+condition.test \
+condition_utf.test \
+base.test \
+base_utf.test \
+allcaps.test \
+allcaps_utf.test \
+allcaps2.test \
+allcaps3.test \
+keepcase.test \
+i58202.test \
+map.test \
+rep.test \
+sug.test \
+sugutf.test \
+phone.test \
+flag.test \
+flaglong.test \
+flagnum.test \
+flagutf8.test \
+slash.test \
+forbiddenword.test \
+nosuggest.test \
+alias.test \
+alias2.test \
+alias3.test \
+breakdefault.test \
+break.test \
+needaffix.test \
+needaffix2.test \
+needaffix3.test \
+needaffix4.test \
+needaffix5.test \
+circumfix.test \
+fogemorpheme.test \
+onlyincompound.test \
+complexprefixes.test \
+complexprefixes2.test \
+complexprefixesutf.test \
+conditionalprefix.test \
+zeroaffix.test \
+utf8.test \
+utf8_bom.test \
+utf8_bom2.test \
+utf8_nonbmp.test \
+compoundflag.test \
+compoundrule.test \
+compoundrule2.test \
+compoundrule3.test \
+compoundrule4.test \
+compoundrule5.test \
+compoundrule6.test \
+compoundrule7.test \
+compoundrule8.test \
+compoundaffix.test \
+compoundaffix2.test \
+compoundaffix3.test \
+checkcompounddup.test \
+checkcompoundtriple.test \
+simplifiedtriple.test \
+checkcompoundrep.test \
+checkcompoundcase2.test \
+checkcompoundcaseutf.test \
+checkcompoundpattern.test \
+checkcompoundpattern2.test \
+checkcompoundpattern3.test \
+checkcompoundpattern4.test \
+utfcompound.test \
+checksharps.test \
+checksharpsutf.test \
+germancompounding.test \
+germancompoundingold.test \
+i35725.test \
+i53643.test \
+i54633.test \
+i54980.test \
+maputf.test \
+reputf.test \
+ignore.test \
+ignoreutf.test \
+1592880.test \
+1695964.test \
+1463589.test \
+1463589_utf.test \
+IJ.test \
+i68568.test \
+i68568utf.test \
+1706659.test \
+digits_in_words.test \
+colons_in_words.test \
+ngram_utf_fix.test \
+morph.test \
+1975530.test \
+fullstrip.test \
+iconv.test \
+oconv.test \
+encoding.test \
+korean.test \
+opentaal_forbiddenword1.test \
+opentaal_forbiddenword2.test \
+opentaal_keepcase.test \
+arabic.test \
+2970240.test \
+2970242.test \
+breakoff.test \
+opentaal_cpdpat.test \
+opentaal_cpdpat2.test \
+2999225.test \
+onlyincompound2.test \
+forceucase.test \
+warn.test
+
+# infixes.test
+
+distclean-local:
+	-rm -rf testSubDir
+        
+EXTRA_DIST = \
+test.sh \
+affixes.aff \
+affixes.dic \
+affixes.good \
+affixes.test \
+condition.aff \
+condition.dic \
+condition.good \
+condition.test \
+condition.wrong \
+condition_utf.aff \
+condition_utf.dic \
+condition_utf.good \
+condition_utf.test \
+condition_utf.wrong \
+base.aff \
+base.dic \
+base.good \
+base.sug \
+base.test \
+base.wrong \
+base_utf.aff \
+base_utf.dic \
+base_utf.good \
+base_utf.sug \
+base_utf.test \
+base_utf.wrong \
+allcaps.aff \
+allcaps.dic \
+allcaps.good \
+allcaps.sug \
+allcaps.test \
+allcaps.wrong \
+allcaps2.aff \
+allcaps2.dic \
+allcaps2.good \
+allcaps2.sug \
+allcaps2.test \
+allcaps2.wrong \
+allcaps3.aff \
+allcaps3.dic \
+allcaps3.good \
+allcaps3.test \
+allcaps3.wrong \
+allcaps_utf.aff \
+allcaps_utf.dic \
+allcaps_utf.good \
+allcaps_utf.sug \
+allcaps_utf.test \
+allcaps_utf.wrong \
+keepcase.aff \
+keepcase.dic \
+keepcase.good \
+keepcase.sug \
+keepcase.test \
+keepcase.wrong \
+map.aff \
+map.dic \
+map.sug \
+map.test \
+map.wrong \
+rep.aff \
+rep.dic \
+rep.sug \
+rep.test \
+rep.wrong \
+sug.aff \
+sug.dic \
+sug.sug \
+sug.test \
+sug.wrong \
+sugutf.aff \
+sugutf.dic \
+sugutf.sug \
+sugutf.test \
+sugutf.wrong \
+phone.aff \
+phone.dic \
+phone.sug \
+phone.test \
+phone.wrong \
+alias.aff \
+alias.dic \
+alias.good \
+alias.test \
+alias2.aff \
+alias2.dic \
+alias2.good \
+alias2.morph \
+alias2.test \
+alias3.aff \
+alias3.dic \
+alias3.good \
+alias3.morph \
+alias3.test \
+break.aff \
+break.dic \
+break.good \
+break.test \
+break.wrong \
+breakdefault.aff \
+breakdefault.dic \
+breakdefault.good \
+breakdefault.sug \
+breakdefault.test \
+breakdefault.wrong \
+circumfix.aff \
+circumfix.dic \
+circumfix.good \
+circumfix.morph \
+circumfix.test \
+circumfix.wrong \
+fogemorpheme.aff \
+fogemorpheme.dic \
+fogemorpheme.good \
+fogemorpheme.test \
+fogemorpheme.wrong \
+onlyincompound.aff \
+onlyincompound.dic \
+onlyincompound.good \
+onlyincompound.sug \
+onlyincompound.test \
+onlyincompound.wrong \
+forbiddenword.aff \
+forbiddenword.dic \
+forbiddenword.good \
+forbiddenword.test \
+forbiddenword.wrong \
+nosuggest.aff \
+nosuggest.dic \
+nosuggest.good \
+nosuggest.sug \
+nosuggest.test \
+nosuggest.wrong \
+germancompounding.aff \
+germancompounding.dic \
+germancompounding.good \
+germancompounding.test \
+germancompounding.wrong \
+germancompoundingold.aff \
+germancompoundingold.dic \
+germancompoundingold.good \
+germancompoundingold.test \
+germancompoundingold.wrong \
+needaffix2.aff \
+needaffix2.dic \
+needaffix2.good \
+needaffix2.morph \
+needaffix2.test \
+needaffix3.aff \
+needaffix3.dic \
+needaffix3.good \
+needaffix3.test \
+needaffix3.wrong \
+needaffix4.aff \
+needaffix4.dic \
+needaffix4.good \
+needaffix4.test \
+needaffix5.aff \
+needaffix5.dic \
+needaffix5.good \
+needaffix5.test \
+needaffix5.wrong \
+needaffix.aff \
+needaffix.dic \
+needaffix.good \
+needaffix.test \
+needaffix.wrong \
+zeroaffix.aff \
+zeroaffix.dic \
+zeroaffix.good \
+zeroaffix.morph \
+zeroaffix.test \
+utf8.aff \
+utf8.dic \
+utf8.good \
+utf8.test \
+utf8_bom.aff \
+utf8_bom.dic \
+utf8_bom.good \
+utf8_bom.test \
+utf8_bom2.aff \
+utf8_bom2.dic \
+utf8_bom2.good \
+utf8_bom2.test \
+utf8_nonbmp.aff \
+utf8_nonbmp.dic \
+utf8_nonbmp.good \
+utf8_nonbmp.sug \
+utf8_nonbmp.test \
+utf8_nonbmp.wrong \
+utfcompound.aff \
+utfcompound.dic \
+utfcompound.good \
+utfcompound.test \
+utfcompound.wrong \
+compoundflag.aff \
+compoundflag.dic \
+compoundflag.good \
+compoundflag.test \
+compoundflag.wrong \
+compoundrule.aff \
+compoundrule.dic \
+compoundrule.good \
+compoundrule.test \
+compoundrule.wrong \
+compoundrule2.aff \
+compoundrule2.dic \
+compoundrule2.good \
+compoundrule2.test \
+compoundrule2.wrong \
+compoundrule3.aff \
+compoundrule3.dic \
+compoundrule3.good \
+compoundrule3.test \
+compoundrule3.wrong \
+compoundrule4.aff \
+compoundrule4.dic \
+compoundrule4.good \
+compoundrule4.test \
+compoundrule4.wrong \
+compoundrule5.aff \
+compoundrule5.dic \
+compoundrule5.good \
+compoundrule5.morph \
+compoundrule5.test \
+compoundrule5.wrong \
+compoundrule6.aff \
+compoundrule6.dic \
+compoundrule6.good \
+compoundrule6.test \
+compoundrule6.wrong \
+compoundrule7.aff \
+compoundrule7.dic \
+compoundrule7.good \
+compoundrule7.test \
+compoundrule7.wrong \
+compoundrule8.aff \
+compoundrule8.dic \
+compoundrule8.good \
+compoundrule8.test \
+compoundrule8.wrong \
+compoundaffix.aff \
+compoundaffix.dic \
+compoundaffix.good \
+compoundaffix.test \
+compoundaffix.wrong \
+compoundaffix2.aff \
+compoundaffix2.dic \
+compoundaffix2.good \
+compoundaffix2.test \
+compoundaffix3.aff \
+compoundaffix3.dic \
+compoundaffix3.good \
+compoundaffix3.test \
+compoundaffix3.wrong \
+checkcompounddup.aff \
+checkcompounddup.dic \
+checkcompounddup.good \
+checkcompounddup.test \
+checkcompounddup.wrong \
+checkcompoundcase.aff \
+checkcompoundcase.dic \
+checkcompoundcase.good \
+checkcompoundcase.test \
+checkcompoundcase.wrong \
+checkcompoundcase2.aff \
+checkcompoundcase2.dic \
+checkcompoundcase2.good \
+checkcompoundcase2.test \
+checkcompoundcase2.wrong \
+checkcompoundcaseutf.aff \
+checkcompoundcaseutf.dic \
+checkcompoundcaseutf.good \
+checkcompoundcaseutf.test \
+checkcompoundcaseutf.wrong \
+checkcompoundrep.aff \
+checkcompoundrep.dic \
+checkcompoundrep.good \
+checkcompoundrep.test \
+checkcompoundrep.wrong \
+checkcompoundtriple.aff \
+checkcompoundtriple.dic \
+checkcompoundtriple.good \
+checkcompoundtriple.test \
+checkcompoundtriple.wrong \
+simplifiedtriple.aff \
+simplifiedtriple.dic \
+simplifiedtriple.good \
+simplifiedtriple.test \
+simplifiedtriple.wrong \
+checkcompoundpattern.aff \
+checkcompoundpattern.dic \
+checkcompoundpattern.good \
+checkcompoundpattern.test \
+checkcompoundpattern.wrong \
+checkcompoundpattern2.aff \
+checkcompoundpattern2.dic \
+checkcompoundpattern2.good \
+checkcompoundpattern2.test \
+checkcompoundpattern2.wrong \
+checkcompoundpattern3.aff \
+checkcompoundpattern3.dic \
+checkcompoundpattern3.good \
+checkcompoundpattern3.test \
+checkcompoundpattern3.wrong \
+checkcompoundpattern4.aff \
+checkcompoundpattern4.dic \
+checkcompoundpattern4.good \
+checkcompoundpattern4.test \
+checkcompoundpattern4.wrong \
+checksharps.aff \
+checksharps.dic \
+checksharps.good \
+checksharps.sug \
+checksharps.test \
+checksharps.wrong \
+checksharpsutf.aff \
+checksharpsutf.dic \
+checksharpsutf.good \
+checksharpsutf.sug \
+checksharpsutf.test \
+checksharpsutf.wrong \
+conditionalprefix.aff \
+conditionalprefix.dic \
+conditionalprefix.good \
+conditionalprefix.morph \
+conditionalprefix.test \
+conditionalprefix.wrong \
+flaglong.aff \
+flaglong.dic \
+flaglong.good \
+flaglong.test \
+flagnum.aff \
+flagnum.dic \
+flagnum.good \
+flagnum.test \
+flag.aff \
+flag.dic \
+flag.good \
+flag.test \
+flagutf8.aff \
+flagutf8.dic \
+flagutf8.good \
+flagutf8.test \
+complexprefixes.aff \
+complexprefixes.dic \
+complexprefixes.good \
+complexprefixes.wrong \
+complexprefixes.test \
+complexprefixes2.aff \
+complexprefixes2.dic \
+complexprefixes2.good \
+complexprefixes2.test \
+complexprefixesutf.aff \
+complexprefixesutf.dic \
+complexprefixesutf.good \
+complexprefixesutf.wrong \
+complexprefixesutf.test \
+i35725.aff \
+i35725.dic \
+i35725.good \
+i35725.sug \
+i35725.test \
+i35725.wrong \
+i53643.aff \
+i53643.dic \
+i53643.good \
+i53643.test \
+i53643.wrong \
+i54633.aff \
+i54633.dic \
+i54633.good \
+i54633.sug \
+i54633.test \
+i54633.wrong \
+i54980.aff \
+i54980.dic \
+i54980.good \
+i54980.test \
+i58202.aff \
+i58202.dic \
+i58202.good \
+i58202.sug \
+i58202.test \
+i58202.wrong \
+maputf.aff \
+maputf.dic \
+maputf.sug \
+maputf.wrong \
+maputf.test \
+reputf.aff \
+reputf.dic \
+reputf.sug \
+reputf.wrong \
+reputf.test \
+slash.aff \
+slash.dic \
+slash.good \
+slash.test \
+ignore.aff \
+ignore.dic \
+ignore.good \
+ignore.test \
+ignoreutf.aff \
+ignoreutf.dic \
+ignoreutf.good \
+ignoreutf.test \
+1592880.aff \
+1592880.dic \
+1592880.good \
+1592880.test \
+1695964.aff \
+1695964.dic \
+1695964.sug \
+1695964.test \
+1695964.wrong \
+1463589.aff \
+1463589.dic \
+1463589.sug \
+1463589.test \
+1463589.wrong \
+1463589_utf.aff \
+1463589_utf.dic \
+1463589_utf.sug \
+1463589_utf.test \
+1463589_utf.wrong \
+IJ.aff \
+IJ.dic \
+IJ.good \
+IJ.sug \
+IJ.test \
+IJ.wrong \
+i68568.aff \
+i68568.dic \
+i68568.test \
+i68568.wrong \
+i68568utf.aff \
+i68568utf.dic \
+i68568utf.test \
+i68568utf.wrong \
+1706659.aff \
+1706659.dic \
+1706659.test \
+1706659.wrong \
+digits_in_words.aff \
+digits_in_words.dic \
+digits_in_words.test \
+digits_in_words.wrong \
+colons_in_words.aff \
+colons_in_words.dic \
+colons_in_words.test \
+ngram_utf_fix.aff \
+ngram_utf_fix.dic \
+ngram_utf_fix.good \
+ngram_utf_fix.sug \
+ngram_utf_fix.test \
+ngram_utf_fix.wrong \
+morph.aff \
+morph.dic \
+morph.good \
+morph.morph \
+morph.test \
+1975530.aff \
+1975530.dic \
+1975530.good \
+1975530.test \
+1975530.wrong \
+fullstrip.aff \
+fullstrip.dic \
+fullstrip.good \
+fullstrip.test \
+iconv.aff \
+iconv.dic \
+iconv.good \
+iconv.test \
+oconv.aff \
+oconv.dic \
+oconv.good \
+oconv.sug \
+oconv.test \
+oconv.wrong \
+encoding.aff \
+encoding.dic \
+encoding.good \
+encoding.test \
+opentaal_forbiddenword1.aff \
+opentaal_forbiddenword1.dic \
+opentaal_forbiddenword1.good \
+opentaal_forbiddenword1.sug \
+opentaal_forbiddenword1.test \
+opentaal_forbiddenword1.wrong \
+opentaal_forbiddenword2.aff \
+opentaal_forbiddenword2.dic \
+opentaal_forbiddenword2.good \
+opentaal_forbiddenword2.sug \
+opentaal_forbiddenword2.test \
+opentaal_forbiddenword2.wrong \
+opentaal_forbiddenword2.aff \
+opentaal_forbiddenword2.dic \
+opentaal_forbiddenword2.good \
+opentaal_forbiddenword2.sug \
+opentaal_forbiddenword2.test \
+opentaal_forbiddenword2.wrong \
+opentaal_keepcase.aff \
+opentaal_keepcase.dic \
+opentaal_keepcase.good \
+opentaal_keepcase.sug \
+opentaal_keepcase.test \
+opentaal_keepcase.wrong \
+arabic.aff \
+arabic.dic \
+arabic.wrong \
+arabic.test \
+2970240.aff \
+2970240.dic \
+2970240.good \
+2970240.wrong \
+2970240.test \
+2970242.aff \
+2970242.dic \
+2970242.good \
+2970242.wrong \
+2970242.test \
+breakoff.aff \
+breakoff.dic \
+breakoff.good \
+breakoff.wrong \
+breakoff.test \
+opentaal_cpdpat.aff \
+opentaal_cpdpat.dic \
+opentaal_cpdpat.good \
+opentaal_cpdpat.wrong \
+opentaal_cpdpat.test \
+opentaal_cpdpat2.aff \
+opentaal_cpdpat2.dic \
+opentaal_cpdpat2.good \
+opentaal_cpdpat2.wrong \
+opentaal_cpdpat2.test \
+2999225.aff \
+2999225.dic \
+2999225.good \
+2999225.test \
+korean.aff \
+korean.dic \
+korean.good \
+korean.wrong \
+korean.test \
+onlyincompound2.aff \
+onlyincompound2.dic \
+onlyincompound2.good \
+onlyincompound2.test \
+onlyincompound2.wrong \
+forceucase.aff \
+forceucase.dic \
+forceucase.good \
+forceucase.sug \
+forceucase.wrong \
+forceucase.test \
+warn.aff \
+warn.dic \
+warn.good \
+warn.test
+
+# infixes.aff
+# infixes.dic
+# infixes.good
+# infixes.test
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/tests/Makefile.in
@@ -0,0 +1,1416 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = tests
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/codeset.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \
+	$(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \
+	$(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \
+	$(top_srcdir)/m4/inttypes-pri.m4 \
+	$(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \
+	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/longlong.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+	$(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/stdint_h.m4 \
+	$(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/visibility.m4 \
+	$(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \
+	$(top_srcdir)/m4/xsize.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-dvi-recursive install-exec-recursive \
+	install-html-recursive install-info-recursive \
+	install-pdf-recursive install-ps-recursive install-recursive \
+	installcheck-recursive installdirs-recursive pdf-recursive \
+	ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+	$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+	distdir
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSESLIB = @CURSESLIB@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENCAT = @GENCAT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GLIBC2 = @GLIBC2@
+GLIBC21 = @GLIBC21@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+HAVE_ASPRINTF = @HAVE_ASPRINTF@
+HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@
+HAVE_SNPRINTF = @HAVE_SNPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WPRINTF = @HAVE_WPRINTF@
+HUNSPELL_VERSION_MAJOR = @HUNSPELL_VERSION_MAJOR@
+HUNSPELL_VERSION_MINOR = @HUNSPELL_VERSION_MINOR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLBISON = @INTLBISON@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBPTH_PREFIX = @LIBPTH_PREFIX@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBC = @LTLIBC@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSUB = @POSUB@
+PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@
+RANLIB = @RANLIB@
+READLINELIB = @READLINELIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+WOE32 = @WOE32@
+WOE32DLL = @WOE32DLL@
+XFAILED = @XFAILED@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = suggestiontest
+XFAIL_TESTS = @XFAILED@
+TESTS = \
+affixes.test \
+condition.test \
+condition_utf.test \
+base.test \
+base_utf.test \
+allcaps.test \
+allcaps_utf.test \
+allcaps2.test \
+allcaps3.test \
+keepcase.test \
+i58202.test \
+map.test \
+rep.test \
+sug.test \
+sugutf.test \
+phone.test \
+flag.test \
+flaglong.test \
+flagnum.test \
+flagutf8.test \
+slash.test \
+forbiddenword.test \
+nosuggest.test \
+alias.test \
+alias2.test \
+alias3.test \
+breakdefault.test \
+break.test \
+needaffix.test \
+needaffix2.test \
+needaffix3.test \
+needaffix4.test \
+needaffix5.test \
+circumfix.test \
+fogemorpheme.test \
+onlyincompound.test \
+complexprefixes.test \
+complexprefixes2.test \
+complexprefixesutf.test \
+conditionalprefix.test \
+zeroaffix.test \
+utf8.test \
+utf8_bom.test \
+utf8_bom2.test \
+utf8_nonbmp.test \
+compoundflag.test \
+compoundrule.test \
+compoundrule2.test \
+compoundrule3.test \
+compoundrule4.test \
+compoundrule5.test \
+compoundrule6.test \
+compoundrule7.test \
+compoundrule8.test \
+compoundaffix.test \
+compoundaffix2.test \
+compoundaffix3.test \
+checkcompounddup.test \
+checkcompoundtriple.test \
+simplifiedtriple.test \
+checkcompoundrep.test \
+checkcompoundcase2.test \
+checkcompoundcaseutf.test \
+checkcompoundpattern.test \
+checkcompoundpattern2.test \
+checkcompoundpattern3.test \
+checkcompoundpattern4.test \
+utfcompound.test \
+checksharps.test \
+checksharpsutf.test \
+germancompounding.test \
+germancompoundingold.test \
+i35725.test \
+i53643.test \
+i54633.test \
+i54980.test \
+maputf.test \
+reputf.test \
+ignore.test \
+ignoreutf.test \
+1592880.test \
+1695964.test \
+1463589.test \
+1463589_utf.test \
+IJ.test \
+i68568.test \
+i68568utf.test \
+1706659.test \
+digits_in_words.test \
+colons_in_words.test \
+ngram_utf_fix.test \
+morph.test \
+1975530.test \
+fullstrip.test \
+iconv.test \
+oconv.test \
+encoding.test \
+korean.test \
+opentaal_forbiddenword1.test \
+opentaal_forbiddenword2.test \
+opentaal_keepcase.test \
+arabic.test \
+2970240.test \
+2970242.test \
+breakoff.test \
+opentaal_cpdpat.test \
+opentaal_cpdpat2.test \
+2999225.test \
+onlyincompound2.test \
+forceucase.test \
+warn.test
+
+EXTRA_DIST = \
+test.sh \
+affixes.aff \
+affixes.dic \
+affixes.good \
+affixes.test \
+condition.aff \
+condition.dic \
+condition.good \
+condition.test \
+condition.wrong \
+condition_utf.aff \
+condition_utf.dic \
+condition_utf.good \
+condition_utf.test \
+condition_utf.wrong \
+base.aff \
+base.dic \
+base.good \
+base.sug \
+base.test \
+base.wrong \
+base_utf.aff \
+base_utf.dic \
+base_utf.good \
+base_utf.sug \
+base_utf.test \
+base_utf.wrong \
+allcaps.aff \
+allcaps.dic \
+allcaps.good \
+allcaps.sug \
+allcaps.test \
+allcaps.wrong \
+allcaps2.aff \
+allcaps2.dic \
+allcaps2.good \
+allcaps2.sug \
+allcaps2.test \
+allcaps2.wrong \
+allcaps3.aff \
+allcaps3.dic \
+allcaps3.good \
+allcaps3.test \
+allcaps3.wrong \
+allcaps_utf.aff \
+allcaps_utf.dic \
+allcaps_utf.good \
+allcaps_utf.sug \
+allcaps_utf.test \
+allcaps_utf.wrong \
+keepcase.aff \
+keepcase.dic \
+keepcase.good \
+keepcase.sug \
+keepcase.test \
+keepcase.wrong \
+map.aff \
+map.dic \
+map.sug \
+map.test \
+map.wrong \
+rep.aff \
+rep.dic \
+rep.sug \
+rep.test \
+rep.wrong \
+sug.aff \
+sug.dic \
+sug.sug \
+sug.test \
+sug.wrong \
+sugutf.aff \
+sugutf.dic \
+sugutf.sug \
+sugutf.test \
+sugutf.wrong \
+phone.aff \
+phone.dic \
+phone.sug \
+phone.test \
+phone.wrong \
+alias.aff \
+alias.dic \
+alias.good \
+alias.test \
+alias2.aff \
+alias2.dic \
+alias2.good \
+alias2.morph \
+alias2.test \
+alias3.aff \
+alias3.dic \
+alias3.good \
+alias3.morph \
+alias3.test \
+break.aff \
+break.dic \
+break.good \
+break.test \
+break.wrong \
+breakdefault.aff \
+breakdefault.dic \
+breakdefault.good \
+breakdefault.sug \
+breakdefault.test \
+breakdefault.wrong \
+circumfix.aff \
+circumfix.dic \
+circumfix.good \
+circumfix.morph \
+circumfix.test \
+circumfix.wrong \
+fogemorpheme.aff \
+fogemorpheme.dic \
+fogemorpheme.good \
+fogemorpheme.test \
+fogemorpheme.wrong \
+onlyincompound.aff \
+onlyincompound.dic \
+onlyincompound.good \
+onlyincompound.sug \
+onlyincompound.test \
+onlyincompound.wrong \
+forbiddenword.aff \
+forbiddenword.dic \
+forbiddenword.good \
+forbiddenword.test \
+forbiddenword.wrong \
+nosuggest.aff \
+nosuggest.dic \
+nosuggest.good \
+nosuggest.sug \
+nosuggest.test \
+nosuggest.wrong \
+germancompounding.aff \
+germancompounding.dic \
+germancompounding.good \
+germancompounding.test \
+germancompounding.wrong \
+germancompoundingold.aff \
+germancompoundingold.dic \
+germancompoundingold.good \
+germancompoundingold.test \
+germancompoundingold.wrong \
+needaffix2.aff \
+needaffix2.dic \
+needaffix2.good \
+needaffix2.morph \
+needaffix2.test \
+needaffix3.aff \
+needaffix3.dic \
+needaffix3.good \
+needaffix3.test \
+needaffix3.wrong \
+needaffix4.aff \
+needaffix4.dic \
+needaffix4.good \
+needaffix4.test \
+needaffix5.aff \
+needaffix5.dic \
+needaffix5.good \
+needaffix5.test \
+needaffix5.wrong \
+needaffix.aff \
+needaffix.dic \
+needaffix.good \
+needaffix.test \
+needaffix.wrong \
+zeroaffix.aff \
+zeroaffix.dic \
+zeroaffix.good \
+zeroaffix.morph \
+zeroaffix.test \
+utf8.aff \
+utf8.dic \
+utf8.good \
+utf8.test \
+utf8_bom.aff \
+utf8_bom.dic \
+utf8_bom.good \
+utf8_bom.test \
+utf8_bom2.aff \
+utf8_bom2.dic \
+utf8_bom2.good \
+utf8_bom2.test \
+utf8_nonbmp.aff \
+utf8_nonbmp.dic \
+utf8_nonbmp.good \
+utf8_nonbmp.sug \
+utf8_nonbmp.test \
+utf8_nonbmp.wrong \
+utfcompound.aff \
+utfcompound.dic \
+utfcompound.good \
+utfcompound.test \
+utfcompound.wrong \
+compoundflag.aff \
+compoundflag.dic \
+compoundflag.good \
+compoundflag.test \
+compoundflag.wrong \
+compoundrule.aff \
+compoundrule.dic \
+compoundrule.good \
+compoundrule.test \
+compoundrule.wrong \
+compoundrule2.aff \
+compoundrule2.dic \
+compoundrule2.good \
+compoundrule2.test \
+compoundrule2.wrong \
+compoundrule3.aff \
+compoundrule3.dic \
+compoundrule3.good \
+compoundrule3.test \
+compoundrule3.wrong \
+compoundrule4.aff \
+compoundrule4.dic \
+compoundrule4.good \
+compoundrule4.test \
+compoundrule4.wrong \
+compoundrule5.aff \
+compoundrule5.dic \
+compoundrule5.good \
+compoundrule5.morph \
+compoundrule5.test \
+compoundrule5.wrong \
+compoundrule6.aff \
+compoundrule6.dic \
+compoundrule6.good \
+compoundrule6.test \
+compoundrule6.wrong \
+compoundrule7.aff \
+compoundrule7.dic \
+compoundrule7.good \
+compoundrule7.test \
+compoundrule7.wrong \
+compoundrule8.aff \
+compoundrule8.dic \
+compoundrule8.good \
+compoundrule8.test \
+compoundrule8.wrong \
+compoundaffix.aff \
+compoundaffix.dic \
+compoundaffix.good \
+compoundaffix.test \
+compoundaffix.wrong \
+compoundaffix2.aff \
+compoundaffix2.dic \
+compoundaffix2.good \
+compoundaffix2.test \
+compoundaffix3.aff \
+compoundaffix3.dic \
+compoundaffix3.good \
+compoundaffix3.test \
+compoundaffix3.wrong \
+checkcompounddup.aff \
+checkcompounddup.dic \
+checkcompounddup.good \
+checkcompounddup.test \
+checkcompounddup.wrong \
+checkcompoundcase.aff \
+checkcompoundcase.dic \
+checkcompoundcase.good \
+checkcompoundcase.test \
+checkcompoundcase.wrong \
+checkcompoundcase2.aff \
+checkcompoundcase2.dic \
+checkcompoundcase2.good \
+checkcompoundcase2.test \
+checkcompoundcase2.wrong \
+checkcompoundcaseutf.aff \
+checkcompoundcaseutf.dic \
+checkcompoundcaseutf.good \
+checkcompoundcaseutf.test \
+checkcompoundcaseutf.wrong \
+checkcompoundrep.aff \
+checkcompoundrep.dic \
+checkcompoundrep.good \
+checkcompoundrep.test \
+checkcompoundrep.wrong \
+checkcompoundtriple.aff \
+checkcompoundtriple.dic \
+checkcompoundtriple.good \
+checkcompoundtriple.test \
+checkcompoundtriple.wrong \
+simplifiedtriple.aff \
+simplifiedtriple.dic \
+simplifiedtriple.good \
+simplifiedtriple.test \
+simplifiedtriple.wrong \
+checkcompoundpattern.aff \
+checkcompoundpattern.dic \
+checkcompoundpattern.good \
+checkcompoundpattern.test \
+checkcompoundpattern.wrong \
+checkcompoundpattern2.aff \
+checkcompoundpattern2.dic \
+checkcompoundpattern2.good \
+checkcompoundpattern2.test \
+checkcompoundpattern2.wrong \
+checkcompoundpattern3.aff \
+checkcompoundpattern3.dic \
+checkcompoundpattern3.good \
+checkcompoundpattern3.test \
+checkcompoundpattern3.wrong \
+checkcompoundpattern4.aff \
+checkcompoundpattern4.dic \
+checkcompoundpattern4.good \
+checkcompoundpattern4.test \
+checkcompoundpattern4.wrong \
+checksharps.aff \
+checksharps.dic \
+checksharps.good \
+checksharps.sug \
+checksharps.test \
+checksharps.wrong \
+checksharpsutf.aff \
+checksharpsutf.dic \
+checksharpsutf.good \
+checksharpsutf.sug \
+checksharpsutf.test \
+checksharpsutf.wrong \
+conditionalprefix.aff \
+conditionalprefix.dic \
+conditionalprefix.good \
+conditionalprefix.morph \
+conditionalprefix.test \
+conditionalprefix.wrong \
+flaglong.aff \
+flaglong.dic \
+flaglong.good \
+flaglong.test \
+flagnum.aff \
+flagnum.dic \
+flagnum.good \
+flagnum.test \
+flag.aff \
+flag.dic \
+flag.good \
+flag.test \
+flagutf8.aff \
+flagutf8.dic \
+flagutf8.good \
+flagutf8.test \
+complexprefixes.aff \
+complexprefixes.dic \
+complexprefixes.good \
+complexprefixes.wrong \
+complexprefixes.test \
+complexprefixes2.aff \
+complexprefixes2.dic \
+complexprefixes2.good \
+complexprefixes2.test \
+complexprefixesutf.aff \
+complexprefixesutf.dic \
+complexprefixesutf.good \
+complexprefixesutf.wrong \
+complexprefixesutf.test \
+i35725.aff \
+i35725.dic \
+i35725.good \
+i35725.sug \
+i35725.test \
+i35725.wrong \
+i53643.aff \
+i53643.dic \
+i53643.good \
+i53643.test \
+i53643.wrong \
+i54633.aff \
+i54633.dic \
+i54633.good \
+i54633.sug \
+i54633.test \
+i54633.wrong \
+i54980.aff \
+i54980.dic \
+i54980.good \
+i54980.test \
+i58202.aff \
+i58202.dic \
+i58202.good \
+i58202.sug \
+i58202.test \
+i58202.wrong \
+maputf.aff \
+maputf.dic \
+maputf.sug \
+maputf.wrong \
+maputf.test \
+reputf.aff \
+reputf.dic \
+reputf.sug \
+reputf.wrong \
+reputf.test \
+slash.aff \
+slash.dic \
+slash.good \
+slash.test \
+ignore.aff \
+ignore.dic \
+ignore.good \
+ignore.test \
+ignoreutf.aff \
+ignoreutf.dic \
+ignoreutf.good \
+ignoreutf.test \
+1592880.aff \
+1592880.dic \
+1592880.good \
+1592880.test \
+1695964.aff \
+1695964.dic \
+1695964.sug \
+1695964.test \
+1695964.wrong \
+1463589.aff \
+1463589.dic \
+1463589.sug \
+1463589.test \
+1463589.wrong \
+1463589_utf.aff \
+1463589_utf.dic \
+1463589_utf.sug \
+1463589_utf.test \
+1463589_utf.wrong \
+IJ.aff \
+IJ.dic \
+IJ.good \
+IJ.sug \
+IJ.test \
+IJ.wrong \
+i68568.aff \
+i68568.dic \
+i68568.test \
+i68568.wrong \
+i68568utf.aff \
+i68568utf.dic \
+i68568utf.test \
+i68568utf.wrong \
+1706659.aff \
+1706659.dic \
+1706659.test \
+1706659.wrong \
+digits_in_words.aff \
+digits_in_words.dic \
+digits_in_words.test \
+digits_in_words.wrong \
+colons_in_words.aff \
+colons_in_words.dic \
+colons_in_words.test \
+ngram_utf_fix.aff \
+ngram_utf_fix.dic \
+ngram_utf_fix.good \
+ngram_utf_fix.sug \
+ngram_utf_fix.test \
+ngram_utf_fix.wrong \
+morph.aff \
+morph.dic \
+morph.good \
+morph.morph \
+morph.test \
+1975530.aff \
+1975530.dic \
+1975530.good \
+1975530.test \
+1975530.wrong \
+fullstrip.aff \
+fullstrip.dic \
+fullstrip.good \
+fullstrip.test \
+iconv.aff \
+iconv.dic \
+iconv.good \
+iconv.test \
+oconv.aff \
+oconv.dic \
+oconv.good \
+oconv.sug \
+oconv.test \
+oconv.wrong \
+encoding.aff \
+encoding.dic \
+encoding.good \
+encoding.test \
+opentaal_forbiddenword1.aff \
+opentaal_forbiddenword1.dic \
+opentaal_forbiddenword1.good \
+opentaal_forbiddenword1.sug \
+opentaal_forbiddenword1.test \
+opentaal_forbiddenword1.wrong \
+opentaal_forbiddenword2.aff \
+opentaal_forbiddenword2.dic \
+opentaal_forbiddenword2.good \
+opentaal_forbiddenword2.sug \
+opentaal_forbiddenword2.test \
+opentaal_forbiddenword2.wrong \
+opentaal_forbiddenword2.aff \
+opentaal_forbiddenword2.dic \
+opentaal_forbiddenword2.good \
+opentaal_forbiddenword2.sug \
+opentaal_forbiddenword2.test \
+opentaal_forbiddenword2.wrong \
+opentaal_keepcase.aff \
+opentaal_keepcase.dic \
+opentaal_keepcase.good \
+opentaal_keepcase.sug \
+opentaal_keepcase.test \
+opentaal_keepcase.wrong \
+arabic.aff \
+arabic.dic \
+arabic.wrong \
+arabic.test \
+2970240.aff \
+2970240.dic \
+2970240.good \
+2970240.wrong \
+2970240.test \
+2970242.aff \
+2970242.dic \
+2970242.good \
+2970242.wrong \
+2970242.test \
+breakoff.aff \
+breakoff.dic \
+breakoff.good \
+breakoff.wrong \
+breakoff.test \
+opentaal_cpdpat.aff \
+opentaal_cpdpat.dic \
+opentaal_cpdpat.good \
+opentaal_cpdpat.wrong \
+opentaal_cpdpat.test \
+opentaal_cpdpat2.aff \
+opentaal_cpdpat2.dic \
+opentaal_cpdpat2.good \
+opentaal_cpdpat2.wrong \
+opentaal_cpdpat2.test \
+2999225.aff \
+2999225.dic \
+2999225.good \
+2999225.test \
+korean.aff \
+korean.dic \
+korean.good \
+korean.wrong \
+korean.test \
+onlyincompound2.aff \
+onlyincompound2.dic \
+onlyincompound2.good \
+onlyincompound2.test \
+onlyincompound2.wrong \
+forceucase.aff \
+forceucase.dic \
+forceucase.good \
+forceucase.sug \
+forceucase.wrong \
+forceucase.test \
+warn.aff \
+warn.dic \
+warn.good \
+warn.test
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@fail= failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+	@fail= failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list=' $(TESTS) '; \
+	$(am__tty_colors); \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xpass=`expr $$xpass + 1`; \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=XPASS; \
+	      ;; \
+	      *) \
+		col=$$grn; res=PASS; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *[\ \	]$$tst[\ \	]*) \
+		xfail=`expr $$xfail + 1`; \
+		col=$$lgn; res=XFAIL; \
+	      ;; \
+	      *) \
+		failed=`expr $$failed + 1`; \
+		col=$$red; res=FAIL; \
+	      ;; \
+	      esac; \
+	    else \
+	      skip=`expr $$skip + 1`; \
+	      col=$$blu; res=SKIP; \
+	    fi; \
+	    echo "$${col}$$res$${std}: $$tst"; \
+	  done; \
+	  if test "$$all" -eq 1; then \
+	    tests="test"; \
+	    All=""; \
+	  else \
+	    tests="tests"; \
+	    All="All "; \
+	  fi; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="$$All$$all $$tests passed"; \
+	    else \
+	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all $$tests failed"; \
+	    else \
+	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+	    fi; \
+	  fi; \
+	  dashes="$$banner"; \
+	  skipped=""; \
+	  if test "$$skip" -ne 0; then \
+	    if test "$$skip" -eq 1; then \
+	      skipped="($$skip test was not run)"; \
+	    else \
+	      skipped="($$skip tests were not run)"; \
+	    fi; \
+	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$skipped"; \
+	  fi; \
+	  report=""; \
+	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+	    report="Please report to $(PACKAGE_BUGREPORT)"; \
+	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+	      dashes="$$report"; \
+	  fi; \
+	  dashes=`echo "$$dashes" | sed s/./=/g`; \
+	  if test "$$failed" -eq 0; then \
+	    echo "$$grn$$dashes"; \
+	  else \
+	    echo "$$red$$dashes"; \
+	  fi; \
+	  echo "$$banner"; \
+	  test -z "$$skipped" || echo "$$skipped"; \
+	  test -z "$$report" || echo "$$report"; \
+	  echo "$$dashes$$std"; \
+	  test "$$failed" -eq 0; \
+	else :; fi
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(MKDIR_P) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+