bug 641838 - decomtaminate accessible relations r=surkov sr=neil
☠☠ backed out by 86b0d5ce1a6d ☠ ☠
authorTrevor Saunders <trev.saunders@gmail.com>
Tue, 09 Aug 2011 18:44:00 -0700
changeset 74107 a00864f6c1a7122f46d74a974d200eedcd8c30fa
parent 74106 04dfb49d3a3d3469be379c76405f18f3592ac48b
child 74108 86b0d5ce1a6d6bf63844101d7b17075aa6c052a7
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewerssurkov, neil
bugs641838
milestone8.0a1
bug 641838 - decomtaminate accessible relations r=surkov sr=neil
accessible/src/atk/Makefile.in
accessible/src/atk/nsAccessibleRelationWrap.h
accessible/src/atk/nsAccessibleWrap.cpp
accessible/src/base/AccIterator.cpp
accessible/src/base/AccIterator.h
accessible/src/base/Makefile.in
accessible/src/base/Relation.h
accessible/src/base/nsARIAGridAccessible.cpp
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/base/nsAccessibleRelation.cpp
accessible/src/base/nsAccessibleRelation.h
accessible/src/base/nsApplicationAccessible.cpp
accessible/src/base/nsApplicationAccessible.h
accessible/src/base/nsCoreUtils.cpp
accessible/src/base/nsCoreUtils.h
accessible/src/base/nsDocAccessible.cpp
accessible/src/base/nsRelUtils.cpp
accessible/src/base/nsRelUtils.h
accessible/src/base/nsRootAccessible.cpp
accessible/src/base/nsRootAccessible.h
accessible/src/base/nsTextEquivUtils.cpp
accessible/src/html/nsHTMLFormControlAccessible.cpp
accessible/src/html/nsHTMLFormControlAccessible.h
accessible/src/html/nsHTMLTableAccessible.cpp
accessible/src/html/nsHTMLTableAccessible.h
accessible/src/html/nsHTMLTextAccessible.cpp
accessible/src/html/nsHTMLTextAccessible.h
accessible/src/mac/Makefile.in
accessible/src/mac/nsAccessibleRelationWrap.h
accessible/src/msaa/Makefile.in
accessible/src/msaa/ia2AccessibleRelation.cpp
accessible/src/msaa/ia2AccessibleRelation.h
accessible/src/msaa/nsAccessibleRelationWrap.cpp
accessible/src/msaa/nsAccessibleRelationWrap.h
accessible/src/msaa/nsAccessibleWrap.cpp
accessible/src/other/Makefile.in
accessible/src/other/nsAccessibleRelationWrap.h
accessible/src/xpcom/Makefile.in
accessible/src/xpcom/nsAccessibleRelation.cpp
accessible/src/xpcom/nsAccessibleRelation.h
accessible/src/xul/nsXULFormControlAccessible.cpp
accessible/src/xul/nsXULFormControlAccessible.h
accessible/src/xul/nsXULTabAccessible.cpp
accessible/src/xul/nsXULTabAccessible.h
accessible/src/xul/nsXULTextAccessible.cpp
accessible/src/xul/nsXULTextAccessible.h
accessible/src/xul/nsXULTreeAccessible.cpp
accessible/src/xul/nsXULTreeAccessible.h
--- a/accessible/src/atk/Makefile.in
+++ b/accessible/src/atk/Makefile.in
@@ -77,17 +77,16 @@ EXPORTS = \
   nsRootAccessibleWrap.h \
   nsTextAccessibleWrap.h \
   nsXULMenuAccessibleWrap.h \
   nsXULListboxAccessibleWrap.h \
   nsXULTreeGridAccessibleWrap.h \
   nsHyperTextAccessibleWrap.h \
   nsHTMLImageAccessibleWrap.h \
   nsHTMLTableAccessibleWrap.h \
-  nsAccessibleRelationWrap.h \
   $(NULL)
 
 # we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 CFLAGS		+= $(MOZ_GTK2_CFLAGS)
deleted file mode 100644
--- a/accessible/src/atk/nsAccessibleRelationWrap.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.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
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_ACCESSIBLE_RELATION_WRAP_H
-#define _NS_ACCESSIBLE_RELATION_WRAP_H
-
-#include "nsAccessibleRelation.h"
-
-typedef class nsAccessibleRelation nsAccessibleRelationWrap;
-
-#endif
-
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -33,29 +33,31 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsAccessible.h"
 #include "nsAccessibleWrap.h"
 
 #include "nsAccUtils.h"
 #include "nsApplicationAccessibleWrap.h"
+#include "nsIAccessibleRelation.h"
 #include "nsRootAccessible.h"
 #include "nsDocAccessibleWrap.h"
 #include "nsIAccessibleValue.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "prprf.h"
 #include "nsRoleMap.h"
-#include "nsRelUtils.h"
 #include "nsStateMap.h"
+#include "Relation.h"
 #include "States.h"
 
 #include "nsMaiInterfaceComponent.h"
 #include "nsMaiInterfaceAction.h"
 #include "nsMaiInterfaceText.h"
 #include "nsMaiInterfaceEditableText.h"
 #include "nsMaiInterfaceSelection.h"
 #include "nsMaiInterfaceValue.h"
@@ -936,70 +938,55 @@ refStateSetCB(AtkObject *aAtkObj)
     TranslateStates(accWrap->State(), state_set);
 
     return state_set;
 }
 
 AtkRelationSet *
 refRelationSetCB(AtkObject *aAtkObj)
 {
-    AtkRelationSet *relation_set = nsnull;
-    relation_set = ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
+  AtkRelationSet* relation_set =
+    ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
 
-    nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
-    if (!accWrap) {
-        return relation_set;
-    }
+  nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
+  if (!accWrap)
+    return relation_set;
 
-    AtkRelation* relation;
-    
-    PRUint32 relationType[] = {nsIAccessibleRelation::RELATION_LABELLED_BY,
-                               nsIAccessibleRelation::RELATION_LABEL_FOR,
-                               nsIAccessibleRelation::RELATION_NODE_CHILD_OF,
-                               nsIAccessibleRelation::RELATION_CONTROLLED_BY,
-                               nsIAccessibleRelation::RELATION_CONTROLLER_FOR,
-                               nsIAccessibleRelation::RELATION_EMBEDS,
-                               nsIAccessibleRelation::RELATION_FLOWS_TO,
-                               nsIAccessibleRelation::RELATION_FLOWS_FROM,
-                               nsIAccessibleRelation::RELATION_DESCRIBED_BY,
-                               nsIAccessibleRelation::RELATION_DESCRIPTION_FOR,
-                               };
+  PRUint32 relationTypes[] = {
+    nsIAccessibleRelation::RELATION_LABELLED_BY,
+    nsIAccessibleRelation::RELATION_LABEL_FOR,
+    nsIAccessibleRelation::RELATION_NODE_CHILD_OF,
+    nsIAccessibleRelation::RELATION_CONTROLLED_BY,
+    nsIAccessibleRelation::RELATION_CONTROLLER_FOR,
+    nsIAccessibleRelation::RELATION_EMBEDS,
+    nsIAccessibleRelation::RELATION_FLOWS_TO,
+    nsIAccessibleRelation::RELATION_FLOWS_FROM,
+    nsIAccessibleRelation::RELATION_DESCRIBED_BY,
+    nsIAccessibleRelation::RELATION_DESCRIPTION_FOR,
+  };
 
-    for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(relationType); i++) {
-        relation = atk_relation_set_get_relation_by_type(relation_set, static_cast<AtkRelationType>(relationType[i]));
-        if (relation) {
-            atk_relation_set_remove(relation_set, relation);
-        }
+  for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(relationTypes); i++) {
+    AtkRelationType atkType = static_cast<AtkRelationType>(relationTypes[i]);
+    AtkRelation* atkRelation =
+      atk_relation_set_get_relation_by_type(relation_set, atkType);
+    if (atkRelation)
+      atk_relation_set_remove(relation_set, atkRelation);
 
-        nsCOMPtr<nsIAccessibleRelation> geckoRelation;
-        nsresult rv = accWrap->GetRelationByType(relationType[i],
-                                                 getter_AddRefs(geckoRelation));
-        if (NS_SUCCEEDED(rv) && geckoRelation) {
-            PRUint32 targetsCount = 0;
-            geckoRelation->GetTargetsCount(&targetsCount);
-            if (targetsCount) {
-                AtkObject** accessible_array = new AtkObject*[targetsCount];
-                for (PRUint32 index = 0; index < targetsCount; index++) {
-                    nsCOMPtr<nsIAccessible> geckoTarget;
-                    geckoRelation->GetTarget(index, getter_AddRefs(geckoTarget));
-                    accessible_array[index] =
-                        nsAccessibleWrap::GetAtkObject(geckoTarget);
-                }
+    Relation rel(accWrap->RelationByType(relationTypes[i]));
+    nsTArray<AtkObject*> targets;
+    nsAccessible* tempAcc = nsnull;
+    while ((tempAcc = rel.Next()))
+      targets.AppendElement(nsAccessibleWrap::GetAtkObject(tempAcc));
 
-                relation = atk_relation_new(accessible_array, targetsCount,
-                                            static_cast<AtkRelationType>(relationType[i]));
-                atk_relation_set_add(relation_set, relation);
-                g_object_unref(relation);
+    atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
+    atk_relation_set_add(relation_set, atkRelation);
+    g_object_unref(atkRelation);
+  }
 
-                delete [] accessible_array;
-            }
-        }
-    }
-
-    return relation_set;
+  return relation_set;
 }
 
 // Check if aAtkObj is a valid MaiAtkObject, and return the nsAccessibleWrap
 // for it.
 nsAccessibleWrap *GetAccessibleWrap(AtkObject *aAtkObj)
 {
     NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nsnull);
     nsAccessibleWrap *tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
--- a/accessible/src/base/AccIterator.cpp
+++ b/accessible/src/base/AccIterator.cpp
@@ -35,16 +35,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "AccIterator.h"
 
 #include "nsAccessibilityService.h"
 #include "nsAccessible.h"
 
+#include "mozilla/dom/Element.h"
+
 ////////////////////////////////////////////////////////////////////////////////
 // AccIterator
 ////////////////////////////////////////////////////////////////////////////////
 
 AccIterator::AccIterator(nsAccessible *aAccessible,
                          filters::FilterFuncPtr aFilterFunc,
                          IterationType aIterationType) :
   mFilterFunc(aFilterFunc), mIsDeep(aIterationType != eFlatNav)
@@ -57,17 +59,17 @@ AccIterator::~AccIterator()
   while (mState) {
     IteratorState *tmp = mState;
     mState = tmp->mParentState;
     delete tmp;
   }
 }
 
 nsAccessible*
-AccIterator::GetNext()
+AccIterator::Next()
 {
   while (mState) {
     nsAccessible *child = mState->mParent->GetChildAt(mState->mIndex++);
     if (!child) {
       IteratorState *tmp = mState;
       mState = mState->mParentState;
       delete tmp;
 
@@ -250,8 +252,98 @@ XULDescriptionIterator::Next()
   nsAccessible* descr = nsnull;
   while ((descr = mRelIter.Next())) {
     if (descr->GetContent()->Tag() == nsAccessibilityAtoms::description)
       return descr;
   }
 
   return nsnull;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// IDRefsIterator
+////////////////////////////////////////////////////////////////////////////////
+
+IDRefsIterator::IDRefsIterator(nsIContent* aContent, nsIAtom* aIDRefsAttr) :
+  mCurrIdx(0)
+{
+  if (!aContent->IsInDoc() ||
+      !aContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs))
+    return;
+
+  if (aContent->IsInAnonymousSubtree()) {
+    mXBLDocument = do_QueryInterface(aContent->GetOwnerDoc());
+    mBindingParent = do_QueryInterface(aContent->GetBindingParent());
+  } else {
+    mDocument = aContent->GetOwnerDoc();
+  }
+}
+
+const nsDependentSubstring
+IDRefsIterator::NextID()
+{
+  for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
+    if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
+      break;
+  }
+
+  if (mCurrIdx >= mIDs.Length())
+    return nsDependentSubstring();
+
+  nsAString::index_type idStartIdx = mCurrIdx;
+  while (++mCurrIdx < mIDs.Length()) {
+    if (NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
+      break;
+  }
+
+  return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
+}
+
+nsIContent*
+IDRefsIterator::NextElem()
+{
+  while (true) {
+    const nsDependentSubstring id = NextID();
+    if (id.IsEmpty())
+      break;
+
+    nsIContent* refContent = GetElem(id);
+    if (refContent)
+      return refContent;
+  }
+
+  return nsnull;
+}
+
+nsIContent*
+IDRefsIterator::GetElem(const nsDependentSubstring& aID)
+{
+  if (mXBLDocument) {
+    // If content is anonymous subtree then use "anonid" attribute to get
+    // elements, otherwise search elements in DOM by ID attribute.
+
+    nsCOMPtr<nsIDOMElement> refElm;
+    mXBLDocument->GetAnonymousElementByAttribute(mBindingParent,
+                                                 NS_LITERAL_STRING("anonid"),
+                                                 aID,
+                                                 getter_AddRefs(refElm));
+    nsCOMPtr<nsIContent> refContent = do_QueryInterface(refElm);
+    return refContent;
+  }
+
+  return mDocument->GetElementById(aID);
+}
+
+nsAccessible*
+IDRefsIterator::Next()
+{
+  nsIContent* nextElm = NextElem();
+  return nextElm ? GetAccService()->GetAccessible(nextElm) : nsnull;
+}
+
+nsAccessible*
+SingleAccIterator::Next()
+{
+  nsRefPtr<nsAccessible> nextAcc;
+  mAcc.swap(nextAcc);
+  return (nextAcc && !nextAcc->IsDefunct()) ? nextAcc : nsnull;
+}
+
--- a/accessible/src/base/AccIterator.h
+++ b/accessible/src/base/AccIterator.h
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -33,25 +35,42 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsAccIterator_h_
 #define nsAccIterator_h_
 
+#include "nsAccessibilityService.h"
 #include "filters.h"
 #include "nscore.h"
 #include "nsDocAccessible.h"
 
+#include "nsIDOMDocumentXBL.h"
+
+/**
+ * AccIterable is a basic interface for iterators over accessibles.
+ */
+class AccIterable
+{
+public:
+  virtual ~AccIterable() { }
+  virtual nsAccessible* Next() = 0;
+
+private:
+  friend class Relation;
+  nsAutoPtr<AccIterable> mNextIter;
+};
+
 /**
  * Allows to iterate through accessible children or subtree complying with
  * filter function.
  */
-class AccIterator
+class AccIterator : public AccIterable
 {
 public:
   /**
    * Used to define iteration type.
    */
   enum IterationType {
     /**
      * Navigation happens through direct children.
@@ -62,23 +81,23 @@ public:
      * Navigation through subtree excluding iterator root; if the accessible
      * complies with filter, iterator ignores its children.
      */
     eTreeNav
   };
 
   AccIterator(nsAccessible* aRoot, filters::FilterFuncPtr aFilterFunc,
               IterationType aIterationType = eFlatNav);
-  ~AccIterator();
+  virtual ~AccIterator();
 
   /**
    * Return next accessible complying with filter function. Return the first
    * accessible for the first time.
    */
-  nsAccessible *GetNext();
+  virtual nsAccessible *Next();
 
 private:
   AccIterator();
   AccIterator(const AccIterator&);
   AccIterator& operator =(const AccIterator&);
 
   struct IteratorState
   {
@@ -94,36 +113,38 @@ private:
   IteratorState *mState;
 };
 
 
 /**
  * Allows to traverse through related accessibles that are pointing to the given
  * dependent accessible by relation attribute.
  */
-class RelatedAccIterator
+class RelatedAccIterator : public AccIterable
 {
 public:
   /**
    * Constructor.
    *
    * @param aDocument         [in] the document accessible the related
    * &                         accessibles belong to.
    * @param aDependentContent [in] the content of dependent accessible that
    *                           relations were requested for
    * @param aRelAttr          [in] relation attribute that relations are
    *                           pointed by
    */
   RelatedAccIterator(nsDocAccessible* aDocument, nsIContent* aDependentContent,
                      nsIAtom* aRelAttr);
 
+  virtual ~RelatedAccIterator() { }
+
   /**
    * Return next related accessible for the given dependent accessible.
    */
-  nsAccessible* Next();
+  virtual nsAccessible* Next();
 
 private:
   RelatedAccIterator();
   RelatedAccIterator(const RelatedAccIterator&);
   RelatedAccIterator& operator = (const RelatedAccIterator&);
 
   nsDocAccessible* mDocument;
   nsIAtom* mRelAttr;
@@ -131,101 +152,168 @@ private:
   nsIContent* mBindingParent;
   PRUint32 mIndex;
 };
 
 
 /**
  * Used to iterate through HTML labels associated with the given element.
  */
-class HTMLLabelIterator
+class HTMLLabelIterator : public AccIterable
 {
 public:
   enum LabelFilter {
     eAllLabels,
     eSkipAncestorLabel
   };
 
   HTMLLabelIterator(nsDocAccessible* aDocument, nsIContent* aElement,
                     LabelFilter aFilter = eAllLabels);
 
+  virtual ~HTMLLabelIterator() { }
+
   /**
    * Return next label accessible associated with the given element.
    */
-  nsAccessible* Next();
+  virtual nsAccessible* Next();
 
 private:
   HTMLLabelIterator();
   HTMLLabelIterator(const HTMLLabelIterator&);
   HTMLLabelIterator& operator = (const HTMLLabelIterator&);
 
   RelatedAccIterator mRelIter;
   nsIContent* mElement;
   LabelFilter mLabelFilter;
 };
 
 
 /**
  * Used to iterate through HTML outputs associated with the given element.
  */
-class HTMLOutputIterator
+class HTMLOutputIterator : public AccIterable
 {
 public:
   HTMLOutputIterator(nsDocAccessible* aDocument, nsIContent* aElement);
+  virtual ~HTMLOutputIterator() { }
 
   /**
    * Return next output accessible associated with the given element.
    */
-  nsAccessible* Next();
+  virtual nsAccessible* Next();
 
 private:
   HTMLOutputIterator();
   HTMLOutputIterator(const HTMLOutputIterator&);
   HTMLOutputIterator& operator = (const HTMLOutputIterator&);
 
   RelatedAccIterator mRelIter;
 };
 
 
 /**
  * Used to iterate through XUL labels associated with the given element.
  */
-class XULLabelIterator
+class XULLabelIterator : public AccIterable
 {
 public:
   XULLabelIterator(nsDocAccessible* aDocument, nsIContent* aElement);
+  virtual ~XULLabelIterator() { }
 
   /**
    * Return next label accessible associated with the given element.
    */
-  nsAccessible* Next();
+  virtual nsAccessible* Next();
 
 private:
   XULLabelIterator();
   XULLabelIterator(const XULLabelIterator&);
   XULLabelIterator& operator = (const XULLabelIterator&);
 
   RelatedAccIterator mRelIter;
 };
 
 
 /**
  * Used to iterate through XUL descriptions associated with the given element.
  */
-class XULDescriptionIterator
+class XULDescriptionIterator : public AccIterable
 {
 public:
   XULDescriptionIterator(nsDocAccessible* aDocument, nsIContent* aElement);
+  virtual ~XULDescriptionIterator() { }
 
   /**
    * Return next description accessible associated with the given element.
    */
-  nsAccessible* Next();
+  virtual nsAccessible* Next();
 
 private:
   XULDescriptionIterator();
   XULDescriptionIterator(const XULDescriptionIterator&);
   XULDescriptionIterator& operator = (const XULDescriptionIterator&);
 
   RelatedAccIterator mRelIter;
 };
 
+/**
+ * Used to iterate through IDs, elements or accessibles pointed by IDRefs
+ * attribute. Note, any method used to iterate through IDs, elements, or
+ * accessibles moves iterator to next position.
+ */
+class IDRefsIterator : public AccIterable
+{
+public:
+  IDRefsIterator(nsIContent* aContent, nsIAtom* aIDRefsAttr);
+  virtual ~IDRefsIterator() { }
+
+  /**
+   * Return next ID.
+   */
+  const nsDependentSubstring NextID();
+
+  /**
+   * Return next element.
+   */
+  nsIContent* NextElem();
+
+  /**
+   * Return the element with the given ID.
+   */
+  nsIContent* GetElem(const nsDependentSubstring& aID);
+
+  // AccIterable
+  virtual nsAccessible* Next();
+
+private:
+  IDRefsIterator();
+  IDRefsIterator(const IDRefsIterator&);
+  IDRefsIterator operator = (const IDRefsIterator&);
+
+  nsString mIDs;
+  nsAString::index_type mCurrIdx;
+
+  nsIDocument* mDocument;
+  nsCOMPtr<nsIDOMDocumentXBL> mXBLDocument;
+  nsCOMPtr<nsIDOMElement> mBindingParent;
+};
+
+/**
+ * Iterator that points to a single accessible returning it on the first call
+ * to Next().
+ */
+class SingleAccIterator : public AccIterable
+{
+public:
+  SingleAccIterator(nsAccessible* aTarget): mAcc(aTarget) { }
+  virtual ~SingleAccIterator() { }
+
+  virtual nsAccessible* Next();
+
+private:
+  SingleAccIterator();
+  SingleAccIterator(const SingleAccIterator&);
+  SingleAccIterator& operator = (const SingleAccIterator&);
+
+  nsRefPtr<nsAccessible> mAcc;
+};
+
 #endif
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -58,20 +58,18 @@ CPPSRCS = \
   nsAccessNode.cpp \
   nsARIAGridAccessible.cpp \
   nsARIAMap.cpp \
   nsDocAccessible.cpp \
   nsOuterDocAccessible.cpp \
   nsAccessibilityAtoms.cpp \
   nsCoreUtils.cpp \
   nsAccUtils.cpp \
-  nsRelUtils.cpp \
   nsAccessibilityService.cpp \
   nsAccessible.cpp \
-  nsAccessibleRelation.cpp \
   nsAccTreeWalker.cpp \
   nsBaseWidgetAccessible.cpp \
   nsEventShell.cpp \
   nsFormControlAccessible.cpp \
   nsRootAccessible.cpp \
   nsApplicationAccessible.cpp \
   nsCaretAccessible.cpp \
   nsTextAccessible.cpp \
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/Relation.h
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Trevor Saunders <trev.saunders@gmail.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
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef RELATION_H_
+#define RELATION_H_
+
+#include "AccIterator.h"
+
+/**
+ * This class is used to return Relation objects from functions.  A copy
+ * constructor doesn't work here because we need to mutate the old relation to
+ * have its nsAutoPtr forget what it points to.
+ */
+struct RelationCopyHelper
+{
+  RelationCopyHelper(AccIterable* aFirstIter, AccIterable* aLastIter) :
+    mFirstIter(aFirstIter), mLastIter(aLastIter) { }
+
+  AccIterable* mFirstIter;
+  AccIterable* mLastIter;
+};
+
+/**
+ * A collection of relation targets of a certain type.  Targets are computed
+ * lazily while enumerating.
+ */
+class Relation
+{
+public:
+  Relation() : mFirstIter(nsnull), mLastIter(nsnull) { }
+
+  Relation(const RelationCopyHelper aRelation) :
+    mFirstIter(aRelation.mFirstIter), mLastIter(aRelation.mLastIter) { }
+
+  Relation(AccIterable* aIter) : mFirstIter(aIter), mLastIter(aIter) { }
+
+  Relation(nsAccessible* aAcc) :
+    mFirstIter(nsnull), mLastIter(nsnull)
+    { AppendTarget(aAcc); }
+
+  Relation(nsIContent* aContent) :
+    mFirstIter(nsnull), mLastIter(nsnull)
+    { AppendTarget(aContent); }
+
+  Relation& operator = (const RelationCopyHelper& aRH)
+  {
+    mFirstIter = aRH.mFirstIter;
+    mLastIter = aRH.mLastIter;
+    return *this;
+  }
+
+  Relation& operator = (Relation& aRelation)
+  {
+    mFirstIter = aRelation.mFirstIter;
+    mLastIter = aRelation.mLastIter;
+    return *this;
+  }
+
+  operator RelationCopyHelper()
+  {
+    return RelationCopyHelper(mFirstIter.forget(), mLastIter);
+  }
+
+  inline void AppendIter(AccIterable* aIter)
+  {
+    if (mLastIter)
+      mLastIter->mNextIter = aIter;
+    else
+      mFirstIter = aIter;
+
+    mLastIter = aIter;
+  }
+
+  /**
+   * Append the given accessible to the set of related accessibles.
+   */
+  inline void AppendTarget(nsAccessible* aAcc)
+  {
+    if (aAcc)
+      AppendIter(new SingleAccIterator(aAcc));
+  }
+
+  /**
+   * Append the one accessible for this content node to the set of related
+   * accessibles.
+   */
+  inline void AppendTarget(nsIContent* aContent)
+  {
+    if (aContent)
+      AppendTarget(GetAccService()->GetAccessible(aContent));
+  }
+
+  /**
+   * compute and return the next related accessible.
+   */
+  inline nsAccessible* Next()
+  {
+    nsAccessible* target = nsnull;
+
+    // a trick nsAutoPtr deletes what it used to point to when assigned to
+    while (mFirstIter && !(target = mFirstIter->Next()))
+      mFirstIter = mFirstIter->mNextIter;
+
+    if (!mFirstIter)
+      mLastIter = nsnull;
+
+    return target;
+  }
+
+private:
+  Relation& operator = (const Relation&);
+
+  nsAutoPtr<AccIterable> mFirstIter;
+  AccIterable* mLastIter;
+};
+
+#endif
+
--- a/accessible/src/base/nsARIAGridAccessible.cpp
+++ b/accessible/src/base/nsARIAGridAccessible.cpp
@@ -101,40 +101,40 @@ nsARIAGridAccessible::GetColumnCount(PRI
 {
   NS_ENSURE_ARG_POINTER(acolumnCount);
   *acolumnCount = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
-  nsAccessible* row = rowIter.GetNext();
+  nsAccessible* row = rowIter.Next();
   if (!row)
     return NS_OK;
 
   AccIterator cellIter(row, filters::GetCell);
   nsAccessible *cell = nsnull;
 
-  while ((cell = cellIter.GetNext()))
+  while ((cell = cellIter.Next()))
     (*acolumnCount)++;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsARIAGridAccessible::GetRowCount(PRInt32 *arowCount)
 {
   NS_ENSURE_ARG_POINTER(arowCount);
   *arowCount = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
-  while (rowIter.GetNext())
+  while (rowIter.Next())
     (*arowCount)++;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsARIAGridAccessible::GetCellAt(PRInt32 aRowIndex, PRInt32 aColumnIndex,
                                 nsIAccessible **aAccessible)
@@ -322,30 +322,30 @@ nsARIAGridAccessible::IsColumnSelected(P
   *aIsSelected = PR_FALSE;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   NS_ENSURE_ARG(IsValidColumn(aColumn));
 
   AccIterator rowIter(this, filters::GetRow);
-  nsAccessible *row = rowIter.GetNext();
+  nsAccessible *row = rowIter.Next();
   if (!row)
     return NS_OK;
 
   do {
     if (!nsAccUtils::IsARIASelected(row)) {
       nsAccessible *cell = GetCellInRowAt(row, aColumn);
       if (!cell) // Do not fail due to wrong markup
         return NS_OK;
       
       if (!nsAccUtils::IsARIASelected(cell))
         return NS_OK;
     }
-  } while ((row = rowIter.GetNext()));
+  } while ((row = rowIter.Next()));
 
   *aIsSelected = PR_TRUE;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsARIAGridAccessible::IsRowSelected(PRInt32 aRow, PRBool *aIsSelected)
 {
@@ -356,17 +356,17 @@ nsARIAGridAccessible::IsRowSelected(PRIn
     return NS_ERROR_FAILURE;
 
   nsAccessible *row = GetRowAt(aRow);
   NS_ENSURE_ARG(row);
 
   if (!nsAccUtils::IsARIASelected(row)) {
     AccIterator cellIter(row, filters::GetCell);
     nsAccessible *cell = nsnull;
-    while ((cell = cellIter.GetNext())) {
+    while ((cell = cellIter.Next())) {
       if (!nsAccUtils::IsARIASelected(cell))
         return NS_OK;
     }
   }
 
   *aIsSelected = PR_TRUE;
   return NS_OK;
 }
@@ -406,26 +406,26 @@ nsARIAGridAccessible::GetSelectedCellCou
     return NS_ERROR_FAILURE;
 
   PRInt32 colCount = 0;
   GetColumnCount(&colCount);
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  while ((row = rowIter.GetNext())) {
+  while ((row = rowIter.Next())) {
     if (nsAccUtils::IsARIASelected(row)) {
       (*aCount) += colCount;
       continue;
     }
 
     AccIterator cellIter(row, filters::GetCell);
     nsAccessible *cell = nsnull;
 
-    while ((cell = cellIter.GetNext())) {
+    while ((cell = cellIter.Next())) {
       if (nsAccUtils::IsARIASelected(cell))
         (*aCount)++;
     }
   }
 
   return NS_OK;
 }
 
@@ -442,34 +442,34 @@ nsARIAGridAccessible::GetSelectedRowCoun
   *aCount = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  while ((row = rowIter.GetNext())) {
+  while ((row = rowIter.Next())) {
     if (nsAccUtils::IsARIASelected(row)) {
       (*aCount)++;
       continue;
     }
 
     AccIterator cellIter(row, filters::GetCell);
-    nsAccessible *cell = cellIter.GetNext();
+    nsAccessible *cell = cellIter.Next();
     if (!cell)
       continue;
 
     PRBool isRowSelected = PR_TRUE;
     do {
       if (!nsAccUtils::IsARIASelected(cell)) {
         isRowSelected = PR_FALSE;
         break;
       }
-    } while ((cell = cellIter.GetNext()));
+    } while ((cell = cellIter.Next()));
 
     if (isRowSelected)
       (*aCount)++;
   }
 
   return NS_OK;
 }
 
@@ -485,28 +485,28 @@ nsARIAGridAccessible::GetSelectedCells(n
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> selCells =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  while ((row = rowIter.GetNext())) {
+  while ((row = rowIter.Next())) {
     AccIterator cellIter(row, filters::GetCell);
     nsAccessible *cell = nsnull;
 
     if (nsAccUtils::IsARIASelected(row)) {
-      while ((cell = cellIter.GetNext()))
+      while ((cell = cellIter.Next()))
         selCells->AppendElement(static_cast<nsIAccessible *>(cell), PR_FALSE);
 
       continue;
     }
 
-    while ((cell = cellIter.GetNext())) {
+    while ((cell = cellIter.Next())) {
       if (nsAccUtils::IsARIASelected(cell))
         selCells->AppendElement(static_cast<nsIAccessible *>(cell), PR_FALSE);
     }
   }
 
   NS_ADDREF(*aCells = selCells);
   return NS_OK;
 }
@@ -529,28 +529,28 @@ nsARIAGridAccessible::GetSelectedCellInd
   PRInt32 colCount = 0;
   GetColumnCount(&colCount);
 
   nsTArray<PRInt32> selCells(rowCount * colCount);
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); rowIdx++) {
+  for (PRInt32 rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
     if (nsAccUtils::IsARIASelected(row)) {
       for (PRInt32 colIdx = 0; colIdx < colCount; colIdx++)
         selCells.AppendElement(rowIdx * colCount + colIdx);
 
       continue;
     }
 
     AccIterator cellIter(row, filters::GetCell);
     nsAccessible *cell = nsnull;
 
-    for (PRInt32 colIdx = 0; (cell = cellIter.GetNext()); colIdx++) {
+    for (PRInt32 colIdx = 0; (cell = cellIter.Next()); colIdx++) {
       if (nsAccUtils::IsARIASelected(cell))
         selCells.AppendElement(rowIdx * colCount + colIdx);
     }
   }
 
   PRUint32 selCellsCount = selCells.Length();
   if (!selCellsCount)
     return NS_OK;
@@ -589,34 +589,34 @@ nsARIAGridAccessible::GetSelectedRowIndi
   if (!rowCount)
     return NS_OK;
 
   nsTArray<PRInt32> selRows(rowCount);
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); rowIdx++) {
+  for (PRInt32 rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
     if (nsAccUtils::IsARIASelected(row)) {
       selRows.AppendElement(rowIdx);
       continue;
     }
 
     AccIterator cellIter(row, filters::GetCell);
-    nsAccessible *cell = cellIter.GetNext();
+    nsAccessible *cell = cellIter.Next();
     if (!cell)
       continue;
 
     PRBool isRowSelected = PR_TRUE;
     do {
       if (!nsAccUtils::IsARIASelected(cell)) {
         isRowSelected = PR_FALSE;
         break;
       }
-    } while ((cell = cellIter.GetNext()));
+    } while ((cell = cellIter.Next()));
 
     if (isRowSelected)
       selRows.AppendElement(rowIdx);
   }
 
   PRUint32 selrowCount = selRows.Length();
   if (!selrowCount)
     return NS_OK;
@@ -635,17 +635,17 @@ nsARIAGridAccessible::SelectRow(PRInt32 
   NS_ENSURE_ARG(IsValidRow(aRow));
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); rowIdx++) {
+  for (PRInt32 rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
     nsresult rv = SetARIASelected(row, rowIdx == aRow);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -654,17 +654,17 @@ nsARIAGridAccessible::SelectColumn(PRInt
   NS_ENSURE_ARG(IsValidColumn(aColumn));
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  while ((row = rowIter.GetNext())) {
+  while ((row = rowIter.Next())) {
     // Unselect all cells in the row.
     nsresult rv = SetARIASelected(row, PR_FALSE);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Select cell at the column index.
     nsAccessible *cell = GetCellInRowAt(row, aColumn);
     if (cell) {
       rv = SetARIASelected(cell, PR_TRUE);
@@ -693,17 +693,17 @@ nsARIAGridAccessible::UnselectColumn(PRI
   NS_ENSURE_ARG(IsValidColumn(aColumn));
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
 
   nsAccessible *row = nsnull;
-  while ((row = rowIter.GetNext())) {
+  while ((row = rowIter.Next())) {
     nsAccessible *cell = GetCellInRowAt(row, aColumn);
     if (cell) {
       nsresult rv = SetARIASelected(cell, PR_FALSE);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   return NS_OK;
@@ -761,31 +761,31 @@ nsARIAGridAccessible::IsValidRowNColumn(
 
 nsAccessible*
 nsARIAGridAccessible::GetRowAt(PRInt32 aRow)
 {
   PRInt32 rowIdx = aRow;
 
   AccIterator rowIter(this, filters::GetRow);
 
-  nsAccessible *row = rowIter.GetNext();
-  while (rowIdx != 0 && (row = rowIter.GetNext()))
+  nsAccessible *row = rowIter.Next();
+  while (rowIdx != 0 && (row = rowIter.Next()))
     rowIdx--;
 
   return row;
 }
 
 nsAccessible*
 nsARIAGridAccessible::GetCellInRowAt(nsAccessible *aRow, PRInt32 aColumn)
 {
   PRInt32 colIdx = aColumn;
 
   AccIterator cellIter(aRow, filters::GetCell);
-  nsAccessible *cell = cellIter.GetNext();
-  while (colIdx != 0 && (cell = cellIter.GetNext()))
+  nsAccessible *cell = cellIter.Next();
+  while (colIdx != 0 && (cell = cellIter.Next()))
     colIdx--;
 
   return cell;
 }
 
 nsresult
 nsARIAGridAccessible::SetARIASelected(nsAccessible *aAccessible,
                                       PRBool aIsSelected, PRBool aNotify)
@@ -816,17 +816,17 @@ nsARIAGridAccessible::SetARIASelected(ns
   PRUint32 role = aAccessible->Role();
 
   // If the given accessible is row that was unselected then remove
   // aria-selected from cell accessible.
   if (role == nsIAccessibleRole::ROLE_ROW) {
     AccIterator cellIter(aAccessible, filters::GetCell);
     nsAccessible *cell = nsnull;
 
-    while ((cell = cellIter.GetNext())) {
+    while ((cell = cellIter.Next())) {
       rv = SetARIASelected(cell, PR_FALSE, PR_FALSE);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     return NS_OK;
   }
 
   // If the given accessible is cell that was unselected and its row is selected
   // then remove aria-selected from row and put aria-selected on
@@ -838,17 +838,17 @@ nsARIAGridAccessible::SetARIASelected(ns
 
     if (row && row->Role() == nsIAccessibleRole::ROLE_ROW &&
         nsAccUtils::IsARIASelected(row)) {
       rv = SetARIASelected(row, PR_FALSE, PR_FALSE);
       NS_ENSURE_SUCCESS(rv, rv);
 
       AccIterator cellIter(row, filters::GetCell);
       nsAccessible *cell = nsnull;
-      while ((cell = cellIter.GetNext())) {
+      while ((cell = cellIter.Next())) {
         if (cell != aAccessible) {
           rv = SetARIASelected(cell, PR_TRUE, PR_FALSE);
           NS_ENSURE_SUCCESS(rv, rv);
         }
       }
     }
   }
 
@@ -863,17 +863,17 @@ nsARIAGridAccessible::GetSelectedColumns
   *acolumnCount = 0;
   if (aColumns)
     *aColumns = nsnull;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
-  nsAccessible *row = rowIter.GetNext();
+  nsAccessible *row = rowIter.Next();
   if (!row)
     return NS_OK;
 
   PRInt32 colCount = 0;
   GetColumnCount(&colCount);
   if (!colCount)
     return NS_OK;
 
@@ -887,24 +887,24 @@ nsARIAGridAccessible::GetSelectedColumns
   do {
     if (nsAccUtils::IsARIASelected(row))
       continue;
 
     PRInt32 colIdx = 0;
 
     AccIterator cellIter(row, filters::GetCell);
     nsAccessible *cell = nsnull;
-    for (colIdx = 0; (cell = cellIter.GetNext()); colIdx++) {
+    for (colIdx = 0; (cell = cellIter.Next()); colIdx++) {
       if (isColSelArray.SafeElementAt(colIdx, PR_FALSE) &&
           !nsAccUtils::IsARIASelected(cell)) {
         isColSelArray[colIdx] = PR_FALSE;
         selColCount--;
       }
     }
-  } while ((row = rowIter.GetNext()));
+  } while ((row = rowIter.Next()));
 
   if (!selColCount)
     return NS_OK;
 
   if (!aColumns) {
     *acolumnCount = selColCount;
     return NS_OK;
   }
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -43,20 +43,22 @@
 
 #include "AccGroupInfo.h"
 #include "AccIterator.h"
 #include "nsAccUtils.h"
 #include "nsDocAccessible.h"
 #include "nsEventShell.h"
 
 #include "nsAccEvent.h"
+#include "nsAccessibleRelation.h"
 #include "nsAccessibilityService.h"
 #include "nsAccTreeWalker.h"
-#include "nsRelUtils.h"
+#include "nsIAccessibleRelation.h"
 #include "nsTextEquivUtils.h"
+#include "Relation.h"
 #include "States.h"
 
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentXBL.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMNodeFilter.h"
@@ -1523,23 +1525,21 @@ nsAccessible::State()
                              nsAccessibilityAtoms::aria_selected,
                              nsAccessibilityAtoms::_false, eCaseMatters)) {
     // Special case: for tabs, focused implies selected, unless explicitly
     // false, i.e. aria-selected="false".
     if (state & states::FOCUSED) {
       state |= states::SELECTED;
     } else {
       // If focus is in a child of the tab panel surely the tab is selected!
-      nsCOMPtr<nsIAccessible> tabPanel = nsRelUtils::
-        GetRelatedAccessible(this, nsIAccessibleRelation::RELATION_LABEL_FOR);
-
-      if (nsAccUtils::Role(tabPanel) == nsIAccessibleRole::ROLE_PROPERTYPAGE) {
-        nsRefPtr<nsAccessible> tabPanelAcc(do_QueryObject(tabPanel));
-        nsINode *tabPanelNode = tabPanelAcc->GetNode();
-        if (nsCoreUtils::IsAncestorOf(tabPanelNode, gLastFocusedNode))
+      Relation rel = RelationByType(nsIAccessibleRelation::RELATION_LABEL_FOR);
+      nsAccessible* relTarget = nsnull;
+      while ((relTarget = rel.Next())) {
+        if (relTarget->Role() == nsIAccessibleRole::ROLE_PROPERTYPAGE &&
+            nsCoreUtils::IsAncestorOf(relTarget->GetNode(), gLastFocusedNode))
           state |= states::SELECTED;
       }
     }
   }
 
   const PRUint32 kExpandCollapseStates = states::COLLAPSED | states::EXPANDED;
   if ((state & kExpandCollapseStates) == kExpandCollapseStates) {
     // Cannot be both expanded and collapsed -- this happens in ARIA expanded
@@ -1825,21 +1825,21 @@ nsAccessible::ARIARoleInternal()
     }
 
   } else if (mRoleMapEntry->role == nsIAccessibleRole::ROLE_LISTBOX) {
     // A listbox inside of a combobox needs a special role because of ATK
     // mapping to menu.
     if (mParent && mParent->Role() == nsIAccessibleRole::ROLE_COMBOBOX) {
       return nsIAccessibleRole::ROLE_COMBOBOX_LIST;
 
-      nsCOMPtr<nsIAccessible> possibleCombo =
-        nsRelUtils::GetRelatedAccessible(this,
-                                         nsIAccessibleRelation::RELATION_NODE_CHILD_OF);
-      if (nsAccUtils::Role(possibleCombo) == nsIAccessibleRole::ROLE_COMBOBOX)
-        return nsIAccessibleRole::ROLE_COMBOBOX_LIST;
+      Relation rel = RelationByType(nsIAccessibleRelation::RELATION_NODE_CHILD_OF);
+      nsAccessible* targetAcc = nsnull;
+      while ((targetAcc = rel.Next()))
+        if (targetAcc->Role() == nsIAccessibleRole::ROLE_COMBOBOX)
+          return nsIAccessibleRole::ROLE_COMBOBOX_LIST;
     }
 
   } else if (mRoleMapEntry->role == nsIAccessibleRole::ROLE_OPTION) {
     if (mParent && mParent->Role() == nsIAccessibleRole::ROLE_COMBOBOX_LIST)
       return nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
   }
 
   return mRoleMapEntry->role;
@@ -1993,252 +1993,153 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
 }
 
 /* nsIAccessible getAccessibleBelow(); */
 NS_IMETHODIMP nsAccessible::GetAccessibleBelow(nsIAccessible **_retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-nsIDOMNode* nsAccessible::GetAtomicRegion()
+nsIContent*
+nsAccessible::GetAtomicRegion() const
 {
   nsIContent *loopContent = mContent;
   nsAutoString atomic;
-  while (loopContent && !loopContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic, atomic)) {
+  while (loopContent && !loopContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic, atomic))
     loopContent = loopContent->GetParent();
-  }
-
-  nsCOMPtr<nsIDOMNode> atomicRegion;
-  if (atomic.EqualsLiteral("true")) {
-    atomicRegion = do_QueryInterface(loopContent);
-  }
-  return atomicRegion;
+
+  return atomic.EqualsLiteral("true") ? loopContent : nsnull;
 }
 
 // nsIAccessible getRelationByType()
 NS_IMETHODIMP
-nsAccessible::GetRelationByType(PRUint32 aRelationType,
-                                nsIAccessibleRelation **aRelation)
+nsAccessible::GetRelationByType(PRUint32 aType,
+                                nsIAccessibleRelation** aRelation)
 {
   NS_ENSURE_ARG_POINTER(aRelation);
   *aRelation = nsnull;
-
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
+  Relation rel = RelationByType(aType);
+  NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &rel));
+  return *aRelation ? NS_OK : NS_ERROR_FAILURE;
+}
+
+Relation
+nsAccessible::RelationByType(PRUint32 aType)
+{
   // Relationships are defined on the same content node that the role would be
   // defined on.
-  nsresult rv = NS_OK_NO_RELATION_TARGET;
-  switch (aRelationType)
-  {
-  case nsIAccessibleRelation::RELATION_LABEL_FOR:
-    {
-      RelatedAccIterator iter(GetDocAccessible(), mContent,
-                              nsAccessibilityAtoms::aria_labelledby);
-
-      nsAccessible* related = nsnull;
-      while ((related = iter.Next())) {
-        rv = nsRelUtils::AddTarget(aRelationType, aRelation, related);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      if (mContent->Tag() == nsAccessibilityAtoms::label) {
-        nsIAtom *IDAttr = mContent->IsHTML() ?
-          nsAccessibilityAtoms::_for : nsAccessibilityAtoms::control;
-        rv = nsRelUtils::
-          AddTargetFromIDRefAttr(aRelationType, aRelation, mContent, IDAttr);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-      return rv;
+  switch (aType) {
+    case nsIAccessibleRelation::RELATION_LABEL_FOR: {
+      Relation rel(new RelatedAccIterator(GetDocAccessible(), mContent,
+                                          nsAccessibilityAtoms::aria_labelledby));
+      if (mContent->Tag() == nsAccessibilityAtoms::label)
+        rel.AppendIter(new IDRefsIterator(mContent, mContent->IsHTML() ?
+                                          nsAccessibilityAtoms::_for :
+                                          nsAccessibilityAtoms::control));
+
+      return rel;
     }
-
-  case nsIAccessibleRelation::RELATION_LABELLED_BY:
-    {
-      rv = nsRelUtils::
-        AddTargetFromIDRefsAttr(aRelationType, aRelation, mContent,
-                                nsAccessibilityAtoms::aria_labelledby);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsAccessible* label = nsnull;
+    case nsIAccessibleRelation::RELATION_LABELLED_BY: {
+      Relation rel(new IDRefsIterator(mContent,
+                                      nsAccessibilityAtoms::aria_labelledby));
       if (mContent->IsHTML()) {
-        HTMLLabelIterator iter(GetDocAccessible(), mContent);
-        while ((label = iter.Next())) {
-          rv = nsRelUtils::AddTarget(aRelationType, aRelation, label);
-          NS_ENSURE_SUCCESS(rv, rv);
-        }
-        return rv;
+        rel.AppendIter(new HTMLLabelIterator(GetDocAccessible(), mContent));
+      } else if (mContent->IsXUL()) {
+        rel.AppendIter(new XULLabelIterator(GetDocAccessible(), mContent));
       }
 
-      if (mContent->IsXUL()) {
-        XULLabelIterator iter(GetDocAccessible(), mContent);
-        while ((label = iter.Next())) {
-          rv = nsRelUtils::AddTarget(aRelationType, aRelation, label);
-          NS_ENSURE_SUCCESS(rv, rv);
-        }
-      }
-      return rv;
+      return rel;
     }
-
-  case nsIAccessibleRelation::RELATION_DESCRIBED_BY:
-    {
-      rv = nsRelUtils::
-        AddTargetFromIDRefsAttr(aRelationType, aRelation, mContent,
-                                nsAccessibilityAtoms::aria_describedby);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (mContent->IsXUL()) {
-        XULDescriptionIterator iter(GetDocAccessible(), mContent);
-        nsAccessible* descr = nsnull;
-        while ((descr = iter.Next())) {
-          rv = nsRelUtils::AddTarget(aRelationType, aRelation, descr);
-          NS_ENSURE_SUCCESS(rv, rv);
-        }
-      }
-
-      return rv;
+    case nsIAccessibleRelation::RELATION_DESCRIBED_BY: {
+      Relation rel(new IDRefsIterator(mContent,
+                                        nsAccessibilityAtoms::aria_describedby));
+      if (mContent->IsXUL())
+        rel.AppendIter(new XULDescriptionIterator(GetDocAccessible(), mContent));
+
+      return rel;
     }
-
-  case nsIAccessibleRelation::RELATION_DESCRIPTION_FOR:
-    {
-      RelatedAccIterator iter(GetDocAccessible(), mContent,
-                              nsAccessibilityAtoms::aria_describedby);
-
-      nsAccessible* related = nsnull;
-      while ((related = iter.Next())) {
-        rv = nsRelUtils::AddTarget(aRelationType, aRelation, related);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
+    case nsIAccessibleRelation::RELATION_DESCRIPTION_FOR: {
+      Relation rel(new RelatedAccIterator(GetDocAccessible(), mContent,
+                                            nsAccessibilityAtoms::aria_describedby));
+
+      // This affectively adds an optional control attribute to xul:description,
+      // which only affects accessibility, by allowing the description to be
+      // tied to a control.
       if (mContent->Tag() == nsAccessibilityAtoms::description &&
-          mContent->IsXUL()) {
-        // This affectively adds an optional control attribute to xul:description,
-        // which only affects accessibility, by allowing the description to be
-        // tied to a control.
-        return nsRelUtils::
-          AddTargetFromIDRefAttr(aRelationType, aRelation, mContent,
-                                 nsAccessibilityAtoms::control);
-      }
-
-      return rv;
+          mContent->IsXUL())
+        rel.AppendIter(new IDRefsIterator(mContent,
+                                          nsAccessibilityAtoms::control));
+
+      return rel;
     }
-
-  case nsIAccessibleRelation::RELATION_NODE_CHILD_OF:
-    {
-      RelatedAccIterator iter(GetDocAccessible(), mContent,
-                              nsAccessibilityAtoms::aria_owns);
-
-      nsAccessible* related = nsnull;
-      while ((related = iter.Next())) {
-        rv = nsRelUtils::AddTarget(aRelationType, aRelation, related);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      // Got relation from aria-owns, don't calculate it from native markup.
-      if (rv != NS_OK_NO_RELATION_TARGET)
-        return NS_OK;
-
+    case nsIAccessibleRelation::RELATION_NODE_CHILD_OF: {
+      Relation rel(new RelatedAccIterator(GetDocAccessible(), mContent,
+                                            nsAccessibilityAtoms::aria_owns));
+      
       // This is an ARIA tree or treegrid that doesn't use owns, so we need to
       // get the parent the hard way.
       if (mRoleMapEntry &&
           (mRoleMapEntry->role == nsIAccessibleRole::ROLE_OUTLINEITEM ||
            mRoleMapEntry->role == nsIAccessibleRole::ROLE_ROW)) {
-
         AccGroupInfo* groupInfo = GetGroupInfo();
         if (!groupInfo)
-          return NS_OK_NO_RELATION_TARGET;
-
-        return nsRelUtils::AddTarget(aRelationType, aRelation,
-                                     groupInfo->ConceptualParent());
+          return rel;
+
+        rel.AppendTarget(groupInfo->ConceptualParent());
       }
 
       // If accessible is in its own Window, or is the root of a document,
       // then we should provide NODE_CHILD_OF relation so that MSAA clients
       // can easily get to true parent instead of getting to oleacc's
       // ROLE_WINDOW accessible which will prevent us from going up further
       // (because it is system generated and has no idea about the hierarchy
       // above it).
       nsIFrame *frame = GetFrame();
       if (frame) {
         nsIView *view = frame->GetViewExternal();
         if (view) {
           nsIScrollableFrame *scrollFrame = do_QueryFrame(frame);
           if (scrollFrame || view->GetWidget() || !frame->GetParent())
-            return nsRelUtils::AddTarget(aRelationType, aRelation, Parent());
+            rel.AppendTarget(Parent());
         }
       }
 
-      return rv;
-    }
-
-  case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
-    {
-      RelatedAccIterator iter(GetDocAccessible(), mContent,
-                              nsAccessibilityAtoms::aria_controls);
-
-      nsAccessible* related = nsnull;
-      while ((related = iter.Next())) {
-        rv = nsRelUtils::AddTarget(aRelationType, aRelation, related);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-      return rv;
+      return rel;
     }
-
-  case nsIAccessibleRelation::RELATION_CONTROLLER_FOR:
-    {
-      nsresult rv = nsRelUtils::
-        AddTargetFromIDRefsAttr(aRelationType, aRelation, mContent,
-                                nsAccessibilityAtoms::aria_controls);
-      NS_ENSURE_SUCCESS(rv,rv);
-
-      HTMLOutputIterator iter(GetDocAccessible(), mContent);
-      nsAccessible* related = nsnull;
-      while ((related = iter.Next())) {
-        rv = nsRelUtils::AddTarget(aRelationType, aRelation, related);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      return rv;
+    case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
+      return Relation(new RelatedAccIterator(GetDocAccessible(), mContent,
+                                             nsAccessibilityAtoms::aria_controls));
+    case nsIAccessibleRelation::RELATION_CONTROLLER_FOR: {
+      Relation rel(new IDRefsIterator(mContent,
+                                      nsAccessibilityAtoms::aria_controls));
+      rel.AppendIter(new HTMLOutputIterator(GetDocAccessible(), mContent));
+      return rel;
     }
-
-  case nsIAccessibleRelation::RELATION_FLOWS_TO:
-    {
-      return nsRelUtils::
-        AddTargetFromIDRefsAttr(aRelationType, aRelation, mContent,
-                                nsAccessibilityAtoms::aria_flowto);
-    }
-
-  case nsIAccessibleRelation::RELATION_FLOWS_FROM:
-    {
-      RelatedAccIterator iter(GetDocAccessible(), mContent,
-                              nsAccessibilityAtoms::aria_flowto);
-
-      nsAccessible* related = nsnull;
-      while ((related = iter.Next())) {
-        rv = nsRelUtils::AddTarget(aRelationType, aRelation, related);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-      return rv;
-    }
-
-  case nsIAccessibleRelation::RELATION_DEFAULT_BUTTON:
-    {
+    case nsIAccessibleRelation::RELATION_FLOWS_TO:
+      return Relation(new IDRefsIterator(mContent,
+                                         nsAccessibilityAtoms::aria_flowto));
+    case nsIAccessibleRelation::RELATION_FLOWS_FROM:
+      return Relation(new RelatedAccIterator(GetDocAccessible(), mContent,
+                                             nsAccessibilityAtoms::aria_flowto));
+    case nsIAccessibleRelation::RELATION_DEFAULT_BUTTON: {
       if (mContent->IsHTML()) {
         // HTML form controls implements nsIFormControl interface.
         nsCOMPtr<nsIFormControl> control(do_QueryInterface(mContent));
         if (control) {
           nsCOMPtr<nsIForm> form(do_QueryInterface(control->GetFormElement()));
           if (form) {
             nsCOMPtr<nsIContent> formContent =
               do_QueryInterface(form->GetDefaultSubmitElement());
-            return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
-                                                    formContent);
+            return Relation(formContent);
           }
         }
-      }
-      else {
+      } else {
         // In XUL, use first <button default="true" .../> in the document
         nsCOMPtr<nsIDOMXULDocument> xulDoc =
           do_QueryInterface(mContent->GetOwnerDoc());
         nsCOMPtr<nsIDOMXULButtonElement> buttonEl;
         if (xulDoc) {
           nsCOMPtr<nsIDOMNodeList> possibleDefaultButtons;
           xulDoc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
                                          NS_LITERAL_STRING("true"),
@@ -2266,98 +2167,92 @@ nsAccessible::GetRelationByType(PRUint32
                                                       NS_LITERAL_STRING("default"),
                                                       NS_LITERAL_STRING("true"),
                                                       getter_AddRefs(possibleButtonEl));
                 buttonEl = do_QueryInterface(possibleButtonEl);
               }
             }
           }
           nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl));
-          return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
-                                                  relatedContent);
+          return Relation(relatedContent);
         }
       }
-      return NS_OK;
-    }
-
-  case nsIAccessibleRelation::RELATION_MEMBER_OF:
-    {
-      nsCOMPtr<nsIContent> regionContent = do_QueryInterface(GetAtomicRegion());
-      return nsRelUtils::
-        AddTargetFromContent(aRelationType, aRelation, regionContent);
+      return Relation();
     }
-
-  case nsIAccessibleRelation::RELATION_SUBWINDOW_OF:
-  case nsIAccessibleRelation::RELATION_EMBEDS:
-  case nsIAccessibleRelation::RELATION_EMBEDDED_BY:
-  case nsIAccessibleRelation::RELATION_POPUP_FOR:
-  case nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF:
-    {
-      return NS_OK_NO_RELATION_TARGET;
-    }
-
-  default:
-    return NS_ERROR_INVALID_ARG;
+    case nsIAccessibleRelation::RELATION_MEMBER_OF:
+      return Relation(GetAtomicRegion());
+    case nsIAccessibleRelation::RELATION_SUBWINDOW_OF:
+    case nsIAccessibleRelation::RELATION_EMBEDS:
+    case nsIAccessibleRelation::RELATION_EMBEDDED_BY:
+    case nsIAccessibleRelation::RELATION_POPUP_FOR:
+    case nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF:
+    default:
+    return Relation();
   }
 }
 
 NS_IMETHODIMP
-nsAccessible::GetRelationsCount(PRUint32 *aCount)
+nsAccessible::GetRelationsCount(PRUint32* aCount)
 {
   NS_ENSURE_ARG_POINTER(aCount);
   *aCount = 0;
 
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   nsCOMPtr<nsIArray> relations;
   nsresult rv = GetRelations(getter_AddRefs(relations));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return relations->GetLength(aCount);
 }
 
 NS_IMETHODIMP
-nsAccessible::GetRelation(PRUint32 aIndex, nsIAccessibleRelation **aRelation)
+nsAccessible::GetRelation(PRUint32 aIndex, nsIAccessibleRelation** aRelation)
 {
   NS_ENSURE_ARG_POINTER(aRelation);
   *aRelation = nsnull;
 
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   nsCOMPtr<nsIArray> relations;
-  nsresult rv = GetRelations(getter_AddRefs(relations));
+  nsresult rv= GetRelations(getter_AddRefs(relations));
   NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIAccessibleRelation> relation;
-  rv = relations->QueryElementAt(aIndex, NS_GET_IID(nsIAccessibleRelation),
-                                 getter_AddRefs(relation));
-
-  // nsIArray::QueryElementAt() returns NS_ERROR_ILLEGAL_VALUE on invalid index.
-  if (rv == NS_ERROR_ILLEGAL_VALUE)
-    return NS_ERROR_INVALID_ARG;
-
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_IF_ADDREF(*aRelation = relation);
-  return NS_OK;
+  nsCOMPtr<nsIAccessibleRelation> relation = do_QueryElementAt(relations,
+                                                               aIndex, &rv);
+  NS_ADDREF(*aRelation = relation);
+  return rv;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetRelations(nsIArray **aRelations)
 {
   NS_ENSURE_ARG_POINTER(aRelations);
+  *aRelations = nsnull;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIMutableArray> relations = do_CreateInstance(NS_ARRAY_CONTRACTID);
   NS_ENSURE_TRUE(relations, NS_ERROR_OUT_OF_MEMORY);
 
   for (PRUint32 relType = nsIAccessibleRelation::RELATION_FIRST;
        relType < nsIAccessibleRelation::RELATION_LAST;
        ++relType) {
 
     nsCOMPtr<nsIAccessibleRelation> relation;
     nsresult rv = GetRelationByType(relType, getter_AddRefs(relation));
 
-    if (NS_SUCCEEDED(rv) && relation)
-      relations->AppendElement(relation, PR_FALSE);
+    if (NS_SUCCEEDED(rv) && relation) {
+      PRUint32 targets = 0;
+      relation->GetTargetsCount(&targets);
+      if (targets)
+        relations->AppendElement(relation, PR_FALSE);
+    }
   }
 
   NS_ADDREF(*aRelations = relations);
   return NS_OK;
 }
 
 /* void extendSelection (); */
 NS_IMETHODIMP nsAccessible::ExtendSelection()
@@ -2969,114 +2864,114 @@ already_AddRefed<nsIArray>
 nsAccessible::SelectedItems()
 {
   nsCOMPtr<nsIMutableArray> selectedItems = do_CreateInstance(NS_ARRAY_CONTRACTID);
   if (!selectedItems)
     return nsnull;
 
   AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
   nsIAccessible* selected = nsnull;
-  while ((selected = iter.GetNext()))
+  while ((selected = iter.Next()))
     selectedItems->AppendElement(selected, PR_FALSE);
 
   nsIMutableArray* items = nsnull;
   selectedItems.forget(&items);
   return items;
 }
 
 PRUint32
 nsAccessible::SelectedItemCount()
 {
   PRUint32 count = 0;
   AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
   nsAccessible* selected = nsnull;
-  while ((selected = iter.GetNext()))
+  while ((selected = iter.Next()))
     ++count;
 
   return count;
 }
 
 nsAccessible*
 nsAccessible::GetSelectedItem(PRUint32 aIndex)
 {
   AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
   nsAccessible* selected = nsnull;
 
   PRUint32 index = 0;
-  while ((selected = iter.GetNext()) && index < aIndex)
+  while ((selected = iter.Next()) && index < aIndex)
     index++;
 
   return selected;
 }
 
 bool
 nsAccessible::IsItemSelected(PRUint32 aIndex)
 {
   PRUint32 index = 0;
   AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
   nsAccessible* selected = nsnull;
-  while ((selected = iter.GetNext()) && index < aIndex)
+  while ((selected = iter.Next()) && index < aIndex)
     index++;
 
   return selected &&
     selected->State() & states::SELECTED;
 }
 
 bool
 nsAccessible::AddItemToSelection(PRUint32 aIndex)
 {
   PRUint32 index = 0;
   AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
   nsAccessible* selected = nsnull;
-  while ((selected = iter.GetNext()) && index < aIndex)
+  while ((selected = iter.Next()) && index < aIndex)
     index++;
 
   if (selected)
     selected->SetSelected(PR_TRUE);
 
   return static_cast<bool>(selected);
 }
 
 bool
 nsAccessible::RemoveItemFromSelection(PRUint32 aIndex)
 {
   PRUint32 index = 0;
   AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
   nsAccessible* selected = nsnull;
-  while ((selected = iter.GetNext()) && index < aIndex)
+  while ((selected = iter.Next()) && index < aIndex)
     index++;
 
   if (selected)
     selected->SetSelected(PR_FALSE);
 
   return static_cast<bool>(selected);
 }
 
 bool
 nsAccessible::SelectAll()
 {
   bool success = false;
   nsAccessible* selectable = nsnull;
 
   AccIterator iter(this, filters::GetSelectable, AccIterator::eTreeNav);
-  while((selectable = iter.GetNext())) {
+  while((selectable = iter.Next())) {
     success = true;
     selectable->SetSelected(PR_TRUE);
   }
   return success;
 }
 
 bool
 nsAccessible::UnselectAll()
 {
   bool success = false;
   nsAccessible* selected = nsnull;
 
   AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
-  while ((selected = iter.GetNext())) {
+  while ((selected = iter.Next())) {
     success = true;
     selected->SetSelected(PR_FALSE);
   }
   return success;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -57,16 +57,17 @@
 class AccEvent;
 class AccGroupInfo;
 class EmbeddedObjCollector;
 class KeyBinding;
 class nsAccessible;
 class nsHyperTextAccessible;
 class nsHTMLLIAccessible;
 struct nsRoleMapEntry;
+class Relation;
 class nsTextAccessible;
 
 struct nsRect;
 class nsIContent;
 class nsIFrame;
 class nsIAtom;
 class nsIView;
 
@@ -232,16 +233,21 @@ public:
    * on accessible hierarchy.
    *
    * @param  aPosInSet  [out] accessible position in the group
    * @param  aSetSize   [out] the group size
    */
   virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
                                           PRInt32 *aSetSize);
 
+  /**
+   * Get the relation of the given type.
+   */
+  virtual Relation RelationByType(PRUint32 aType);
+
   //////////////////////////////////////////////////////////////////////////////
   // Initializing methods
 
   /**
    * Set the ARIA role map entry for a new accessible.
    * For a newly created accessible, specify which role map entry should be used.
    *
    * @param aRoleMapEntry The ARIA nsRoleMapEntry* for the accessible, or 
@@ -662,17 +668,17 @@ protected:
 
   //////////////////////////////////////////////////////////////////////////////
   // Helpers
 
   /**
    *  Get the container node for an atomic region, defined by aria-atomic="true"
    *  @return the container node
    */
-  nsIDOMNode* GetAtomicRegion();
+  nsIContent* GetAtomicRegion() const;
 
   /**
    * Get numeric value of the given ARIA attribute.
    *
    * @param aAriaProperty - the ARIA property we're using
    * @param aValue - value of the attribute
    *
    * @return - NS_OK_NO_ARIA_VALUE if there is no setted ARIA attribute
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -37,16 +37,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
  
 #include "nsApplicationAccessible.h"
 
+#include "Relation.h"
 #include "States.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 
 #include "nsIComponentManager.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIWindowMediator.h"
@@ -177,48 +178,20 @@ nsApplicationAccessible::FocusedChild()
     nsAccessible* focusedChild =
       GetAccService()->GetAccessible(gLastFocusedNode);
     if (focusedChild && focusedChild->Parent() == this)
       return focusedChild;
   }
   return nsnull;
 }
 
-NS_IMETHODIMP
-nsApplicationAccessible::GetRelationByType(PRUint32 aRelationType,
-                                           nsIAccessibleRelation **aRelation)
-{
-  NS_ENSURE_ARG_POINTER(aRelation);
-  *aRelation = nsnull;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsApplicationAccessible::GetRelationsCount(PRUint32 *aCount)
+Relation
+nsApplicationAccessible::RelationByType(PRUint32 aRelationType)
 {
-  NS_ENSURE_ARG_POINTER(aCount);
-  *aCount = 0;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsApplicationAccessible::GetRelation(PRUint32 aIndex,
-                                     nsIAccessibleRelation **aRelation)
-{
-  NS_ENSURE_ARG_POINTER(aRelation);
-  *aRelation = nsnull;
-  return NS_ERROR_INVALID_ARG;
-}
-
-NS_IMETHODIMP
-nsApplicationAccessible::GetRelations(nsIArray **aRelations)
-{
-  NS_ENSURE_ARG_POINTER(aRelations);
-  *aRelations = nsnull;
-  return NS_OK;
+  return Relation();
 }
 
 NS_IMETHODIMP
 nsApplicationAccessible::GetBounds(PRInt32 *aX, PRInt32 *aY,
                                    PRInt32 *aWidth, PRInt32 *aHeight)
 {
   NS_ENSURE_ARG_POINTER(aX);
   *aX = 0;
--- a/accessible/src/base/nsApplicationAccessible.h
+++ b/accessible/src/base/nsApplicationAccessible.h
@@ -88,21 +88,16 @@ public:
   NS_IMETHOD GetParent(nsIAccessible **aParent);
   NS_IMETHOD GetNextSibling(nsIAccessible **aNextSibling);
   NS_IMETHOD GetPreviousSibling(nsIAccessible **aPreviousSibling);
   NS_IMETHOD GetName(nsAString &aName);
   NS_IMETHOD GetValue(nsAString &aValue);
   NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes);
   NS_IMETHOD GroupPosition(PRInt32 *aGroupLevel, PRInt32 *aSimilarItemsInGroup,
                            PRInt32 *aPositionInGroup);
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-  NS_IMETHOD GetRelationsCount(PRUint32 *aRelationsCount);
-  NS_IMETHOD GetRelation(PRUint32 aIndex, nsIAccessibleRelation **aRelation);
-  NS_IMETHOD GetRelations(nsIArray **aRelations);
   NS_IMETHOD GetBounds(PRInt32 *aX, PRInt32 *aY,
                        PRInt32 *aWidth, PRInt32 *aHeight);
   NS_IMETHOD SetSelected(PRBool aIsSelected);
   NS_IMETHOD TakeSelection();
   NS_IMETHOD TakeFocus();
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString &aName);
   NS_IMETHOD GetActionDescription(PRUint8 aIndex, nsAString &aDescription);
   NS_IMETHOD DoAction(PRUint8 aIndex);
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -823,82 +823,8 @@ nsAccessibleDOMStringList::GetLength(PRU
 NS_IMETHODIMP
 nsAccessibleDOMStringList::Contains(const nsAString& aString, PRBool *aResult)
 {
   *aResult = mNames.Contains(aString);
 
   return NS_OK;
 }
 
-
-////////////////////////////////////////////////////////////////////////////////
-// IDRefsIterator
-////////////////////////////////////////////////////////////////////////////////
-
-IDRefsIterator::IDRefsIterator(nsIContent* aContent, nsIAtom* aIDRefsAttr) :
-  mCurrIdx(0)
-{
-  if (!aContent->IsInDoc() ||
-      !aContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs))
-    return;
-
-  if (aContent->IsInAnonymousSubtree()) {
-    mXBLDocument = do_QueryInterface(aContent->GetOwnerDoc());
-    mBindingParent = do_QueryInterface(aContent->GetBindingParent());
-  } else {
-    mDocument = aContent->GetOwnerDoc();
-  }
-}
-
-const nsDependentSubstring
-IDRefsIterator::NextID()
-{
-  for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
-    if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
-      break;
-  }
-
-  if (mCurrIdx >= mIDs.Length())
-    return nsDependentSubstring();
-
-  nsAString::index_type idStartIdx = mCurrIdx;
-  while (++mCurrIdx < mIDs.Length()) {
-    if (NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
-      break;
-  }
-
-  return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
-}
-
-nsIContent*
-IDRefsIterator::NextElem()
-{
-  while (true) {
-    const nsDependentSubstring id = NextID();
-    if (id.IsEmpty())
-      break;
-
-    nsIContent* refContent = GetElem(id);
-    if (refContent)
-      return refContent;
-  }
-
-  return nsnull;
-}
-
-nsIContent*
-IDRefsIterator::GetElem(const nsDependentSubstring& aID)
-{
-  if (mXBLDocument) {
-    // If content is anonymous subtree then use "anonid" attribute to get
-    // elements, otherwise search elements in DOM by ID attribute.
-
-    nsCOMPtr<nsIDOMElement> refElm;
-    mXBLDocument->GetAnonymousElementByAttribute(mBindingParent,
-                                                 NS_LITERAL_STRING("anonid"),
-                                                 aID,
-                                                 getter_AddRefs(refElm));
-    nsCOMPtr<nsIContent> refContent = do_QueryInterface(refElm);
-    return refContent;
-  }
-
-  return mDocument->GetElementById(aID);
-}
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -36,17 +36,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsCoreUtils_h_
 #define nsCoreUtils_h_
 
 #include "nsAccessibilityAtoms.h"
 
-#include "nsIDOMDocumentXBL.h"
 #include "nsIDOMNode.h"
 #include "nsIContent.h"
 #include "nsIBoxObject.h"
 #include "nsITreeBoxObject.h"
 #include "nsITreeColumns.h"
 
 #include "nsIFrame.h"
 #include "nsIDocShellTreeItem.h"
@@ -396,44 +395,10 @@ public:
   PRBool Add(const nsAString& aName) {
     return mNames.AppendElement(aName) != nsnull;
   }
 
 private:
   nsTArray<nsString> mNames;
 };
 
-/**
- * Used to iterate through IDs or elements pointed by IDRefs attribute. Note,
- * any method used to iterate through IDs or elements moves iterator to next
- * position.
- */
-class IDRefsIterator
-{
-public:
-  IDRefsIterator(nsIContent* aContent, nsIAtom* aIDRefsAttr);
-
-  /**
-   * Return next ID.
-   */
-  const nsDependentSubstring NextID();
-
-  /**
-   * Return next element.
-   */
-  nsIContent* NextElem();
-
-  /**
-   * Return the element with the given ID.
-   */
-  nsIContent* GetElem(const nsDependentSubstring& aID);
-
-private:
-  nsString mIDs;
-  nsAString::index_type mCurrIdx;
-
-  nsIDocument* mDocument;
-  nsCOMPtr<nsIDOMDocumentXBL> mXBLDocument;
-  nsCOMPtr<nsIDOMElement> mBindingParent;
-};
-
 #endif
 
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -31,16 +31,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "AccIterator.h"
 #include "States.h"
 #include "nsAccCache.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessibilityService.h"
 #include "nsAccTreeWalker.h"
 #include "nsAccUtils.h"
 #include "nsRootAccessible.h"
 #include "nsTextEquivUtils.h"
deleted file mode 100644
--- a/accessible/src/base/nsRelUtils.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsRelUtils.h"
-
-#include "nsAccessibilityService.h"
-#include "nsAccessible.h"
-#include "nsCoreUtils.h"
-
-#include "nsIDOMDocument.h"
-#include "nsIDOMElement.h"
-#include "nsIDOMDocumentXBL.h"
-
-#include "nsAutoPtr.h"
-#include "nsArrayUtils.h"
-
-already_AddRefed<nsIAccessible>
-nsRelUtils::GetRelatedAccessible(nsIAccessible *aAccessible,
-                                 PRUint32 aRelationType)
-{
-  nsCOMPtr<nsIAccessibleRelation> relation;
-  nsresult rv = aAccessible->GetRelationByType(aRelationType,
-                                               getter_AddRefs(relation));
-  if (NS_FAILED(rv) || !relation)
-    return nsnull;
-
-  nsIAccessible *targetAccessible = nsnull;
-  rv = relation->GetTarget(0, &targetAccessible);
-  return targetAccessible;
-}
-
-nsresult
-nsRelUtils::AddTarget(PRUint32 aRelationType, nsIAccessibleRelation **aRelation,
-                      nsIAccessible *aTarget)
-{
-  if (!aTarget)
-    return NS_OK_NO_RELATION_TARGET;
-
-  if (*aRelation) {
-    nsRefPtr<nsAccessibleRelation> relation = QueryAccRelation(*aRelation);
-    return relation->AddTarget(aTarget);
-  }
-
-  *aRelation = new nsAccessibleRelationWrap(aRelationType, aTarget);
-  NS_ENSURE_TRUE(*aRelation, NS_ERROR_OUT_OF_MEMORY);
-
-  NS_ADDREF(*aRelation);
-  return NS_OK;
-}
-
-nsresult
-nsRelUtils::AddTargetFromContent(PRUint32 aRelationType,
-                                 nsIAccessibleRelation **aRelation,
-                                 nsIContent *aContent)
-{
-  if (!aContent)
-    return NS_OK_NO_RELATION_TARGET;
-
-  nsAccessible* accessible = GetAccService()->GetAccessible(aContent);
-  return AddTarget(aRelationType, aRelation, accessible);
-}
-
-nsresult
-nsRelUtils::AddTargetFromIDRefAttr(PRUint32 aRelationType,
-                                   nsIAccessibleRelation **aRelation,
-                                   nsIContent *aContent, nsIAtom *aAttr,
-                                   PRBool aMayBeAnon)
-{
-  nsAutoString id;
-  if (!aContent->GetAttr(kNameSpaceID_None, aAttr, id))
-    return NS_OK_NO_RELATION_TARGET;
-
-  nsCOMPtr<nsIDOMDocument> document =
-    do_QueryInterface(aContent->GetOwnerDoc());
-  NS_ASSERTION(document, "The given node is not in document!");
-  if (!document)
-    return NS_OK_NO_RELATION_TARGET;
-
-  nsCOMPtr<nsIDOMElement> refElm;
-  if (aMayBeAnon && aContent->GetBindingParent()) {
-    nsCOMPtr<nsIDOMDocumentXBL> documentXBL(do_QueryInterface(document));
-    nsCOMPtr<nsIDOMElement> bindingParent =
-      do_QueryInterface(aContent->GetBindingParent());
-    documentXBL->GetAnonymousElementByAttribute(bindingParent,
-                                                NS_LITERAL_STRING("id"),
-                                                id,
-                                                getter_AddRefs(refElm));
-  }
-  else {
-    document->GetElementById(id, getter_AddRefs(refElm));
-  }
-
-  nsCOMPtr<nsIContent> refContent(do_QueryInterface(refElm));
-  return AddTargetFromContent(aRelationType, aRelation, refContent);
-}
-
-nsresult
-nsRelUtils::AddTargetFromIDRefsAttr(PRUint32 aRelationType,
-                                    nsIAccessibleRelation **aRelation,
-                                    nsIContent *aContent, nsIAtom *aAttr)
-{
-  nsresult rv = NS_OK_NO_RELATION_TARGET;
-
-  nsIContent* refElm = nsnull;
-  IDRefsIterator iter(aContent, aAttr);
-  while ((refElm = iter.NextElem())) {
-    rv = AddTargetFromContent(aRelationType, aRelation, refElm);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return rv;
-}
deleted file mode 100644
--- a/accessible/src/base/nsRelUtils.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _nsRelUtils_H_
-#define _nsRelUtils_H_
-
-#include "nsAccessibleRelationWrap.h"
-
-#include "nsIAtom.h"
-#include "nsIContent.h"
-
-// Used by AddTarget...() methods. Returned when can't get target accessible.
-#define NS_OK_NO_RELATION_TARGET \
-NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x24)
-
-/**
- * Utils class designed to work with accessible relations.
- */
-class nsRelUtils
-{
-public:
-  /**
-   * Return first target of the relation of the given relation type for
-   * the given accessible.
-   *
-   * @param aAccessible   [in] the accessible to get an relation
-   * @param aRelationType [in] relation type
-   * @return              an accessible
-   */
-  static already_AddRefed<nsIAccessible>
-    GetRelatedAccessible(nsIAccessible *aAccessible, PRUint32 aRelationType);
-
-  /**
-   * Create the relation if the given relation is null. Add target to it
-   * which is the given accessible.
-   *
-   * @param  aRelationType  [in] relation type
-   * @param  aRelation      [in, out] relation object
-   * @param  aTarget        [in] accessible object
-   */
-  static nsresult AddTarget(PRUint32 aRelationType,
-                            nsIAccessibleRelation **aRelation,
-                            nsIAccessible *aTarget);
-
-  /**
-   * Create the relation if the given relation is null and add the target to it
-   * which is the accessible for the given node.
-   *
-   * @param  aRelationType  [in] relation type
-   * @param  aRelation      [in, out] relation object
-   * @param  aContent       [in] accessible node
-   */
-  static nsresult AddTargetFromContent(PRUint32 aRelationType,
-                                       nsIAccessibleRelation **aRelation,
-                                       nsIContent *aContent);
-
-  /**
-   * Create the relation if the given relation is null and add the target to it
-   * pointed by IDRef attribute on the given node.
-   *
-   * @param  aRelationType  [in] relation type
-   * @param  aRelation      [in, out] relation object
-   * @param  aContent       [in] node having the given IDRef attribute
-   * @param  aAttr          [in] IDRef attribute
-   * @param  aMayBeAnon     [in] true if the target may be anonymous; if so,
-   *                             we need to look for it under the binding
-   *                             parent of aContent.
-   */
-  static nsresult AddTargetFromIDRefAttr(PRUint32 aRelationType,
-                                         nsIAccessibleRelation **aRelation,
-                                         nsIContent *aContent, nsIAtom *aAttr,
-                                         PRBool aMayBeAnon = PR_FALSE);
-
-  /**
-   * Create the relation if the given relation is null and add the targets to it
-   * that are pointed by IDRefs attribute on the given node.
-   *
-   * @param  aRelationType  [in] relation type
-   * @param  aRelation      [in, out] relation object
-   * @param  aContent       [in] node having the given IDRefs attribute
-   * @param  aAttr          [in] IDRefs attribute
-   */
-  static nsresult AddTargetFromIDRefsAttr(PRUint32 aRelationType,
-                                          nsIAccessibleRelation **aRelation,
-                                          nsIContent *aContent, nsIAtom *aAttr);
-
-  /**
-   * Query nsAccessibleRelation from the given nsIAccessibleRelation.
-   */
-  static already_AddRefed<nsAccessibleRelation>
-  QueryAccRelation(nsIAccessibleRelation *aRelation)
-  {
-    nsAccessibleRelation* relation = nsnull;
-    if (aRelation)
-      CallQueryInterface(aRelation, &relation);
-
-    return relation;
-  }
-};
-
-#endif
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -33,25 +33,26 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #define CreateEvent CreateEventA
 #include "nsIDOMDocument.h"
 
-#include "States.h"
 #include "nsAccessibilityService.h"
 #include "nsApplicationAccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
-#include "nsRelUtils.h"
+#include "Relation.h"
+#include "States.h"
 
 #include "mozilla/dom/Element.h"
 #include "nsHTMLSelectAccessible.h"
+#include "nsIAccessibleRelation.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMHTMLAnchorElement.h"
@@ -825,37 +826,30 @@ nsRootAccessible::GetContentDocShell(nsI
         return aStart;
       }
     }
   }
   return nsnull;
 }
 
 // nsIAccessible method
-NS_IMETHODIMP
-nsRootAccessible::GetRelationByType(PRUint32 aRelationType,
-                                    nsIAccessibleRelation **aRelation)
+Relation
+nsRootAccessible::RelationByType(PRUint32 aType)
 {
-  NS_ENSURE_ARG_POINTER(aRelation);
-  *aRelation = nsnull;
-
-  if (!mDocument || aRelationType != nsIAccessibleRelation::RELATION_EMBEDS) {
-    return nsDocAccessibleWrap::GetRelationByType(aRelationType, aRelation);
-  }
+  if (!mDocument || aType != nsIAccessibleRelation::RELATION_EMBEDS)
+    return nsDocAccessibleWrap::RelationByType(aType);
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem =
     nsCoreUtils::GetDocShellTreeItemFor(mDocument);
   nsCOMPtr<nsIDocShellTreeItem> contentTreeItem = GetContentDocShell(treeItem);
   // there may be no content area, so we need a null check
-  if (contentTreeItem) {
-    nsDocAccessible *accDoc = nsAccUtils::GetDocAccessibleFor(contentTreeItem);
-    return nsRelUtils::AddTarget(aRelationType, aRelation, accDoc);
-  }
+  if (!contentTreeItem)
+    return Relation();
 
-  return NS_OK;
+  return Relation(nsAccUtils::GetDocAccessibleFor(contentTreeItem));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
 void
 nsRootAccessible::HandlePopupShownEvent(nsAccessible* aAccessible)
 {
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -46,16 +46,18 @@
 #include "nsXULTreeAccessible.h"
 #endif
 
 #include "nsHashtable.h"
 #include "nsCaretAccessible.h"
 #include "nsIDocument.h"
 #include "nsIDOMEventListener.h"
 
+class Relation;
+
 #define NS_ROOTACCESSIBLE_IMPL_CID                      \
 {  /* eaba2cf0-21b1-4e2b-b711-d3a89dcd5e1a */           \
   0xeaba2cf0,                                           \
   0x21b1,                                               \
   0x4e2b,                                               \
   { 0xb7, 0x11, 0xd3, 0xa8, 0x9d, 0xcd, 0x5e, 0x1a }    \
 }
 
@@ -68,26 +70,25 @@ class nsRootAccessible : public nsDocAcc
 
 public:
   nsRootAccessible(nsIDocument *aDocument, nsIContent *aRootContent,
                    nsIWeakReference *aShell);
   virtual ~nsRootAccessible();
 
   // nsIAccessible
   NS_IMETHOD GetName(nsAString& aName);
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
 
   // nsIDOMEventListener
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
 
   // nsAccessNode
   virtual void Shutdown();
 
   // nsAccessible
+  virtual Relation RelationByType(PRUint32 aType);
   virtual PRUint32 NativeRole();
   virtual PRUint64 NativeState();
 
   // nsRootAccessible
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ROOTACCESSIBLE_IMPL_CID)
 
   /**
    * Fire an accessible focus event for the focused accessible and attach a new
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -34,16 +34,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsTextEquivUtils.h"
 
+#include "AccIterator.h"
 #include "nsAccessibilityService.h"
 #include "nsAccessible.h"
 #include "nsAccUtils.h"
 
 #include "nsIDOMXULLabeledControlEl.h"
 
 #include "nsArrayUtils.h"
 
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -33,22 +33,23 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHTMLFormControlAccessible.h"
 
+#include "Relation.h"
 #include "States.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsAccUtils.h"
-#include "nsRelUtils.h"
 #include "nsTextEquivUtils.h"
 
+#include "nsIAccessibleRelation.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMHTMLLegendElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIEditor.h"
@@ -610,72 +611,48 @@ nsHTMLGroupboxAccessible::GetNameInterna
   if (legendContent) {
     return nsTextEquivUtils::
       AppendTextEquivFromContent(this, legendContent, &aName);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHTMLGroupboxAccessible::GetRelationByType(PRUint32 aRelationType,
-                                            nsIAccessibleRelation **aRelation)
+Relation
+nsHTMLGroupboxAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsHyperTextAccessibleWrap::GetRelationByType(aRelationType,
-                                                             aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
+  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
+    // No override for label, so use <legend> for this <fieldset>
+  if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
+    rel.AppendTarget(GetLegend());
 
-  if (aRelationType == nsIAccessibleRelation::RELATION_LABELLED_BY) {
-    // No override for label, so use <legend> for this <fieldset>
-    return nsRelUtils::
-      AddTargetFromContent(aRelationType, aRelation, GetLegend());
-  }
-
-  return NS_OK;
+  return rel;
 }
 
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLLegendAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLLegendAccessible::
   nsHTMLLegendAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsHyperTextAccessibleWrap(aContent, aShell)
 {
 }
 
-NS_IMETHODIMP
-nsHTMLLegendAccessible::GetRelationByType(PRUint32 aRelationType,
-                                          nsIAccessibleRelation **aRelation)
+Relation
+nsHTMLLegendAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsHyperTextAccessibleWrap::
-    GetRelationByType(aRelationType, aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aRelationType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
-    // Look for groupbox parent
-    nsAccessible* groupbox = Parent();
+  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
+  if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
+    return rel;
 
-    if (groupbox && groupbox->Role() == nsIAccessibleRole::ROLE_GROUPING) {
-      // XXX: if group box exposes more than one relation of the given type
-      // then we fail.
-      nsCOMPtr<nsIAccessible> testLabelAccessible =
-        nsRelUtils::GetRelatedAccessible(groupbox,
-                                         nsIAccessibleRelation::RELATION_LABELLED_BY);
+  nsAccessible* groupbox = Parent();
+  if (groupbox && groupbox->Role() == nsIAccessibleRole::ROLE_GROUPING)
+    rel.AppendTarget(groupbox);
 
-      if (testLabelAccessible == this) {
-        // We're the first child of the parent groupbox, see
-        // nsHTMLGroupboxAccessible::GetRelationByType().
-        return nsRelUtils::
-          AddTarget(aRelationType, aRelation, groupbox);
-      }
-    }
-  }
-
-  return NS_OK;
+  return rel;
 }
 
 PRUint32
 nsHTMLLegendAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_LABEL;
 }
--- a/accessible/src/html/nsHTMLFormControlAccessible.h
+++ b/accessible/src/html/nsHTMLFormControlAccessible.h
@@ -171,38 +171,32 @@ public:
 /**
  * Accessible for HTML fieldset element.
  */
 class nsHTMLGroupboxAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   nsHTMLGroupboxAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
-  // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-
   // nsAccessible
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual PRUint32 NativeRole();
+  virtual Relation RelationByType(PRUint32 aType);
 
 protected:
   nsIContent* GetLegend();
 };
 
 
 /**
  * Accessible for HTML legend element.
  */
 class nsHTMLLegendAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   nsHTMLLegendAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
-  // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-
   // nsAccessible
   virtual PRUint32 NativeRole();
+  virtual Relation RelationByType(PRUint32 aType);
 };
 
 #endif  
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -34,24 +34,25 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHTMLTableAccessible.h"
 
+#include "Relation.h"
 #include "States.h"
 #include "nsAccessibilityService.h"
 #include "nsAccTreeWalker.h"
 #include "nsAccUtils.h"
 #include "nsDocAccessible.h"
-#include "nsRelUtils.h"
 #include "nsTextEquivUtils.h"
 
+#include "nsIAccessibleRelation.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsISelectionPrivate.h"
 #include "nsINameSpaceManager.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsIDOMHTMLTableCellElement.h"
 #include "nsIDOMHTMLTableElement.h"
@@ -499,28 +500,24 @@ nsHTMLTableAccessible::GetAttributesInte
   }
   
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsIAccessible implementation
 
-NS_IMETHODIMP
-nsHTMLTableAccessible::GetRelationByType(PRUint32 aRelationType,
-                                         nsIAccessibleRelation **aRelation)
+Relation
+nsHTMLTableAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType,
-                                                    aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
+  Relation rel = nsAccessibleWrap::RelationByType(aType);
+  if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
+    rel.AppendTarget(Caption());
 
-  if (aRelationType == nsIAccessibleRelation::RELATION_LABELLED_BY)
-    return nsRelUtils::AddTarget(aRelationType, aRelation, Caption());
-
-  return NS_OK;
+  return rel;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsIAccessibleTable implementation
 
 NS_IMETHODIMP
 nsHTMLTableAccessible::GetCaption(nsIAccessible **aCaption)
 {
@@ -1516,28 +1513,23 @@ nsHTMLTableAccessible::IsProbablyForLayo
   RETURN_LAYOUT_ANSWER(PR_FALSE, "no layout factor strong enough, so will guess data");
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLCaptionAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
-NS_IMETHODIMP
-nsHTMLCaptionAccessible::GetRelationByType(PRUint32 aRelationType,
-                                           nsIAccessibleRelation **aRelation)
+Relation
+nsHTMLCaptionAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsHyperTextAccessible::GetRelationByType(aRelationType,
-                                                         aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
+  Relation rel = nsHyperTextAccessible::RelationByType(aType);
+  if (aType == nsIAccessibleRelation::RELATION_LABEL_FOR)
+    rel.AppendTarget(Parent());
 
-  if (aRelationType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
-      return nsRelUtils::AddTarget(aRelationType, aRelation, Parent());
-  }
-
-  return NS_OK;
+  return rel;
 }
 
 PRUint32
 nsHTMLCaptionAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_CAPTION;
 }
--- a/accessible/src/html/nsHTMLTableAccessible.h
+++ b/accessible/src/html/nsHTMLTableAccessible.h
@@ -125,26 +125,23 @@ class nsHTMLTableAccessible : public nsA
 {
 public:
   nsHTMLTableAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLETABLE
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_TABLEACCESSIBLE_IMPL_CID)
 
-  // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-
   // nsAccessible
   virtual void Description(nsString& aDescription);
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual PRUint32 NativeRole();
   virtual PRUint64 NativeState();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+  virtual Relation RelationByType(PRUint32 aRelationType);
 
   // TableAccessible
   inline nsAccessible* Caption() const
   {
     nsAccessible* child = mChildren.SafeElementAt(0, nsnull);
     return child && child->Role() == nsIAccessibleRole::ROLE_CAPTION ?
       child : nsnull;
   }
@@ -214,16 +211,15 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsHTMLTabl
  */
 class nsHTMLCaptionAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   nsHTMLCaptionAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
     nsHyperTextAccessibleWrap(aContent, aShell) { }
 
   // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
 
   // nsAccessible
   virtual PRUint32 NativeRole();
+  virtual Relation RelationByType(PRUint32 aRelationType);
 };
 
 #endif  
--- a/accessible/src/html/nsHTMLTextAccessible.cpp
+++ b/accessible/src/html/nsHTMLTextAccessible.cpp
@@ -36,20 +36,21 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHTMLTextAccessible.h"
 
 #include "nsDocAccessible.h"
 #include "nsAccUtils.h"
-#include "nsRelUtils.h"
 #include "nsTextEquivUtils.h"
+#include "Relation.h"
 #include "States.h"
 
+#include "nsIAccessibleRelation.h"
 #include "nsIFrame.h"
 #include "nsPresContext.h"
 #include "nsBlockFrame.h"
 #include "nsISelection.h"
 #include "nsISelectionController.h"
 #include "nsComponentManagerUtils.h"
 
 using namespace mozilla::a11y;
@@ -193,33 +194,24 @@ nsHTMLLabelAccessible::NativeRole()
 nsHTMLOutputAccessible::
   nsHTMLOutputAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
   nsHyperTextAccessibleWrap(aContent, aShell)
 {
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLOutputAccessible, nsHyperTextAccessible)
 
-NS_IMETHODIMP
-nsHTMLOutputAccessible::GetRelationByType(PRUint32 aRelationType,
-                                          nsIAccessibleRelation** aRelation)
+Relation
+nsHTMLOutputAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType, aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
+  Relation rel = nsAccessibleWrap::RelationByType(aType);
+  if (aType == nsIAccessibleRelation::RELATION_CONTROLLED_BY)
+    rel.AppendIter(new IDRefsIterator(mContent, nsAccessibilityAtoms::_for));
 
-  if (rv != NS_OK_NO_RELATION_TARGET)
-    return NS_OK; // XXX bug 381599, avoid performance problems
-
-  if (aRelationType == nsIAccessibleRelation::RELATION_CONTROLLED_BY) {
-    return nsRelUtils::
-      AddTargetFromIDRefsAttr(aRelationType, aRelation, mContent,
-                              nsAccessibilityAtoms::_for);
-  }
-
-  return NS_OK;
+  return rel;
 }
 
 PRUint32
 nsHTMLOutputAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_SECTION;
 }
 
--- a/accessible/src/html/nsHTMLTextAccessible.h
+++ b/accessible/src/html/nsHTMLTextAccessible.h
@@ -110,23 +110,20 @@ public:
  */
 class nsHTMLOutputAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   nsHTMLOutputAccessible(nsIContent* aContent, nsIWeakReference* aShell);
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation** aRelation);
-
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes);
+  virtual Relation RelationByType(PRUint32 aType);
 };
 
 /**
  * Used for bullet of HTML list item element (for example, HTML li).
  */
 class nsHTMLListBulletAccessible : public nsLeafAccessible
 {
 public:
--- a/accessible/src/mac/Makefile.in
+++ b/accessible/src/mac/Makefile.in
@@ -67,17 +67,16 @@ EXPORTS = \
   nsDocAccessibleWrap.h \
   nsRootAccessibleWrap.h \
   nsXULMenuAccessibleWrap.h \
   nsXULListboxAccessibleWrap.h \
   nsXULTreeGridAccessibleWrap.h \
   nsHyperTextAccessibleWrap.h \
   nsHTMLImageAccessibleWrap.h \
   nsHTMLTableAccessibleWrap.h \
-  nsAccessibleRelationWrap.h \
   nsApplicationAccessibleWrap.h \
   mozDocAccessible.h \
   mozAccessible.h \
   mozAccessibleWrapper.h \
   mozAccessibleProtocol.h \
   mozActionElements.h \
   mozTextAccessible.h \
   nsRoleMap.h \
deleted file mode 100644
--- a/accessible/src/mac/nsAccessibleRelationWrap.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=2:
- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.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
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_ACCESSIBLE_RELATION_WRAP_H
-#define _NS_ACCESSIBLE_RELATION_WRAP_H
-
-#include "nsAccessibleRelation.h"
-
-typedef class nsAccessibleRelation nsAccessibleRelationWrap;
-
-#endif
-
--- a/accessible/src/msaa/Makefile.in
+++ b/accessible/src/msaa/Makefile.in
@@ -56,26 +56,26 @@ CPPSRCS = \
   nsARIAGridAccessibleWrap.cpp \
   nsRootAccessibleWrap.cpp \
   nsXULMenuAccessibleWrap.cpp \
   nsXULListboxAccessibleWrap.cpp \
   nsXULTreeGridAccessibleWrap.cpp \
   nsHyperTextAccessibleWrap.cpp \
   nsHTMLImageAccessibleWrap.cpp \
   nsHTMLTableAccessibleWrap.cpp \
-  nsAccessibleRelationWrap.cpp \
   nsApplicationAccessibleWrap.cpp \
   nsWinUtils.cpp \
   CAccessibleAction.cpp \
   CAccessibleImage.cpp \
   CAccessibleComponent.cpp \
   CAccessibleText.cpp \
   CAccessibleEditableText.cpp \
   CAccessibleHyperlink.cpp \
   CAccessibleHypertext.cpp \
+  ia2AccessibleRelation.cpp \
   CAccessibleTable.cpp \
   CAccessibleTableCell.cpp \
   CAccessibleValue.cpp \
   $(NULL)
 
 EXPORTS = \
   nsAccessNodeWrap.h \
   nsAccessibleWrap.h \
@@ -85,17 +85,16 @@ EXPORTS = \
   nsHTMLWin32ObjectAccessible.h \
   nsARIAGridAccessibleWrap.h \
   nsXULMenuAccessibleWrap.h \
   nsXULListboxAccessibleWrap.h \
   nsXULTreeGridAccessibleWrap.h \
   nsHyperTextAccessibleWrap.h \
   nsHTMLImageAccessibleWrap.h \
   nsHTMLTableAccessibleWrap.h \
-  nsAccessibleRelationWrap.h \
   nsApplicationAccessibleWrap.h \
   CAccessibleAction.h \
   CAccessibleImage.h \
   CAccessibleComponent.h \
   CAccessibleText.h \
   CAccessibleEditableText.h \
   CAccessibleHyperlink.h \
   CAccessibleHypertext.h \
rename from accessible/src/msaa/nsAccessibleRelationWrap.cpp
rename to accessible/src/msaa/ia2AccessibleRelation.cpp
--- a/accessible/src/msaa/nsAccessibleRelationWrap.cpp
+++ b/accessible/src/msaa/ia2AccessibleRelation.cpp
@@ -33,225 +33,191 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsAccessibleRelationWrap.h"
+#include "ia2AccessibleRelation.h"
+
+#include "Relation.h"
+
+#include "nsIAccessibleRelation.h"
+#include "nsID.h"
 
 #include "AccessibleRelation_i.c"
-#include "nsAccessNodeWrap.h"
 
-#include "nsArrayUtils.h"
-
-nsAccessibleRelationWrap::
-  nsAccessibleRelationWrap(PRUint32 aType, nsIAccessible *aTarget) :
-  nsAccessibleRelation(aType, aTarget)
+ia2AccessibleRelation::ia2AccessibleRelation(PRUint32 aType, Relation* aRel) :
+  mType(aType), mReferences(0)
 {
-}
-
-// ISupports
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsAccessibleRelationWrap, nsAccessibleRelation,
-                             nsIWinAccessNode)
-
-// nsIWinAccessNode
-
-NS_IMETHODIMP
-nsAccessibleRelationWrap::QueryNativeInterface(REFIID aIID, void** aInstancePtr)
-{
-  return QueryInterface(aIID, aInstancePtr);
+  nsAccessible* target = nsnull;
+  while ((target = aRel->Next()))
+    mTargets.AppendElement(target);
 }
 
 // IUnknown
 
 STDMETHODIMP
-nsAccessibleRelationWrap::QueryInterface(REFIID iid, void** ppv)
+ia2AccessibleRelation::QueryInterface(REFIID iid, void** ppv)
 {
+  if (!ppv)
+    return E_INVALIDARG;
+
   *ppv = NULL;
 
   if (IID_IAccessibleRelation == iid || IID_IUnknown == iid) {
     *ppv = static_cast<IAccessibleRelation*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
   return E_NOINTERFACE;
 }
 
+ULONG STDMETHODCALLTYPE
+ia2AccessibleRelation::AddRef()
+{
+  return mReferences++;
+}
+
+ULONG STDMETHODCALLTYPE 
+ia2AccessibleRelation::Release()
+{
+  mReferences--;
+  ULONG references = mReferences;
+  if (!mReferences)
+    delete this;
+
+  return references;
+}
+
 // IAccessibleRelation
 
 STDMETHODIMP
-nsAccessibleRelationWrap::get_relationType(BSTR *aRelationType)
+ia2AccessibleRelation::get_relationType(BSTR *aRelationType)
 {
 __try {
+  if (!aRelationType)
+    return E_INVALIDARG;
+
   *aRelationType = NULL;
 
-  PRUint32 type = 0;
-  nsresult rv = GetRelationType(&type);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  switch (type) {
-    case RELATION_CONTROLLED_BY:
+  switch (mType) {
+    case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
       *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLED_BY);
       break;
-    case RELATION_CONTROLLER_FOR:
+    case nsIAccessibleRelation::RELATION_CONTROLLER_FOR:
       *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLER_FOR);
       break;
-    case RELATION_DESCRIBED_BY:
+    case nsIAccessibleRelation::RELATION_DESCRIBED_BY:
       *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIBED_BY);
       break;
-    case RELATION_DESCRIPTION_FOR:
+    case nsIAccessibleRelation::RELATION_DESCRIPTION_FOR:
       *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIPTION_FOR);
       break;
-    case RELATION_EMBEDDED_BY:
+    case nsIAccessibleRelation::RELATION_EMBEDDED_BY:
       *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDDED_BY);
       break;
-    case RELATION_EMBEDS:
+    case nsIAccessibleRelation::RELATION_EMBEDS:
       *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDS);
       break;
-    case RELATION_FLOWS_FROM:
+    case nsIAccessibleRelation::RELATION_FLOWS_FROM:
       *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_FROM);
       break;
-    case RELATION_FLOWS_TO:
+    case nsIAccessibleRelation::RELATION_FLOWS_TO:
       *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_TO);
       break;
-    case RELATION_LABEL_FOR:
+    case nsIAccessibleRelation::RELATION_LABEL_FOR:
       *aRelationType = ::SysAllocString(IA2_RELATION_LABEL_FOR);
       break;
-    case RELATION_LABELLED_BY:
+    case nsIAccessibleRelation::RELATION_LABELLED_BY:
       *aRelationType = ::SysAllocString(IA2_RELATION_LABELED_BY);
       break;
-    case RELATION_MEMBER_OF:
+    case nsIAccessibleRelation::RELATION_MEMBER_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_MEMBER_OF);
       break;
-    case RELATION_NODE_CHILD_OF:
+    case nsIAccessibleRelation::RELATION_NODE_CHILD_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_NODE_CHILD_OF);
       break;
-    case RELATION_PARENT_WINDOW_OF:
+    case nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_PARENT_WINDOW_OF);
       break;
-    case RELATION_POPUP_FOR:
+    case nsIAccessibleRelation::RELATION_POPUP_FOR:
       *aRelationType = ::SysAllocString(IA2_RELATION_POPUP_FOR);
       break;
-    case RELATION_SUBWINDOW_OF:
+    case nsIAccessibleRelation::RELATION_SUBWINDOW_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_SUBWINDOW_OF);
       break;
     default:
       return E_FAIL;
   }
 
   return *aRelationType ? S_OK : E_OUTOFMEMORY;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-nsAccessibleRelationWrap::get_localizedRelationType(BSTR *aLocalizedRelationType)
+ia2AccessibleRelation::get_localizedRelationType(BSTR *aLocalizedRelationType)
 {
 __try {
+  if (!aLocalizedRelationType)
+    return E_INVALIDARG;
+
   *aLocalizedRelationType = NULL;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
-nsAccessibleRelationWrap::get_nTargets(long *aNTargets)
+ia2AccessibleRelation::get_nTargets(long *aNTargets)
 {
 __try {
-  *aNTargets = 0;
+ if (!aNTargets)
+   return E_INVALIDARG;
 
-  PRUint32 count = 0;
-  nsresult rv = GetTargetsCount(&count);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  *aNTargets = count;
+ *aNTargets = mTargets.Length();
   return S_OK;
-
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-nsAccessibleRelationWrap::get_target(long aTargetIndex, IUnknown **aTarget)
+ia2AccessibleRelation::get_target(long aTargetIndex, IUnknown **aTarget)
 {
 __try {
-  nsCOMPtr<nsIAccessible> accessible;
-  nsresult rv = GetTarget(aTargetIndex, getter_AddRefs(accessible));
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
+  if (aTargetIndex < 0 || aTargetIndex >= mTargets.Length() || !aTarget)
+    return E_INVALIDARG;
 
-  nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(accessible));
-  if (!winAccessNode)
-    return E_FAIL;
-
-  void *instancePtr = NULL;
-  rv = winAccessNode->QueryNativeInterface(IID_IUnknown, &instancePtr);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  *aTarget = static_cast<IUnknown*>(instancePtr);
+  mTargets[aTargetIndex]->QueryInterface((const nsID&) IID_IUnknown, (void**) aTarget);
   return S_OK;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
-nsAccessibleRelationWrap::get_targets(long aMaxTargets, IUnknown **aTarget,
-                                      long *aNTargets)
+ia2AccessibleRelation::get_targets(long aMaxTargets, IUnknown **aTargets,
+                                   long *aNTargets)
 {
 __try {
-  *aNTargets = 0;
-
-  nsCOMPtr<nsIArray> targets;
-  nsresult rv = GetTargets(getter_AddRefs(targets));
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  PRUint32 length = 0;
-  rv = targets->GetLength(&length);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  if (length == 0)
-    return S_FALSE;
-
-  PRUint32 count = length < PRUint32(aMaxTargets) ? length : aMaxTargets;
+  if (!aNTargets || !aTargets)
+    return E_INVALIDARG;
 
-  PRUint32 index = 0;
-  for (; index < count; index++) {
-    nsCOMPtr<nsIWinAccessNode> winAccessNode =
-      do_QueryElementAt(targets, index, &rv);
-    if (NS_FAILED(rv))
-      break;
-
-    void *instancePtr = NULL;
-    nsresult rv =  winAccessNode->QueryNativeInterface(IID_IUnknown,
-                                                       &instancePtr);
-    if (NS_FAILED(rv))
-      break;
+  *aNTargets = 0;
+  PRUint32 maxTargets = mTargets.Length();
+  if (maxTargets > aMaxTargets)
+    maxTargets = aMaxTargets;
 
-    aTarget[index] = static_cast<IUnknown*>(instancePtr);
-  }
+  for (PRUint32 idx = 0; idx < maxTargets; idx++)
+    get_target(idx, aTargets + idx);
 
-  if (NS_FAILED(rv)) {
-    for (PRUint32 index2 = 0; index2 < index; index2++) {
-      aTarget[index2]->Release();
-      aTarget[index2] = NULL;
-    }
-    return GetHRESULT(rv);
-  }
-
-  *aNTargets = count;
+  *aNTargets = maxTargets;
   return S_OK;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
rename from accessible/src/msaa/nsAccessibleRelationWrap.h
rename to accessible/src/msaa/ia2AccessibleRelation.h
--- a/accessible/src/msaa/nsAccessibleRelationWrap.h
+++ b/accessible/src/msaa/ia2AccessibleRelation.h
@@ -36,37 +36,32 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _NS_ACCESSIBLE_RELATION_WRAP_H
 #define _NS_ACCESSIBLE_RELATION_WRAP_H
 
-#include "nsAccessibleRelation.h"
+#include "nsAccessible.h"
+
+#include "nsTArray.h"
+
 #include "AccessibleRelation.h"
 
-#include "nsIWinAccessNode.h"
-#include "nsISupports.h"
-
-class nsAccessibleRelationWrap: public nsAccessibleRelation,
-                                public nsIWinAccessNode,
-                                public IAccessibleRelation
+class ia2AccessibleRelation : public IAccessibleRelation
 {
 public:
-  nsAccessibleRelationWrap(PRUint32 aType, nsIAccessible *aTarget);
-
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIWinAccessNode
-  NS_DECL_NSIWINACCESSNODE
+  ia2AccessibleRelation(PRUint32 aType, Relation* aRel);
+  virtual ~ia2AccessibleRelation() { }
 
   // IUnknown
-  STDMETHODIMP QueryInterface(REFIID, void**);
+  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID aIID, void** aOutPtr);
+  virtual ULONG STDMETHODCALLTYPE AddRef();
+  virtual ULONG STDMETHODCALLTYPE Release();
 
   // IAccessibleRelation
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationType(
       /* [retval][out] */ BSTR *relationType);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedRelationType(
       /* [retval][out] */ BSTR *localizedRelationType);
 
@@ -77,12 +72,23 @@ public:
       /* [in] */ long targetIndex,
       /* [retval][out] */ IUnknown **target);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_targets(
       /* [in] */ long maxTargets,
       /* [length_is][size_is][out] */ IUnknown **target,
       /* [retval][out] */ long *nTargets);
 
+  inline bool HasTargets() const
+    { return mTargets.Length(); }
+
+private:
+  ia2AccessibleRelation();
+  ia2AccessibleRelation(const ia2AccessibleRelation&);
+  ia2AccessibleRelation& operator = (const ia2AccessibleRelation&);
+
+  PRUint32 mType;
+  nsTArray<nsRefPtr<nsAccessible> > mTargets;
+  ULONG mReferences;
 };
 
 #endif
 
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -36,22 +36,25 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAccessibleWrap.h"
 
 #include "nsAccessibilityAtoms.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
-#include "nsRelUtils.h"
 #include "nsWinUtils.h"
+#include "Relation.h"
 #include "States.h"
 
+#include "ia2AccessibleRelation.h"
+
 #include "nsIAccessibleDocument.h"
 #include "nsIAccessibleEvent.h"
+#include "nsIAccessibleRelation.h"
 #include "nsIAccessibleWin32Object.h"
 
 #include "Accessible2_i.c"
 #include "AccessibleStates.h"
 
 #include "nsIMutableArray.h"
 #include "nsIDOMDocument.h"
 #include "nsIFrame.h"
@@ -889,23 +892,25 @@ STDMETHODIMP nsAccessibleWrap::accNaviga
       break;
     case NAVRELATION_DESCRIPTION_FOR:
       xpRelation = nsIAccessibleRelation::RELATION_DESCRIPTION_FOR;
       break;
   }
 
   pvarEndUpAt->vt = VT_EMPTY;
 
-  if (xpRelation)
-    xpAccessibleResult = nsRelUtils::GetRelatedAccessible(this, xpRelation);
+  if (xpRelation) {
+    Relation rel = RelationByType(xpRelation);
+    xpAccessibleResult = rel.Next();
+  }
 
   if (xpAccessibleResult) {
     pvarEndUpAt->pdispVal = NativeAccessible(xpAccessibleResult);
     pvarEndUpAt->vt = VT_DISPATCH;
-    return NS_OK;
+    return S_OK;
   }
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP nsAccessibleWrap::accHitTest(
       /* [in] */ long xLeft,
       /* [in] */ long yTop,
@@ -1051,104 +1056,94 @@ nsAccessibleWrap::Clone(IEnumVARIANT FAR
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibleWrap. IAccessible2
 
 STDMETHODIMP
 nsAccessibleWrap::get_nRelations(long *aNRelations)
 {
 __try {
-  PRUint32 count = 0;
-  nsresult rv = GetRelationsCount(&count);
-  *aNRelations = count;
+  if (!aNRelations)
+    return E_INVALIDARG;
+
+  *aNRelations = 0;
+
+  if (IsDefunct())
+    return E_FAIL;
 
-  return GetHRESULT(rv);
-
+  for (PRUint32 relType = nsIAccessibleRelation::RELATION_FIRST;
+       relType <= nsIAccessibleRelation::RELATION_LAST; relType++) {
+    Relation rel = RelationByType(relType);
+    if (rel.Next())
+      (*aNRelations)++;
+  }
+  return S_OK;
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_relation(long aRelationIndex,
                                IAccessibleRelation **aRelation)
 {
 __try {
+  if (!aRelation)
+    return E_INVALIDARG;
+
   *aRelation = NULL;
 
-  nsCOMPtr<nsIAccessibleRelation> relation;
-  nsresult rv = GetRelation(aRelationIndex, getter_AddRefs(relation));
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(relation));
-  if (!winAccessNode)
+  if (IsDefunct())
     return E_FAIL;
 
-  void *instancePtr = NULL;
-  rv =  winAccessNode->QueryNativeInterface(IID_IAccessibleRelation,
-                                            &instancePtr);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
+  PRUint32 relIdx = 0;
+  for (PRUint32 relType = nsIAccessibleRelation::RELATION_FIRST;
+       relType <= nsIAccessibleRelation::RELATION_LAST; relType++) {
+    Relation rel = RelationByType(relType);
+    nsRefPtr<ia2AccessibleRelation> ia2Relation =
+      new ia2AccessibleRelation(relType, &rel);
+    if (ia2Relation->HasTargets()) {
+      if (relIdx == aRelationIndex) {
+        ia2Relation.forget(aRelation);
+        return S_OK;
+      }
 
-  *aRelation = static_cast<IAccessibleRelation*>(instancePtr);
-  return S_OK;
+      relIdx++;
+    }
+  }
 
+  return E_INVALIDARG;
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_relations(long aMaxRelations,
                                 IAccessibleRelation **aRelation,
                                 long *aNRelations)
 {
 __try {
-  *aRelation = NULL;
+  if (!aRelation || !aNRelations)
+    return E_INVALIDARG;
+
   *aNRelations = 0;
 
-  nsCOMPtr<nsIArray> relations;
-  nsresult rv = GetRelations(getter_AddRefs(relations));
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  PRUint32 length = 0;
-  rv = relations->GetLength(&length);
-  if (NS_FAILED(rv))
-    return GetHRESULT(rv);
-
-  if (length == 0)
-    return S_FALSE;
-
-  PRUint32 count = length < (PRUint32)aMaxRelations ? length : aMaxRelations;
+  if (IsDefunct())
+    return E_FAIL;
 
-  PRUint32 index = 0;
-  for (; index < count; index++) {
-    nsCOMPtr<nsIWinAccessNode> winAccessNode =
-      do_QueryElementAt(relations, index, &rv);
-    if (NS_FAILED(rv))
-      break;
-
-    void *instancePtr = NULL;
-    nsresult rv =  winAccessNode->QueryNativeInterface(IID_IAccessibleRelation,
-                                                       &instancePtr);
-    if (NS_FAILED(rv))
-      break;
-
-    aRelation[index] = static_cast<IAccessibleRelation*>(instancePtr);
+  for (PRUint32 relType = nsIAccessibleRelation::RELATION_FIRST;
+       relType <= nsIAccessibleRelation::RELATION_LAST &&
+       *aNRelations < aMaxRelations; relType++) {
+    Relation rel = RelationByType(relType);
+    nsRefPtr<ia2AccessibleRelation> ia2Rel =
+      new ia2AccessibleRelation(relType, &rel);
+    if (ia2Rel->HasTargets()) {
+      ia2Rel.forget(aRelation + (*aNRelations));
+      (*aNRelations)++;
+    }
   }
-
-  if (NS_FAILED(rv)) {
-    for (PRUint32 index2 = 0; index2 < index; index2++) {
-      aRelation[index2]->Release();
-      aRelation[index2] = NULL;
-    }
-    return GetHRESULT(rv);
-  }
-
-  *aNRelations = count;
   return S_OK;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::role(long *aRole)
--- a/accessible/src/other/Makefile.in
+++ b/accessible/src/other/Makefile.in
@@ -61,17 +61,16 @@ EXPORTS = \
   nsDocAccessibleWrap.h \
   nsRootAccessibleWrap.h \
   nsXULMenuAccessibleWrap.h \
   nsXULListboxAccessibleWrap.h \
   nsXULTreeGridAccessibleWrap.h \
   nsHyperTextAccessibleWrap.h \
   nsHTMLImageAccessibleWrap.h \
   nsHTMLTableAccessibleWrap.h \
-  nsAccessibleRelationWrap.h \
   nsApplicationAccessibleWrap.h \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/accessible/src/other/nsAccessibleRelationWrap.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=2:
- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.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
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_ACCESSIBLE_RELATION_WRAP_H
-#define _NS_ACCESSIBLE_RELATION_WRAP_H
-
-#include "nsAccessibleRelation.h"
-
-typedef class nsAccessibleRelation nsAccessibleRelationWrap;
-
-#endif
-
--- a/accessible/src/xpcom/Makefile.in
+++ b/accessible/src/xpcom/Makefile.in
@@ -44,16 +44,17 @@ VPATH = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = accessibility
 LIBRARY_NAME = accessibility_xpcom_s
 LIBXUL_LIBRARY = 1
 
 CPPSRCS = \
   nsAccEvent.cpp \
+  nsAccessibleRelation.cpp \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
rename from accessible/src/base/nsAccessibleRelation.cpp
rename to accessible/src/xpcom/nsAccessibleRelation.cpp
--- a/accessible/src/base/nsAccessibleRelation.cpp
+++ b/accessible/src/xpcom/nsAccessibleRelation.cpp
@@ -33,83 +33,61 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAccessibleRelation.h"
 
+#include "Relation.h"
+#include "nsAccessible.h"
+
 #include "nsArrayUtils.h"
 #include "nsComponentManagerUtils.h"
 
-nsAccessibleRelation::
-  nsAccessibleRelation(PRUint32 aType, nsIAccessible *aTarget) :
+nsAccessibleRelation::nsAccessibleRelation(PRUint32 aType,
+                                           Relation* aRel) :
   mType(aType)
 {
   mTargets = do_CreateInstance(NS_ARRAY_CONTRACTID);
-  if (aTarget)
-    mTargets->AppendElement(aTarget, PR_FALSE);
+  nsIAccessible* targetAcc = nsnull;
+  while ((targetAcc = aRel->Next()))
+    mTargets->AppendElement(targetAcc, false);
 }
 
 // nsISupports
-NS_IMPL_ISUPPORTS2(nsAccessibleRelation, nsAccessibleRelation,
-                   nsIAccessibleRelation)
+NS_IMPL_ISUPPORTS1(nsAccessibleRelation, nsIAccessibleRelation)
 
 // nsIAccessibleRelation
 NS_IMETHODIMP
 nsAccessibleRelation::GetRelationType(PRUint32 *aType)
 {
   NS_ENSURE_ARG_POINTER(aType);
-
   *aType = mType;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessibleRelation::GetTargetsCount(PRUint32 *aCount)
 {
   NS_ENSURE_ARG_POINTER(aCount);
   *aCount = 0;
-
-  NS_ENSURE_TRUE(mTargets, NS_ERROR_NOT_INITIALIZED);
-
   return mTargets->GetLength(aCount);
 }
 
 NS_IMETHODIMP
 nsAccessibleRelation::GetTarget(PRUint32 aIndex, nsIAccessible **aTarget)
 {
   NS_ENSURE_ARG_POINTER(aTarget);
-  *aTarget = nsnull;
-
-  NS_ENSURE_TRUE(mTargets, NS_ERROR_NOT_INITIALIZED);
-
   nsresult rv = NS_OK;
   nsCOMPtr<nsIAccessible> target = do_QueryElementAt(mTargets, aIndex, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  target.swap(*aTarget);
-  return NS_OK;
+  target.forget(aTarget);
+  return rv;
 }
 
 NS_IMETHODIMP
 nsAccessibleRelation::GetTargets(nsIArray **aTargets)
 {
   NS_ENSURE_ARG_POINTER(aTargets);
-  *aTargets = nsnull;
-
-  NS_ENSURE_TRUE(mTargets, NS_ERROR_NOT_INITIALIZED);
-
   NS_ADDREF(*aTargets = mTargets);
   return NS_OK;
 }
-
-// nsAccessibleRelation
-nsresult
-nsAccessibleRelation::AddTarget(nsIAccessible *aTarget)
-{
-  NS_ENSURE_ARG(aTarget);
-
-  NS_ENSURE_TRUE(mTargets, NS_ERROR_NOT_INITIALIZED);
-
-  return mTargets->AppendElement(aTarget, PR_FALSE);
-}
rename from accessible/src/base/nsAccessibleRelation.h
rename to accessible/src/xpcom/nsAccessibleRelation.h
--- a/accessible/src/base/nsAccessibleRelation.h
+++ b/accessible/src/xpcom/nsAccessibleRelation.h
@@ -34,50 +34,36 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsAccessibleRelation_H_
 #define _nsAccessibleRelation_H_
 
-#include "nsIAccessible.h"
 #include "nsIAccessibleRelation.h"
 
 #include "nsCOMPtr.h"
 #include "nsIMutableArray.h"
 
-#define NS_ACCRELATION_IMPL_CID                         \
-{                                                       \
-  0xb20390d0,                                           \
-  0x40d3,                                               \
-  0x4c76,                                               \
-  { 0xb6, 0x2e, 0xc2, 0x30, 0xc8, 0xea, 0x0c, 0x1e }    \
-}
+class Relation;
 
 /**
  * Class represents an accessible relation.
  */
 class nsAccessibleRelation: public nsIAccessibleRelation
 {
 public:
-  nsAccessibleRelation(PRUint32 aType, nsIAccessible *aTarget);
+  nsAccessibleRelation(PRUint32 aType, Relation* aRel);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIACCESSIBLERELATION
 
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ACCRELATION_IMPL_CID)
-
-  /**
-   * Add target for the given key.
-   *
-   * @param aTarget - accessible target for the given relation.
-   */
-  nsresult AddTarget(nsIAccessible *aTarget);
-
 private:
+  nsAccessibleRelation();
+  nsAccessibleRelation(const nsAccessibleRelation&);
+  nsAccessibleRelation& operator = (const nsAccessibleRelation&);
+  
   PRUint32 mType;
   nsCOMPtr<nsIMutableArray> mTargets;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(nsAccessibleRelation, NS_ACCRELATION_IMPL_CID)
-
 #endif
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -39,22 +39,23 @@
 
 #include "nsXULFormControlAccessible.h"
 
 #include "nsAccessibilityAtoms.h"
 #include "nsAccUtils.h"
 #include "nsAccTreeWalker.h"
 #include "nsCoreUtils.h"
 #include "nsDocAccessible.h"
-#include "nsRelUtils.h"
+#include "Relation.h"
 #include "States.h"
 
 // NOTE: alphabetically ordered
 #include "nsHTMLFormControlAccessible.h"
 #include "nsXULMenuAccessible.h"
+#include "nsIAccessibleRelation.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMXULButtonElement.h"
 #include "nsIDOMXULCheckboxElement.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULTextboxElement.h"
 #include "nsIEditor.h"
@@ -412,58 +413,51 @@ nsXULGroupboxAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_GROUPING;
 }
 
 nsresult
 nsXULGroupboxAccessible::GetNameInternal(nsAString& aName)
 {
   // XXX: we use the first related accessible only.
-  nsCOMPtr<nsIAccessible> label =
-    nsRelUtils::GetRelatedAccessible(this, nsIAccessibleRelation::RELATION_LABELLED_BY);
-
-  if (label) {
+  nsAccessible* label =
+    RelationByType(nsIAccessibleRelation::RELATION_LABELLED_BY).Next();
+  if (label)
     return label->GetName(aName);
-  }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsXULGroupboxAccessible::GetRelationByType(PRUint32 aRelationType,
-                                           nsIAccessibleRelation **aRelation)
+Relation
+nsXULGroupboxAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType, aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
+  Relation rel = nsAccessibleWrap::RelationByType(aType);
+  if (aType != nsIAccessibleRelation::RELATION_LABELLED_BY)
+    return rel;
 
-  if (aRelationType == nsIAccessibleRelation::RELATION_LABELLED_BY) {
-    // The label for xul:groupbox is generated from xul:label that is
-    // inside the anonymous content of the xul:caption.
-    // The xul:label has an accessible object but the xul:caption does not
-    PRInt32 childCount = GetChildCount();
-    for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
-      nsAccessible *childAcc = GetChildAt(childIdx);
-      if (childAcc->Role() == nsIAccessibleRole::ROLE_LABEL) {
-        // Ensure that it's our label
-        // XXX: we'll fail if group accessible expose more than one relation
-        // targets.
-        nsCOMPtr<nsIAccessible> testGroupboxAccessible =
-          nsRelUtils::GetRelatedAccessible(childAcc,
-                                           nsIAccessibleRelation::RELATION_LABEL_FOR);
-
-        if (testGroupboxAccessible == this) {
+  // The label for xul:groupbox is generated from xul:label that is
+  // inside the anonymous content of the xul:caption.
+  // The xul:label has an accessible object but the xul:caption does not
+  PRInt32 childCount = GetChildCount();
+  for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
+    nsAccessible *childAcc = GetChildAt(childIdx);
+    if (childAcc->Role() == nsIAccessibleRole::ROLE_LABEL) {
+      // Ensure that it's our label
+      Relation reverseRel =
+        childAcc->RelationByType(nsIAccessibleRelation::RELATION_LABEL_FOR);
+      nsAccessible* testGroupbox = nsnull;
+      while ((testGroupbox = reverseRel.Next()))
+        if (testGroupbox == this) {
           // The <label> points back to this groupbox
-          return nsRelUtils::
-            AddTarget(aRelationType, aRelation, childAcc);
+          rel.AppendTarget(childAcc);
         }
-      }
     }
   }
 
-  return NS_OK;
+  return rel;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULRadioButtonAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULRadioButtonAccessible::
   nsXULRadioButtonAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
--- a/accessible/src/xul/nsXULFormControlAccessible.h
+++ b/accessible/src/xul/nsXULFormControlAccessible.h
@@ -135,23 +135,20 @@ private:
 /**
  * Used for XUL groupbox element.
  */
 class nsXULGroupboxAccessible : public nsAccessibleWrap
 {
 public:
   nsXULGroupboxAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
-  // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual nsresult GetNameInternal(nsAString& aName);
+  virtual Relation RelationByType(PRUint32 aRelationType);
 };
 
 /**
  * Used for XUL radio element (radio button).
  */
 class nsXULRadioButtonAccessible : public nsRadioButtonAccessible
 {
 
--- a/accessible/src/xul/nsXULTabAccessible.cpp
+++ b/accessible/src/xul/nsXULTabAccessible.cpp
@@ -34,20 +34,21 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXULTabAccessible.h"
 
 #include "nsAccUtils.h"
-#include "nsRelUtils.h"
+#include "Relation.h"
 #include "States.h"
 
 // NOTE: alphabetically ordered
+#include "nsIAccessibleRelation.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULRelatedElement.h"
 
 using namespace mozilla::a11y;
@@ -133,42 +134,38 @@ nsXULTabAccessible::NativeState()
     PRBool selected = PR_FALSE;
     if (NS_SUCCEEDED(tab->GetSelected(&selected)) && selected)
       state |= states::SELECTED;
   }
   return state;
 }
 
 // nsIAccessible
-NS_IMETHODIMP
-nsXULTabAccessible::GetRelationByType(PRUint32 aRelationType,
-                                      nsIAccessibleRelation **aRelation)
+Relation
+nsXULTabAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType,
-                                                    aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aRelationType != nsIAccessibleRelation::RELATION_LABEL_FOR)
-    return NS_OK;
+  Relation rel = nsAccessibleWrap::RelationByType(aType);
+  if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
+    return rel;
 
   // Expose 'LABEL_FOR' relation on tab accessible for tabpanel accessible.
   nsCOMPtr<nsIDOMXULRelatedElement> tabsElm =
     do_QueryInterface(mContent->GetParent());
   if (!tabsElm)
-    return NS_OK;
+    return rel;
 
   nsCOMPtr<nsIDOMNode> DOMNode(GetDOMNode());
   nsCOMPtr<nsIDOMNode> tabpanelNode;
   tabsElm->GetRelatedElement(DOMNode, getter_AddRefs(tabpanelNode));
   if (!tabpanelNode)
-    return NS_OK;
+    return rel;
 
   nsCOMPtr<nsIContent> tabpanelContent(do_QueryInterface(tabpanelNode));
-  return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
-                                          tabpanelContent);
+  rel.AppendTarget(tabpanelContent);
+  return rel;
 }
 
 void
 nsXULTabAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
                                                PRInt32 *aSetSize)
 {
   nsAccUtils::GetPositionAndSizeForXULSelectControlItem(mContent, aPosInSet,
                                                         aSetSize);
@@ -239,34 +236,31 @@ nsXULTabpanelAccessible::
 }
 
 PRUint32
 nsXULTabpanelAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_PROPERTYPAGE;
 }
 
-NS_IMETHODIMP
-nsXULTabpanelAccessible::GetRelationByType(PRUint32 aRelationType,
-                                           nsIAccessibleRelation **aRelation)
+Relation
+nsXULTabpanelAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType, aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aRelationType != nsIAccessibleRelation::RELATION_LABELLED_BY)
-    return NS_OK;
+  Relation rel = nsAccessibleWrap::RelationByType(aType);
+  if (aType != nsIAccessibleRelation::RELATION_LABELLED_BY)
+    return rel;
 
   // Expose 'LABELLED_BY' relation on tabpanel accessible for tab accessible.
   nsCOMPtr<nsIDOMXULRelatedElement> tabpanelsElm =
     do_QueryInterface(mContent->GetParent());
   if (!tabpanelsElm)
-    return NS_OK;
+    return rel;
 
   nsCOMPtr<nsIDOMNode> DOMNode(GetDOMNode());
   nsCOMPtr<nsIDOMNode> tabNode;
   tabpanelsElm->GetRelatedElement(DOMNode, getter_AddRefs(tabNode));
   if (!tabNode)
-    return NS_OK;
+    return rel;
 
   nsCOMPtr<nsIContent> tabContent(do_QueryInterface(tabNode));
-  return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
-                                          tabContent);
+  rel.AppendTarget(tabContent);
+  return rel;
 }
--- a/accessible/src/xul/nsXULTabAccessible.h
+++ b/accessible/src/xul/nsXULTabAccessible.h
@@ -51,24 +51,23 @@ class nsXULTabAccessible : public nsAcce
 public:
   enum { eAction_Switch = 0 };
 
   nsXULTabAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
   // nsIAccessible
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 index);
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
 
   // nsAccessible
   virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
                                           PRInt32 *aSetSize);
   virtual PRUint32 NativeRole();
   virtual PRUint64 NativeState();
+  virtual Relation RelationByType(PRUint32 aType);
 
   // ActionAccessible
   virtual PRUint8 ActionCount();
 };
 
 
 /**
  * A container of tab objects, xul:tabs element.
@@ -113,18 +112,15 @@ public:
  * for example we do not create instance of this class for XUL textbox used as
  * a tabpanel.
  */
 class nsXULTabpanelAccessible : public nsAccessibleWrap
 {
 public:
   nsXULTabpanelAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
-  // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-
   // nsAccessible
   virtual PRUint32 NativeRole();
+  virtual Relation RelationByType(PRUint32 aType);
 };
 
 #endif
 
--- a/accessible/src/xul/nsXULTextAccessible.cpp
+++ b/accessible/src/xul/nsXULTextAccessible.cpp
@@ -39,20 +39,21 @@
 
 // NOTE: groups are alphabetically ordered
 #include "nsXULTextAccessible.h"
 
 #include "nsAccessibilityAtoms.h"
 #include "nsAccUtils.h"
 #include "nsBaseWidgetAccessible.h"
 #include "nsCoreUtils.h"
-#include "nsRelUtils.h"
 #include "nsTextEquivUtils.h"
+#include "Relation.h"
 #include "States.h"
 
+#include "nsIAccessibleRelation.h"
 #include "nsIDOMXULDescriptionElement.h"
 #include "nsINameSpaceManager.h"
 #include "nsString.h"
 #include "nsNetUtil.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -83,35 +84,31 @@ nsXULTextAccessible::NativeRole()
 PRUint64
 nsXULTextAccessible::NativeState()
 {
   // Labels and description have read only state
   // They are not focusable or selectable
   return nsHyperTextAccessibleWrap::NativeState() | states::READONLY;
 }
 
-NS_IMETHODIMP
-nsXULTextAccessible::GetRelationByType(PRUint32 aRelationType,
-                                       nsIAccessibleRelation **aRelation)
+Relation
+nsXULTextAccessible::RelationByType(PRUint32 aType)
 {
-  nsresult rv =
-    nsHyperTextAccessibleWrap::GetRelationByType(aRelationType, aRelation);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aRelationType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
+  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
+  if (aType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
     // Caption is the label for groupbox
     nsIContent *parent = mContent->GetParent();
     if (parent && parent->Tag() == nsAccessibilityAtoms::caption) {
       nsAccessible* parent = Parent();
       if (parent && parent->Role() == nsIAccessibleRole::ROLE_GROUPING)
-        return nsRelUtils::AddTarget(aRelationType, aRelation, parent);
+        rel.AppendTarget(parent);
     }
   }
 
-  return NS_OK;
+  return rel;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTooltipAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULTooltipAccessible::
--- a/accessible/src/xul/nsXULTextAccessible.h
+++ b/accessible/src/xul/nsXULTextAccessible.h
@@ -43,28 +43,24 @@
 #include "nsBaseWidgetAccessible.h"
 #include "nsHyperTextAccessibleWrap.h"
 
 /**
  * Used for XUL description and label elements.
  */
 class nsXULTextAccessible : public nsHyperTextAccessibleWrap
 {
-
 public:
   nsXULTextAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
-  // nsIAccessible
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-
   // nsAccessible
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual PRUint32 NativeRole();
   virtual PRUint64 NativeState();
+  virtual Relation RelationByType(PRUint32 aRelationType);
 };
 
 /**
  * Used for XUL tooltip element.
  */
 class nsXULTooltipAccessible : public nsLeafAccessible
 {
 
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -1,9 +1,10 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -37,19 +38,20 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXULTreeAccessible.h"
 
 #include "nsAccCache.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsDocAccessible.h"
-#include "nsRelUtils.h"
+#include "Relation.h"
 #include "States.h"
 
+#include "nsIAccessibleRelation.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMXULTreeElement.h"
 #include "nsITreeSelection.h"
 #include "nsIMutableArray.h"
 #include "nsComponentManagerUtils.h"
 
 using namespace mozilla::a11y;
@@ -751,42 +753,36 @@ nsXULTreeItemAccessibleBase::TakeFocus()
   mTreeView->GetSelection(getter_AddRefs(selection));
   if (selection)
     selection->SetCurrentIndex(mRow);
 
   // focus event will be fired here
   return nsAccessible::TakeFocus();
 }
 
-NS_IMETHODIMP
-nsXULTreeItemAccessibleBase::GetRelationByType(PRUint32 aRelationType,
-                                               nsIAccessibleRelation **aRelation)
+Relation
+nsXULTreeItemAccessibleBase::RelationByType(PRUint32 aType)
 {
-  NS_ENSURE_ARG_POINTER(aRelation);
-  *aRelation = nsnull;
+  if (aType != nsIAccessibleRelation::RELATION_NODE_CHILD_OF)
+    return nsAccessible::RelationByType(aType);
 
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
-  if (aRelationType == nsIAccessibleRelation::RELATION_NODE_CHILD_OF) {
+  Relation rel;
     PRInt32 parentIndex;
-    if (NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex))) {
-      if (parentIndex == -1)
-        return nsRelUtils::AddTarget(aRelationType, aRelation, mParent);
-
-      nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
+  if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex)))
+    return rel;
 
-      nsAccessible *logicalParent = treeAcc->GetTreeItemAccessible(parentIndex);
-      return nsRelUtils::AddTarget(aRelationType, aRelation, logicalParent);
-    }
-
-    return NS_OK;
+  if (parentIndex == -1) {
+    rel.AppendTarget(mParent);
+    return rel;
   }
 
-  return nsAccessible::GetRelationByType(aRelationType, aRelation);
+  nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
+
+  rel.AppendTarget(treeAcc->GetTreeItemAccessible(parentIndex));
+  return rel;
 }
 
 PRUint8
 nsXULTreeItemAccessibleBase::ActionCount()
 {
   // "activate" action is available for all treeitems, "expand/collapse" action
   // is avaible for treeitem which is container.
   return IsExpandable() ? 2 : 1;
--- a/accessible/src/xul/nsXULTreeAccessible.h
+++ b/accessible/src/xul/nsXULTreeAccessible.h
@@ -183,34 +183,32 @@ public:
 
   // nsIAccessible
   NS_IMETHOD GetBounds(PRInt32 *aX, PRInt32 *aY,
                        PRInt32 *aWidth, PRInt32 *aHeight);
 
   NS_IMETHOD SetSelected(PRBool aSelect); 
   NS_IMETHOD TakeFocus();
 
-  NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
-                               nsIAccessibleRelation **aRelation);
-
   NS_IMETHOD GroupPosition(PRInt32 *aGroupLevel,
                            PRInt32 *aSimilarItemsInGroup,
                            PRInt32 *aPositionInGroup);
 
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsAccessNode
   virtual bool IsDefunct() const;
   virtual void Shutdown();
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual PRUint64 NativeState();
   virtual PRInt32 IndexInParent() const;
+  virtual Relation RelationByType(PRUint32 aType);
   virtual nsAccessible* FocusedChild();
 
   // ActionAccessible
   virtual PRUint8 ActionCount();
 
   // nsXULTreeItemAccessibleBase
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_XULTREEITEMBASEACCESSIBLE_IMPL_CID)