Backed out changeset a00864f6c1a7
authorTrevor Saunders <trev.saunders@gmail.com>
Tue, 09 Aug 2011 19:53:05 -0700
changeset 74108 86b0d5ce1a6d6bf63844101d7b17075aa6c052a7
parent 74107 a00864f6c1a7122f46d74a974d200eedcd8c30fa
child 74109 cbd47dd5a6a164e8572184b7269d12f7386897f1
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone8.0a1
backs outa00864f6c1a7122f46d74a974d200eedcd8c30fa
Backed out changeset a00864f6c1a7
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,16 +77,17 @@ 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)
new file mode 100644
--- /dev/null
+++ b/accessible/src/atk/nsAccessibleRelationWrap.h
@@ -0,0 +1,48 @@
+/* -*- 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,31 +33,29 @@
  * 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"
@@ -938,55 +936,70 @@ refStateSetCB(AtkObject *aAtkObj)
     TranslateStates(accWrap->State(), state_set);
 
     return state_set;
 }
 
 AtkRelationSet *
 refRelationSetCB(AtkObject *aAtkObj)
 {
-  AtkRelationSet* relation_set =
-    ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
+    AtkRelationSet *relation_set = nsnull;
+    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;
+    }
 
-  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,
-  };
+    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,
+                               };
 
-  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);
+    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);
+        }
 
-    Relation rel(accWrap->RelationByType(relationTypes[i]));
-    nsTArray<AtkObject*> targets;
-    nsAccessible* tempAcc = nsnull;
-    while ((tempAcc = rel.Next()))
-      targets.AppendElement(nsAccessibleWrap::GetAtkObject(tempAcc));
+        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);
+                }
 
-    atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
-    atk_relation_set_add(relation_set, atkRelation);
-    g_object_unref(atkRelation);
-  }
+                relation = atk_relation_new(accessible_array, targetsCount,
+                                            static_cast<AtkRelationType>(relationType[i]));
+                atk_relation_set_add(relation_set, relation);
+                g_object_unref(relation);
 
-  return relation_set;
+                delete [] accessible_array;
+            }
+        }
+    }
+
+    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,18 +35,16 @@
  *
  * ***** 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)
@@ -59,17 +57,17 @@ AccIterator::~AccIterator()
   while (mState) {
     IteratorState *tmp = mState;
     mState = tmp->mParentState;
     delete tmp;
   }
 }
 
 nsAccessible*
-AccIterator::Next()
+AccIterator::GetNext()
 {
   while (mState) {
     nsAccessible *child = mState->mParent->GetChildAt(mState->mIndex++);
     if (!child) {
       IteratorState *tmp = mState;
       mState = mState->mParentState;
       delete tmp;
 
@@ -252,98 +250,8 @@ 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,10 +1,8 @@
-/* -*- 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/
  *
@@ -35,42 +33,25 @@
  * 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 : public AccIterable
+class AccIterator
 {
 public:
   /**
    * Used to define iteration type.
    */
   enum IterationType {
     /**
      * Navigation happens through direct children.
@@ -81,23 +62,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);
-  virtual ~AccIterator();
+  ~AccIterator();
 
   /**
    * Return next accessible complying with filter function. Return the first
    * accessible for the first time.
    */
-  virtual nsAccessible *Next();
+  nsAccessible *GetNext();
 
 private:
   AccIterator();
   AccIterator(const AccIterator&);
   AccIterator& operator =(const AccIterator&);
 
   struct IteratorState
   {
@@ -113,38 +94,36 @@ private:
   IteratorState *mState;
 };
 
 
 /**
  * Allows to traverse through related accessibles that are pointing to the given
  * dependent accessible by relation attribute.
  */
-class RelatedAccIterator : public AccIterable
+class RelatedAccIterator
 {
 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.
    */
-  virtual nsAccessible* Next();
+  nsAccessible* Next();
 
 private:
   RelatedAccIterator();
   RelatedAccIterator(const RelatedAccIterator&);
   RelatedAccIterator& operator = (const RelatedAccIterator&);
 
   nsDocAccessible* mDocument;
   nsIAtom* mRelAttr;
@@ -152,168 +131,101 @@ private:
   nsIContent* mBindingParent;
   PRUint32 mIndex;
 };
 
 
 /**
  * Used to iterate through HTML labels associated with the given element.
  */
-class HTMLLabelIterator : public AccIterable
+class HTMLLabelIterator
 {
 public:
   enum LabelFilter {
     eAllLabels,
     eSkipAncestorLabel
   };
 
   HTMLLabelIterator(nsDocAccessible* aDocument, nsIContent* aElement,
                     LabelFilter aFilter = eAllLabels);
 
-  virtual ~HTMLLabelIterator() { }
-
   /**
    * Return next label accessible associated with the given element.
    */
-  virtual nsAccessible* Next();
+  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 : public AccIterable
+class HTMLOutputIterator
 {
 public:
   HTMLOutputIterator(nsDocAccessible* aDocument, nsIContent* aElement);
-  virtual ~HTMLOutputIterator() { }
 
   /**
    * Return next output accessible associated with the given element.
    */
-  virtual nsAccessible* Next();
+  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 : public AccIterable
+class XULLabelIterator
 {
 public:
   XULLabelIterator(nsDocAccessible* aDocument, nsIContent* aElement);
-  virtual ~XULLabelIterator() { }
 
   /**
    * Return next label accessible associated with the given element.
    */
-  virtual nsAccessible* Next();
+  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 : public AccIterable
+class XULDescriptionIterator
 {
 public:
   XULDescriptionIterator(nsDocAccessible* aDocument, nsIContent* aElement);
-  virtual ~XULDescriptionIterator() { }
 
   /**
    * Return next description accessible associated with the given element.
    */
-  virtual nsAccessible* Next();
+  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,18 +58,20 @@ 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 \
deleted file mode 100644
--- a/accessible/src/base/Relation.h
+++ /dev/null
@@ -1,154 +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) 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.Next();
+  nsAccessible* row = rowIter.GetNext();
   if (!row)
     return NS_OK;
 
   AccIterator cellIter(row, filters::GetCell);
   nsAccessible *cell = nsnull;
 
-  while ((cell = cellIter.Next()))
+  while ((cell = cellIter.GetNext()))
     (*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.Next())
+  while (rowIter.GetNext())
     (*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.Next();
+  nsAccessible *row = rowIter.GetNext();
   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.Next()));
+  } while ((row = rowIter.GetNext()));
 
   *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.Next())) {
+    while ((cell = cellIter.GetNext())) {
       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.Next())) {
+  while ((row = rowIter.GetNext())) {
     if (nsAccUtils::IsARIASelected(row)) {
       (*aCount) += colCount;
       continue;
     }
 
     AccIterator cellIter(row, filters::GetCell);
     nsAccessible *cell = nsnull;
 
-    while ((cell = cellIter.Next())) {
+    while ((cell = cellIter.GetNext())) {
       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.Next())) {
+  while ((row = rowIter.GetNext())) {
     if (nsAccUtils::IsARIASelected(row)) {
       (*aCount)++;
       continue;
     }
 
     AccIterator cellIter(row, filters::GetCell);
-    nsAccessible *cell = cellIter.Next();
+    nsAccessible *cell = cellIter.GetNext();
     if (!cell)
       continue;
 
     PRBool isRowSelected = PR_TRUE;
     do {
       if (!nsAccUtils::IsARIASelected(cell)) {
         isRowSelected = PR_FALSE;
         break;
       }
-    } while ((cell = cellIter.Next()));
+    } while ((cell = cellIter.GetNext()));
 
     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.Next())) {
+  while ((row = rowIter.GetNext())) {
     AccIterator cellIter(row, filters::GetCell);
     nsAccessible *cell = nsnull;
 
     if (nsAccUtils::IsARIASelected(row)) {
-      while ((cell = cellIter.Next()))
+      while ((cell = cellIter.GetNext()))
         selCells->AppendElement(static_cast<nsIAccessible *>(cell), PR_FALSE);
 
       continue;
     }
 
-    while ((cell = cellIter.Next())) {
+    while ((cell = cellIter.GetNext())) {
       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.Next()); rowIdx++) {
+  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); 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.Next()); colIdx++) {
+    for (PRInt32 colIdx = 0; (cell = cellIter.GetNext()); 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.Next()); rowIdx++) {
+  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); rowIdx++) {
     if (nsAccUtils::IsARIASelected(row)) {
       selRows.AppendElement(rowIdx);
       continue;
     }
 
     AccIterator cellIter(row, filters::GetCell);
-    nsAccessible *cell = cellIter.Next();
+    nsAccessible *cell = cellIter.GetNext();
     if (!cell)
       continue;
 
     PRBool isRowSelected = PR_TRUE;
     do {
       if (!nsAccUtils::IsARIASelected(cell)) {
         isRowSelected = PR_FALSE;
         break;
       }
-    } while ((cell = cellIter.Next()));
+    } while ((cell = cellIter.GetNext()));
 
     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.Next()); rowIdx++) {
+  for (PRInt32 rowIdx = 0; (row = rowIter.GetNext()); 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.Next())) {
+  while ((row = rowIter.GetNext())) {
     // 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.Next())) {
+  while ((row = rowIter.GetNext())) {
     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.Next();
-  while (rowIdx != 0 && (row = rowIter.Next()))
+  nsAccessible *row = rowIter.GetNext();
+  while (rowIdx != 0 && (row = rowIter.GetNext()))
     rowIdx--;
 
   return row;
 }
 
 nsAccessible*
 nsARIAGridAccessible::GetCellInRowAt(nsAccessible *aRow, PRInt32 aColumn)
 {
   PRInt32 colIdx = aColumn;
 
   AccIterator cellIter(aRow, filters::GetCell);
-  nsAccessible *cell = cellIter.Next();
-  while (colIdx != 0 && (cell = cellIter.Next()))
+  nsAccessible *cell = cellIter.GetNext();
+  while (colIdx != 0 && (cell = cellIter.GetNext()))
     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.Next())) {
+    while ((cell = cellIter.GetNext())) {
       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.Next())) {
+      while ((cell = cellIter.GetNext())) {
         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.Next();
+  nsAccessible *row = rowIter.GetNext();
   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.Next()); colIdx++) {
+    for (colIdx = 0; (cell = cellIter.GetNext()); colIdx++) {
       if (isColSelArray.SafeElementAt(colIdx, PR_FALSE) &&
           !nsAccUtils::IsARIASelected(cell)) {
         isColSelArray[colIdx] = PR_FALSE;
         selColCount--;
       }
     }
-  } while ((row = rowIter.Next()));
+  } while ((row = rowIter.GetNext()));
 
   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,22 +43,20 @@
 
 #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 "nsIAccessibleRelation.h"
+#include "nsRelUtils.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"
@@ -1525,21 +1523,23 @@ 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!
-      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))
+      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))
           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;
 
-      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;
+      nsCOMPtr<nsIAccessible> possibleCombo =
+        nsRelUtils::GetRelatedAccessible(this,
+                                         nsIAccessibleRelation::RELATION_NODE_CHILD_OF);
+      if (nsAccUtils::Role(possibleCombo) == 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,153 +1993,252 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
 }
 
 /* nsIAccessible getAccessibleBelow(); */
 NS_IMETHODIMP nsAccessible::GetAccessibleBelow(nsIAccessible **_retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-nsIContent*
-nsAccessible::GetAtomicRegion() const
+nsIDOMNode* nsAccessible::GetAtomicRegion()
 {
   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();
-
-  return atomic.EqualsLiteral("true") ? loopContent : nsnull;
+  }
+
+  nsCOMPtr<nsIDOMNode> atomicRegion;
+  if (atomic.EqualsLiteral("true")) {
+    atomicRegion = do_QueryInterface(loopContent);
+  }
+  return atomicRegion;
 }
 
 // nsIAccessible getRelationByType()
 NS_IMETHODIMP
-nsAccessible::GetRelationByType(PRUint32 aType,
-                                nsIAccessibleRelation** aRelation)
+nsAccessible::GetRelationByType(PRUint32 aRelationType,
+                                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.
-  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;
+  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;
     }
-    case nsIAccessibleRelation::RELATION_LABELLED_BY: {
-      Relation rel(new IDRefsIterator(mContent,
-                                      nsAccessibilityAtoms::aria_labelledby));
+
+  case nsIAccessibleRelation::RELATION_LABELLED_BY:
+    {
+      rv = nsRelUtils::
+        AddTargetFromIDRefsAttr(aRelationType, aRelation, mContent,
+                                nsAccessibilityAtoms::aria_labelledby);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      nsAccessible* label = nsnull;
       if (mContent->IsHTML()) {
-        rel.AppendIter(new HTMLLabelIterator(GetDocAccessible(), mContent));
-      } else if (mContent->IsXUL()) {
-        rel.AppendIter(new XULLabelIterator(GetDocAccessible(), mContent));
+        HTMLLabelIterator iter(GetDocAccessible(), mContent);
+        while ((label = iter.Next())) {
+          rv = nsRelUtils::AddTarget(aRelationType, aRelation, label);
+          NS_ENSURE_SUCCESS(rv, rv);
+        }
+        return rv;
       }
 
-      return rel;
+      if (mContent->IsXUL()) {
+        XULLabelIterator iter(GetDocAccessible(), mContent);
+        while ((label = iter.Next())) {
+          rv = nsRelUtils::AddTarget(aRelationType, aRelation, label);
+          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_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_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.
+
+  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);
+      }
+
       if (mContent->Tag() == nsAccessibilityAtoms::description &&
-          mContent->IsXUL())
-        rel.AppendIter(new IDRefsIterator(mContent,
-                                          nsAccessibilityAtoms::control));
-
-      return rel;
+          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;
     }
-    case nsIAccessibleRelation::RELATION_NODE_CHILD_OF: {
-      Relation rel(new RelatedAccIterator(GetDocAccessible(), mContent,
-                                            nsAccessibilityAtoms::aria_owns));
-      
+
+  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;
+
       // 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 rel;
-
-        rel.AppendTarget(groupInfo->ConceptualParent());
+          return NS_OK_NO_RELATION_TARGET;
+
+        return nsRelUtils::AddTarget(aRelationType, aRelation,
+                                     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())
-            rel.AppendTarget(Parent());
+            return nsRelUtils::AddTarget(aRelationType, aRelation, Parent());
         }
       }
 
-      return rel;
+      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;
     }
-    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_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_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: {
+
+  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:
+    {
       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 Relation(formContent);
+            return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
+                                                    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"),
@@ -2167,92 +2266,98 @@ nsAccessible::RelationByType(PRUint32 aT
                                                       NS_LITERAL_STRING("default"),
                                                       NS_LITERAL_STRING("true"),
                                                       getter_AddRefs(possibleButtonEl));
                 buttonEl = do_QueryInterface(possibleButtonEl);
               }
             }
           }
           nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl));
-          return Relation(relatedContent);
+          return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
+                                                  relatedContent);
         }
       }
-      return Relation();
+      return NS_OK;
+    }
+
+  case nsIAccessibleRelation::RELATION_MEMBER_OF:
+    {
+      nsCOMPtr<nsIContent> regionContent = do_QueryInterface(GetAtomicRegion());
+      return nsRelUtils::
+        AddTargetFromContent(aRelationType, aRelation, regionContent);
     }
-    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();
+
+  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;
   }
 }
 
 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 = do_QueryElementAt(relations,
-                                                               aIndex, &rv);
-  NS_ADDREF(*aRelation = relation);
-  return 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;
 }
 
 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) {
-      PRUint32 targets = 0;
-      relation->GetTargetsCount(&targets);
-      if (targets)
-        relations->AppendElement(relation, PR_FALSE);
-    }
+    if (NS_SUCCEEDED(rv) && relation)
+      relations->AppendElement(relation, PR_FALSE);
   }
 
   NS_ADDREF(*aRelations = relations);
   return NS_OK;
 }
 
 /* void extendSelection (); */
 NS_IMETHODIMP nsAccessible::ExtendSelection()
@@ -2864,114 +2969,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.Next()))
+  while ((selected = iter.GetNext()))
     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.Next()))
+  while ((selected = iter.GetNext()))
     ++count;
 
   return count;
 }
 
 nsAccessible*
 nsAccessible::GetSelectedItem(PRUint32 aIndex)
 {
   AccIterator iter(this, filters::GetSelected, AccIterator::eTreeNav);
   nsAccessible* selected = nsnull;
 
   PRUint32 index = 0;
-  while ((selected = iter.Next()) && index < aIndex)
+  while ((selected = iter.GetNext()) && 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.Next()) && index < aIndex)
+  while ((selected = iter.GetNext()) && 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.Next()) && index < aIndex)
+  while ((selected = iter.GetNext()) && 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.Next()) && index < aIndex)
+  while ((selected = iter.GetNext()) && 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.Next())) {
+  while((selectable = iter.GetNext())) {
     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.Next())) {
+  while ((selected = iter.GetNext())) {
     success = true;
     selected->SetSelected(PR_FALSE);
   }
   return success;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -57,17 +57,16 @@
 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;
 
@@ -233,21 +232,16 @@ 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 
@@ -668,17 +662,17 @@ protected:
 
   //////////////////////////////////////////////////////////////////////////////
   // Helpers
 
   /**
    *  Get the container node for an atomic region, defined by aria-atomic="true"
    *  @return the container node
    */
-  nsIContent* GetAtomicRegion() const;
+  nsIDOMNode* GetAtomicRegion();
 
   /**
    * 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
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsAccessibleRelation.cpp
@@ -0,0 +1,115 @@
+/* -*- 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) 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 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 "nsAccessibleRelation.h"
+
+#include "nsArrayUtils.h"
+#include "nsComponentManagerUtils.h"
+
+nsAccessibleRelation::
+  nsAccessibleRelation(PRUint32 aType, nsIAccessible *aTarget) :
+  mType(aType)
+{
+  mTargets = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  if (aTarget)
+    mTargets->AppendElement(aTarget, PR_FALSE);
+}
+
+// nsISupports
+NS_IMPL_ISUPPORTS2(nsAccessibleRelation, 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;
+}
+
+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);
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsAccessibleRelation.h
@@ -0,0 +1,83 @@
+/* -*- 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) 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 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 _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 represents an accessible relation.
+ */
+class nsAccessibleRelation: public nsIAccessibleRelation
+{
+public:
+  nsAccessibleRelation(PRUint32 aType, nsIAccessible *aTarget);
+
+  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:
+  PRUint32 mType;
+  nsCOMPtr<nsIMutableArray> mTargets;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsAccessibleRelation, NS_ACCRELATION_IMPL_CID)
+
+#endif
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -37,17 +37,16 @@
  * 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"
@@ -178,20 +177,48 @@ nsApplicationAccessible::FocusedChild()
     nsAccessible* focusedChild =
       GetAccService()->GetAccessible(gLastFocusedNode);
     if (focusedChild && focusedChild->Parent() == this)
       return focusedChild;
   }
   return nsnull;
 }
 
-Relation
-nsApplicationAccessible::RelationByType(PRUint32 aRelationType)
+NS_IMETHODIMP
+nsApplicationAccessible::GetRelationByType(PRUint32 aRelationType,
+                                           nsIAccessibleRelation **aRelation)
+{
+  NS_ENSURE_ARG_POINTER(aRelation);
+  *aRelation = nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsApplicationAccessible::GetRelationsCount(PRUint32 *aCount)
 {
-  return Relation();
+  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;
 }
 
 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,16 +88,21 @@ 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,8 +823,82 @@ 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,16 +36,17 @@
  *
  * ***** 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"
@@ -395,10 +396,44 @@ 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,17 +31,16 @@
  * 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"
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsRelUtils.cpp
@@ -0,0 +1,147 @@
+/* -*- 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;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsRelUtils.h
@@ -0,0 +1,136 @@
+/* -*- 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,26 +33,25 @@
  * 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 "Relation.h"
-#include "States.h"
+#include "nsRelUtils.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"
@@ -826,30 +825,37 @@ nsRootAccessible::GetContentDocShell(nsI
         return aStart;
       }
     }
   }
   return nsnull;
 }
 
 // nsIAccessible method
-Relation
-nsRootAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsRootAccessible::GetRelationByType(PRUint32 aRelationType,
+                                    nsIAccessibleRelation **aRelation)
 {
-  if (!mDocument || aType != nsIAccessibleRelation::RELATION_EMBEDS)
-    return nsDocAccessibleWrap::RelationByType(aType);
+  NS_ENSURE_ARG_POINTER(aRelation);
+  *aRelation = nsnull;
+
+  if (!mDocument || aRelationType != nsIAccessibleRelation::RELATION_EMBEDS) {
+    return nsDocAccessibleWrap::GetRelationByType(aRelationType, aRelation);
+  }
 
   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)
-    return Relation();
+  if (contentTreeItem) {
+    nsDocAccessible *accDoc = nsAccUtils::GetDocAccessibleFor(contentTreeItem);
+    return nsRelUtils::AddTarget(aRelationType, aRelation, accDoc);
+  }
 
-  return Relation(nsAccUtils::GetDocAccessibleFor(contentTreeItem));
+  return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
 void
 nsRootAccessible::HandlePopupShownEvent(nsAccessible* aAccessible)
 {
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -46,18 +46,16 @@
 #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 }    \
 }
 
@@ -70,25 +68,26 @@ 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,17 +34,16 @@
  * 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,23 +33,22 @@
  * 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"
@@ -611,48 +610,72 @@ nsHTMLGroupboxAccessible::GetNameInterna
   if (legendContent) {
     return nsTextEquivUtils::
       AppendTextEquivFromContent(this, legendContent, &aName);
   }
 
   return NS_OK;
 }
 
-Relation
-nsHTMLGroupboxAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsHTMLGroupboxAccessible::GetRelationByType(PRUint32 aRelationType,
+                                            nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
+  nsresult rv = nsHyperTextAccessibleWrap::GetRelationByType(aRelationType,
+                                                             aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aRelationType == nsIAccessibleRelation::RELATION_LABELLED_BY) {
     // No override for label, so use <legend> for this <fieldset>
-  if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
-    rel.AppendTarget(GetLegend());
+    return nsRelUtils::
+      AddTargetFromContent(aRelationType, aRelation, GetLegend());
+  }
 
-  return rel;
+  return NS_OK;
 }
 
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLLegendAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLLegendAccessible::
   nsHTMLLegendAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsHyperTextAccessibleWrap(aContent, aShell)
 {
 }
 
-Relation
-nsHTMLLegendAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsHTMLLegendAccessible::GetRelationByType(PRUint32 aRelationType,
+                                          nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
-  if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
-    return rel;
+  nsresult rv = nsHyperTextAccessibleWrap::
+    GetRelationByType(aRelationType, aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aRelationType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
+    // Look for groupbox parent
+    nsAccessible* groupbox = Parent();
 
-  nsAccessible* groupbox = Parent();
-  if (groupbox && groupbox->Role() == nsIAccessibleRole::ROLE_GROUPING)
-    rel.AppendTarget(groupbox);
+    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);
 
-  return rel;
+      if (testLabelAccessible == this) {
+        // We're the first child of the parent groupbox, see
+        // nsHTMLGroupboxAccessible::GetRelationByType().
+        return nsRelUtils::
+          AddTarget(aRelationType, aRelation, groupbox);
+      }
+    }
+  }
+
+  return NS_OK;
 }
 
 PRUint32
 nsHTMLLegendAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_LABEL;
 }
--- a/accessible/src/html/nsHTMLFormControlAccessible.h
+++ b/accessible/src/html/nsHTMLFormControlAccessible.h
@@ -171,32 +171,38 @@ 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,25 +34,24 @@
  * 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"
@@ -500,24 +499,28 @@ nsHTMLTableAccessible::GetAttributesInte
   }
   
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsIAccessible implementation
 
-Relation
-nsHTMLTableAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsHTMLTableAccessible::GetRelationByType(PRUint32 aRelationType,
+                                         nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsAccessibleWrap::RelationByType(aType);
-  if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
-    rel.AppendTarget(Caption());
+  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType,
+                                                    aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  return rel;
+  if (aRelationType == nsIAccessibleRelation::RELATION_LABELLED_BY)
+    return nsRelUtils::AddTarget(aRelationType, aRelation, Caption());
+
+  return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsIAccessibleTable implementation
 
 NS_IMETHODIMP
 nsHTMLTableAccessible::GetCaption(nsIAccessible **aCaption)
 {
@@ -1513,23 +1516,28 @@ nsHTMLTableAccessible::IsProbablyForLayo
   RETURN_LAYOUT_ANSWER(PR_FALSE, "no layout factor strong enough, so will guess data");
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLCaptionAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
-Relation
-nsHTMLCaptionAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsHTMLCaptionAccessible::GetRelationByType(PRUint32 aRelationType,
+                                           nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsHyperTextAccessible::RelationByType(aType);
-  if (aType == nsIAccessibleRelation::RELATION_LABEL_FOR)
-    rel.AppendTarget(Parent());
+  nsresult rv = nsHyperTextAccessible::GetRelationByType(aRelationType,
+                                                         aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  return rel;
+  if (aRelationType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
+      return nsRelUtils::AddTarget(aRelationType, aRelation, Parent());
+  }
+
+  return NS_OK;
 }
 
 PRUint32
 nsHTMLCaptionAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_CAPTION;
 }
--- a/accessible/src/html/nsHTMLTableAccessible.h
+++ b/accessible/src/html/nsHTMLTableAccessible.h
@@ -125,23 +125,26 @@ 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;
   }
@@ -211,15 +214,16 @@ 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,21 +36,20 @@
  * 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;
@@ -194,24 +193,33 @@ nsHTMLLabelAccessible::NativeRole()
 nsHTMLOutputAccessible::
   nsHTMLOutputAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
   nsHyperTextAccessibleWrap(aContent, aShell)
 {
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLOutputAccessible, nsHyperTextAccessible)
 
-Relation
-nsHTMLOutputAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsHTMLOutputAccessible::GetRelationByType(PRUint32 aRelationType,
+                                          nsIAccessibleRelation** aRelation)
 {
-  Relation rel = nsAccessibleWrap::RelationByType(aType);
-  if (aType == nsIAccessibleRelation::RELATION_CONTROLLED_BY)
-    rel.AppendIter(new IDRefsIterator(mContent, nsAccessibilityAtoms::_for));
+  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType, aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (rv != NS_OK_NO_RELATION_TARGET)
+    return NS_OK; // XXX bug 381599, avoid performance problems
 
-  return rel;
+  if (aRelationType == nsIAccessibleRelation::RELATION_CONTROLLED_BY) {
+    return nsRelUtils::
+      AddTargetFromIDRefsAttr(aRelationType, aRelation, mContent,
+                              nsAccessibilityAtoms::_for);
+  }
+
+  return NS_OK;
 }
 
 PRUint32
 nsHTMLOutputAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_SECTION;
 }
 
--- a/accessible/src/html/nsHTMLTextAccessible.h
+++ b/accessible/src/html/nsHTMLTextAccessible.h
@@ -110,20 +110,23 @@ 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,16 +67,17 @@ 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 \
new file mode 100644
--- /dev/null
+++ b/accessible/src/mac/nsAccessibleRelationWrap.h
@@ -0,0 +1,49 @@
+/* -*- 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,16 +85,17 @@ 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 \
deleted file mode 100644
--- a/accessible/src/msaa/ia2AccessibleRelation.cpp
+++ /dev/null
@@ -1,223 +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 ***** */
-
-#include "ia2AccessibleRelation.h"
-
-#include "Relation.h"
-
-#include "nsIAccessibleRelation.h"
-#include "nsID.h"
-
-#include "AccessibleRelation_i.c"
-
-ia2AccessibleRelation::ia2AccessibleRelation(PRUint32 aType, Relation* aRel) :
-  mType(aType), mReferences(0)
-{
-  nsAccessible* target = nsnull;
-  while ((target = aRel->Next()))
-    mTargets.AppendElement(target);
-}
-
-// IUnknown
-
-STDMETHODIMP
-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
-ia2AccessibleRelation::get_relationType(BSTR *aRelationType)
-{
-__try {
-  if (!aRelationType)
-    return E_INVALIDARG;
-
-  *aRelationType = NULL;
-
-  switch (mType) {
-    case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
-      *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLED_BY);
-      break;
-    case nsIAccessibleRelation::RELATION_CONTROLLER_FOR:
-      *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLER_FOR);
-      break;
-    case nsIAccessibleRelation::RELATION_DESCRIBED_BY:
-      *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIBED_BY);
-      break;
-    case nsIAccessibleRelation::RELATION_DESCRIPTION_FOR:
-      *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIPTION_FOR);
-      break;
-    case nsIAccessibleRelation::RELATION_EMBEDDED_BY:
-      *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDDED_BY);
-      break;
-    case nsIAccessibleRelation::RELATION_EMBEDS:
-      *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDS);
-      break;
-    case nsIAccessibleRelation::RELATION_FLOWS_FROM:
-      *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_FROM);
-      break;
-    case nsIAccessibleRelation::RELATION_FLOWS_TO:
-      *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_TO);
-      break;
-    case nsIAccessibleRelation::RELATION_LABEL_FOR:
-      *aRelationType = ::SysAllocString(IA2_RELATION_LABEL_FOR);
-      break;
-    case nsIAccessibleRelation::RELATION_LABELLED_BY:
-      *aRelationType = ::SysAllocString(IA2_RELATION_LABELED_BY);
-      break;
-    case nsIAccessibleRelation::RELATION_MEMBER_OF:
-      *aRelationType = ::SysAllocString(IA2_RELATION_MEMBER_OF);
-      break;
-    case nsIAccessibleRelation::RELATION_NODE_CHILD_OF:
-      *aRelationType = ::SysAllocString(IA2_RELATION_NODE_CHILD_OF);
-      break;
-    case nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF:
-      *aRelationType = ::SysAllocString(IA2_RELATION_PARENT_WINDOW_OF);
-      break;
-    case nsIAccessibleRelation::RELATION_POPUP_FOR:
-      *aRelationType = ::SysAllocString(IA2_RELATION_POPUP_FOR);
-      break;
-    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
-ia2AccessibleRelation::get_localizedRelationType(BSTR *aLocalizedRelationType)
-{
-__try {
-  if (!aLocalizedRelationType)
-    return E_INVALIDARG;
-
-  *aLocalizedRelationType = NULL;
-
-} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return E_NOTIMPL;
-}
-
-STDMETHODIMP
-ia2AccessibleRelation::get_nTargets(long *aNTargets)
-{
-__try {
- if (!aNTargets)
-   return E_INVALIDARG;
-
- *aNTargets = mTargets.Length();
-  return S_OK;
-} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return E_FAIL;
-}
-
-STDMETHODIMP
-ia2AccessibleRelation::get_target(long aTargetIndex, IUnknown **aTarget)
-{
-__try {
-  if (aTargetIndex < 0 || aTargetIndex >= mTargets.Length() || !aTarget)
-    return E_INVALIDARG;
-
-  mTargets[aTargetIndex]->QueryInterface((const nsID&) IID_IUnknown, (void**) aTarget);
-  return S_OK;
-
-} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return E_FAIL;
-}
-
-STDMETHODIMP
-ia2AccessibleRelation::get_targets(long aMaxTargets, IUnknown **aTargets,
-                                   long *aNTargets)
-{
-__try {
-  if (!aNTargets || !aTargets)
-    return E_INVALIDARG;
-
-  *aNTargets = 0;
-  PRUint32 maxTargets = mTargets.Length();
-  if (maxTargets > aMaxTargets)
-    maxTargets = aMaxTargets;
-
-  for (PRUint32 idx = 0; idx < maxTargets; idx++)
-    get_target(idx, aTargets + idx);
-
-  *aNTargets = maxTargets;
-  return S_OK;
-
-} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return E_FAIL;
-}
-
deleted file mode 100644
--- a/accessible/src/msaa/ia2AccessibleRelation.h
+++ /dev/null
@@ -1,94 +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 "nsAccessible.h"
-
-#include "nsTArray.h"
-
-#include "AccessibleRelation.h"
-
-class ia2AccessibleRelation : public IAccessibleRelation
-{
-public:
-  ia2AccessibleRelation(PRUint32 aType, Relation* aRel);
-  virtual ~ia2AccessibleRelation() { }
-
-  // IUnknown
-  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);
-
-  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nTargets(
-      /* [retval][out] */ long *nTargets);
-
-  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_target(
-      /* [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
-
new file mode 100644
--- /dev/null
+++ b/accessible/src/msaa/nsAccessibleRelationWrap.cpp
@@ -0,0 +1,257 @@
+/* -*- 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 ***** */
+
+#include "nsAccessibleRelationWrap.h"
+
+#include "AccessibleRelation_i.c"
+#include "nsAccessNodeWrap.h"
+
+#include "nsArrayUtils.h"
+
+nsAccessibleRelationWrap::
+  nsAccessibleRelationWrap(PRUint32 aType, nsIAccessible *aTarget) :
+  nsAccessibleRelation(aType, aTarget)
+{
+}
+
+// ISupports
+
+NS_IMPL_ISUPPORTS_INHERITED1(nsAccessibleRelationWrap, nsAccessibleRelation,
+                             nsIWinAccessNode)
+
+// nsIWinAccessNode
+
+NS_IMETHODIMP
+nsAccessibleRelationWrap::QueryNativeInterface(REFIID aIID, void** aInstancePtr)
+{
+  return QueryInterface(aIID, aInstancePtr);
+}
+
+// IUnknown
+
+STDMETHODIMP
+nsAccessibleRelationWrap::QueryInterface(REFIID iid, void** ppv)
+{
+  *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;
+}
+
+// IAccessibleRelation
+
+STDMETHODIMP
+nsAccessibleRelationWrap::get_relationType(BSTR *aRelationType)
+{
+__try {
+  *aRelationType = NULL;
+
+  PRUint32 type = 0;
+  nsresult rv = GetRelationType(&type);
+  if (NS_FAILED(rv))
+    return GetHRESULT(rv);
+
+  switch (type) {
+    case RELATION_CONTROLLED_BY:
+      *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLED_BY);
+      break;
+    case RELATION_CONTROLLER_FOR:
+      *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLER_FOR);
+      break;
+    case RELATION_DESCRIBED_BY:
+      *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIBED_BY);
+      break;
+    case RELATION_DESCRIPTION_FOR:
+      *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIPTION_FOR);
+      break;
+    case RELATION_EMBEDDED_BY:
+      *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDDED_BY);
+      break;
+    case RELATION_EMBEDS:
+      *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDS);
+      break;
+    case RELATION_FLOWS_FROM:
+      *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_FROM);
+      break;
+    case RELATION_FLOWS_TO:
+      *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_TO);
+      break;
+    case RELATION_LABEL_FOR:
+      *aRelationType = ::SysAllocString(IA2_RELATION_LABEL_FOR);
+      break;
+    case RELATION_LABELLED_BY:
+      *aRelationType = ::SysAllocString(IA2_RELATION_LABELED_BY);
+      break;
+    case RELATION_MEMBER_OF:
+      *aRelationType = ::SysAllocString(IA2_RELATION_MEMBER_OF);
+      break;
+    case RELATION_NODE_CHILD_OF:
+      *aRelationType = ::SysAllocString(IA2_RELATION_NODE_CHILD_OF);
+      break;
+    case RELATION_PARENT_WINDOW_OF:
+      *aRelationType = ::SysAllocString(IA2_RELATION_PARENT_WINDOW_OF);
+      break;
+    case RELATION_POPUP_FOR:
+      *aRelationType = ::SysAllocString(IA2_RELATION_POPUP_FOR);
+      break;
+    case 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)
+{
+__try {
+  *aLocalizedRelationType = NULL;
+
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP
+nsAccessibleRelationWrap::get_nTargets(long *aNTargets)
+{
+__try {
+  *aNTargets = 0;
+
+  PRUint32 count = 0;
+  nsresult rv = GetTargetsCount(&count);
+  if (NS_FAILED(rv))
+    return GetHRESULT(rv);
+
+  *aNTargets = count;
+  return S_OK;
+
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+  return E_FAIL;
+}
+
+STDMETHODIMP
+nsAccessibleRelationWrap::get_target(long aTargetIndex, IUnknown **aTarget)
+{
+__try {
+  nsCOMPtr<nsIAccessible> accessible;
+  nsresult rv = GetTarget(aTargetIndex, getter_AddRefs(accessible));
+  if (NS_FAILED(rv))
+    return GetHRESULT(rv);
+
+  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);
+  return S_OK;
+
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+  return E_FAIL;
+}
+
+STDMETHODIMP
+nsAccessibleRelationWrap::get_targets(long aMaxTargets, IUnknown **aTarget,
+                                      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;
+
+  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;
+
+    aTarget[index] = static_cast<IUnknown*>(instancePtr);
+  }
+
+  if (NS_FAILED(rv)) {
+    for (PRUint32 index2 = 0; index2 < index; index2++) {
+      aTarget[index2]->Release();
+      aTarget[index2] = NULL;
+    }
+    return GetHRESULT(rv);
+  }
+
+  *aNTargets = count;
+  return S_OK;
+
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+  return E_FAIL;
+}
+
new file mode 100644
--- /dev/null
+++ b/accessible/src/msaa/nsAccessibleRelationWrap.h
@@ -0,0 +1,88 @@
+/* -*- 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"
+#include "AccessibleRelation.h"
+
+#include "nsIWinAccessNode.h"
+#include "nsISupports.h"
+
+class nsAccessibleRelationWrap: public nsAccessibleRelation,
+                                public nsIWinAccessNode,
+                                public IAccessibleRelation
+{
+public:
+  nsAccessibleRelationWrap(PRUint32 aType, nsIAccessible *aTarget);
+
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIWinAccessNode
+  NS_DECL_NSIWINACCESSNODE
+
+  // IUnknown
+  STDMETHODIMP QueryInterface(REFIID, void**);
+
+  // IAccessibleRelation
+  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationType(
+      /* [retval][out] */ BSTR *relationType);
+
+  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedRelationType(
+      /* [retval][out] */ BSTR *localizedRelationType);
+
+  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nTargets(
+      /* [retval][out] */ long *nTargets);
+
+  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_target(
+      /* [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);
+
+};
+
+#endif
+
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -36,25 +36,22 @@
  *
  * ***** 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"
@@ -892,25 +889,23 @@ STDMETHODIMP nsAccessibleWrap::accNaviga
       break;
     case NAVRELATION_DESCRIPTION_FOR:
       xpRelation = nsIAccessibleRelation::RELATION_DESCRIPTION_FOR;
       break;
   }
 
   pvarEndUpAt->vt = VT_EMPTY;
 
-  if (xpRelation) {
-    Relation rel = RelationByType(xpRelation);
-    xpAccessibleResult = rel.Next();
-  }
+  if (xpRelation)
+    xpAccessibleResult = nsRelUtils::GetRelatedAccessible(this, xpRelation);
 
   if (xpAccessibleResult) {
     pvarEndUpAt->pdispVal = NativeAccessible(xpAccessibleResult);
     pvarEndUpAt->vt = VT_DISPATCH;
-    return S_OK;
+    return NS_OK;
   }
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP nsAccessibleWrap::accHitTest(
       /* [in] */ long xLeft,
       /* [in] */ long yTop,
@@ -1056,94 +1051,104 @@ nsAccessibleWrap::Clone(IEnumVARIANT FAR
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibleWrap. IAccessible2
 
 STDMETHODIMP
 nsAccessibleWrap::get_nRelations(long *aNRelations)
 {
 __try {
-  if (!aNRelations)
-    return E_INVALIDARG;
-
-  *aNRelations = 0;
-
-  if (IsDefunct())
-    return E_FAIL;
+  PRUint32 count = 0;
+  nsresult rv = GetRelationsCount(&count);
+  *aNRelations = count;
 
-  for (PRUint32 relType = nsIAccessibleRelation::RELATION_FIRST;
-       relType <= nsIAccessibleRelation::RELATION_LAST; relType++) {
-    Relation rel = RelationByType(relType);
-    if (rel.Next())
-      (*aNRelations)++;
-  }
-  return S_OK;
+  return GetHRESULT(rv);
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_relation(long aRelationIndex,
                                IAccessibleRelation **aRelation)
 {
 __try {
-  if (!aRelation)
-    return E_INVALIDARG;
-
   *aRelation = NULL;
 
-  if (IsDefunct())
+  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)
     return E_FAIL;
 
-  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;
-      }
+  void *instancePtr = NULL;
+  rv =  winAccessNode->QueryNativeInterface(IID_IAccessibleRelation,
+                                            &instancePtr);
+  if (NS_FAILED(rv))
+    return GetHRESULT(rv);
 
-      relIdx++;
-    }
-  }
+  *aRelation = static_cast<IAccessibleRelation*>(instancePtr);
+  return S_OK;
 
-  return E_INVALIDARG;
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_relations(long aMaxRelations,
                                 IAccessibleRelation **aRelation,
                                 long *aNRelations)
 {
 __try {
-  if (!aRelation || !aNRelations)
-    return E_INVALIDARG;
-
+  *aRelation = NULL;
   *aNRelations = 0;
 
-  if (IsDefunct())
-    return E_FAIL;
+  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;
 
-  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)++;
+  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);
+  }
+
+  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,16 +61,17 @@ 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
 
new file mode 100644
--- /dev/null
+++ b/accessible/src/other/nsAccessibleRelationWrap.h
@@ -0,0 +1,49 @@
+/* -*- 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,17 +44,16 @@ 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 = \
deleted file mode 100644
--- a/accessible/src/xpcom/nsAccessibleRelation.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 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 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 "nsAccessibleRelation.h"
-
-#include "Relation.h"
-#include "nsAccessible.h"
-
-#include "nsArrayUtils.h"
-#include "nsComponentManagerUtils.h"
-
-nsAccessibleRelation::nsAccessibleRelation(PRUint32 aType,
-                                           Relation* aRel) :
-  mType(aType)
-{
-  mTargets = do_CreateInstance(NS_ARRAY_CONTRACTID);
-  nsIAccessible* targetAcc = nsnull;
-  while ((targetAcc = aRel->Next()))
-    mTargets->AppendElement(targetAcc, false);
-}
-
-// nsISupports
-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;
-  return mTargets->GetLength(aCount);
-}
-
-NS_IMETHODIMP
-nsAccessibleRelation::GetTarget(PRUint32 aIndex, nsIAccessible **aTarget)
-{
-  NS_ENSURE_ARG_POINTER(aTarget);
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIAccessible> target = do_QueryElementAt(mTargets, aIndex, &rv);
-  target.forget(aTarget);
-  return rv;
-}
-
-NS_IMETHODIMP
-nsAccessibleRelation::GetTargets(nsIArray **aTargets)
-{
-  NS_ENSURE_ARG_POINTER(aTargets);
-  NS_ADDREF(*aTargets = mTargets);
-  return NS_OK;
-}
deleted file mode 100644
--- a/accessible/src/xpcom/nsAccessibleRelation.h
+++ /dev/null
@@ -1,69 +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) 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 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 _nsAccessibleRelation_H_
-#define _nsAccessibleRelation_H_
-
-#include "nsIAccessibleRelation.h"
-
-#include "nsCOMPtr.h"
-#include "nsIMutableArray.h"
-
-class Relation;
-
-/**
- * Class represents an accessible relation.
- */
-class nsAccessibleRelation: public nsIAccessibleRelation
-{
-public:
-  nsAccessibleRelation(PRUint32 aType, Relation* aRel);
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIACCESSIBLERELATION
-
-private:
-  nsAccessibleRelation();
-  nsAccessibleRelation(const nsAccessibleRelation&);
-  nsAccessibleRelation& operator = (const nsAccessibleRelation&);
-  
-  PRUint32 mType;
-  nsCOMPtr<nsIMutableArray> mTargets;
-};
-
-#endif
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -39,23 +39,22 @@
 
 #include "nsXULFormControlAccessible.h"
 
 #include "nsAccessibilityAtoms.h"
 #include "nsAccUtils.h"
 #include "nsAccTreeWalker.h"
 #include "nsCoreUtils.h"
 #include "nsDocAccessible.h"
-#include "Relation.h"
+#include "nsRelUtils.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"
@@ -413,51 +412,58 @@ nsXULGroupboxAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_GROUPING;
 }
 
 nsresult
 nsXULGroupboxAccessible::GetNameInternal(nsAString& aName)
 {
   // XXX: we use the first related accessible only.
-  nsAccessible* label =
-    RelationByType(nsIAccessibleRelation::RELATION_LABELLED_BY).Next();
-  if (label)
+  nsCOMPtr<nsIAccessible> label =
+    nsRelUtils::GetRelatedAccessible(this, nsIAccessibleRelation::RELATION_LABELLED_BY);
+
+  if (label) {
     return label->GetName(aName);
+  }
 
   return NS_OK;
 }
 
-Relation
-nsXULGroupboxAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsXULGroupboxAccessible::GetRelationByType(PRUint32 aRelationType,
+                                           nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsAccessibleWrap::RelationByType(aType);
-  if (aType != nsIAccessibleRelation::RELATION_LABELLED_BY)
-    return rel;
+  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType, aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // 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) {
+  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> points back to this groupbox
-          rel.AppendTarget(childAcc);
+          return nsRelUtils::
+            AddTarget(aRelationType, aRelation, childAcc);
         }
+      }
     }
   }
 
-  return rel;
+  return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULRadioButtonAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULRadioButtonAccessible::
   nsXULRadioButtonAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
--- a/accessible/src/xul/nsXULFormControlAccessible.h
+++ b/accessible/src/xul/nsXULFormControlAccessible.h
@@ -135,20 +135,23 @@ 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,21 +34,20 @@
  * 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 "Relation.h"
+#include "nsRelUtils.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;
@@ -134,38 +133,42 @@ nsXULTabAccessible::NativeState()
     PRBool selected = PR_FALSE;
     if (NS_SUCCEEDED(tab->GetSelected(&selected)) && selected)
       state |= states::SELECTED;
   }
   return state;
 }
 
 // nsIAccessible
-Relation
-nsXULTabAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsXULTabAccessible::GetRelationByType(PRUint32 aRelationType,
+                                      nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsAccessibleWrap::RelationByType(aType);
-  if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
-    return rel;
+  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType,
+                                                    aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aRelationType != nsIAccessibleRelation::RELATION_LABEL_FOR)
+    return NS_OK;
 
   // Expose 'LABEL_FOR' relation on tab accessible for tabpanel accessible.
   nsCOMPtr<nsIDOMXULRelatedElement> tabsElm =
     do_QueryInterface(mContent->GetParent());
   if (!tabsElm)
-    return rel;
+    return NS_OK;
 
   nsCOMPtr<nsIDOMNode> DOMNode(GetDOMNode());
   nsCOMPtr<nsIDOMNode> tabpanelNode;
   tabsElm->GetRelatedElement(DOMNode, getter_AddRefs(tabpanelNode));
   if (!tabpanelNode)
-    return rel;
+    return NS_OK;
 
   nsCOMPtr<nsIContent> tabpanelContent(do_QueryInterface(tabpanelNode));
-  rel.AppendTarget(tabpanelContent);
-  return rel;
+  return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
+                                          tabpanelContent);
 }
 
 void
 nsXULTabAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
                                                PRInt32 *aSetSize)
 {
   nsAccUtils::GetPositionAndSizeForXULSelectControlItem(mContent, aPosInSet,
                                                         aSetSize);
@@ -236,31 +239,34 @@ nsXULTabpanelAccessible::
 }
 
 PRUint32
 nsXULTabpanelAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_PROPERTYPAGE;
 }
 
-Relation
-nsXULTabpanelAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsXULTabpanelAccessible::GetRelationByType(PRUint32 aRelationType,
+                                           nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsAccessibleWrap::RelationByType(aType);
-  if (aType != nsIAccessibleRelation::RELATION_LABELLED_BY)
-    return rel;
+  nsresult rv = nsAccessibleWrap::GetRelationByType(aRelationType, aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aRelationType != nsIAccessibleRelation::RELATION_LABELLED_BY)
+    return NS_OK;
 
   // Expose 'LABELLED_BY' relation on tabpanel accessible for tab accessible.
   nsCOMPtr<nsIDOMXULRelatedElement> tabpanelsElm =
     do_QueryInterface(mContent->GetParent());
   if (!tabpanelsElm)
-    return rel;
+    return NS_OK;
 
   nsCOMPtr<nsIDOMNode> DOMNode(GetDOMNode());
   nsCOMPtr<nsIDOMNode> tabNode;
   tabpanelsElm->GetRelatedElement(DOMNode, getter_AddRefs(tabNode));
   if (!tabNode)
-    return rel;
+    return NS_OK;
 
   nsCOMPtr<nsIContent> tabContent(do_QueryInterface(tabNode));
-  rel.AppendTarget(tabContent);
-  return rel;
+  return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
+                                          tabContent);
 }
--- a/accessible/src/xul/nsXULTabAccessible.h
+++ b/accessible/src/xul/nsXULTabAccessible.h
@@ -51,23 +51,24 @@ 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.
@@ -112,15 +113,18 @@ 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,21 +39,20 @@
 
 // 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;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -84,31 +83,35 @@ nsXULTextAccessible::NativeRole()
 PRUint64
 nsXULTextAccessible::NativeState()
 {
   // Labels and description have read only state
   // They are not focusable or selectable
   return nsHyperTextAccessibleWrap::NativeState() | states::READONLY;
 }
 
-Relation
-nsXULTextAccessible::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsXULTextAccessible::GetRelationByType(PRUint32 aRelationType,
+                                       nsIAccessibleRelation **aRelation)
 {
-  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
-  if (aType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
+  nsresult rv =
+    nsHyperTextAccessibleWrap::GetRelationByType(aRelationType, aRelation);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aRelationType == 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)
-        rel.AppendTarget(parent);
+        return nsRelUtils::AddTarget(aRelationType, aRelation, parent);
     }
   }
 
-  return rel;
+  return NS_OK;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTooltipAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULTooltipAccessible::
--- a/accessible/src/xul/nsXULTextAccessible.h
+++ b/accessible/src/xul/nsXULTextAccessible.h
@@ -43,24 +43,28 @@
 #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,10 +1,9 @@
 /* -*- 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/
  *
@@ -38,20 +37,19 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXULTreeAccessible.h"
 
 #include "nsAccCache.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsDocAccessible.h"
-#include "Relation.h"
+#include "nsRelUtils.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;
@@ -753,36 +751,42 @@ nsXULTreeItemAccessibleBase::TakeFocus()
   mTreeView->GetSelection(getter_AddRefs(selection));
   if (selection)
     selection->SetCurrentIndex(mRow);
 
   // focus event will be fired here
   return nsAccessible::TakeFocus();
 }
 
-Relation
-nsXULTreeItemAccessibleBase::RelationByType(PRUint32 aType)
+NS_IMETHODIMP
+nsXULTreeItemAccessibleBase::GetRelationByType(PRUint32 aRelationType,
+                                               nsIAccessibleRelation **aRelation)
 {
-  if (aType != nsIAccessibleRelation::RELATION_NODE_CHILD_OF)
-    return nsAccessible::RelationByType(aType);
+  NS_ENSURE_ARG_POINTER(aRelation);
+  *aRelation = nsnull;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
 
-  Relation rel;
+  if (aRelationType == nsIAccessibleRelation::RELATION_NODE_CHILD_OF) {
     PRInt32 parentIndex;
-  if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex)))
-    return rel;
+    if (NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex))) {
+      if (parentIndex == -1)
+        return nsRelUtils::AddTarget(aRelationType, aRelation, mParent);
+
+      nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
 
-  if (parentIndex == -1) {
-    rel.AppendTarget(mParent);
-    return rel;
+      nsAccessible *logicalParent = treeAcc->GetTreeItemAccessible(parentIndex);
+      return nsRelUtils::AddTarget(aRelationType, aRelation, logicalParent);
+    }
+
+    return NS_OK;
   }
 
-  nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
-
-  rel.AppendTarget(treeAcc->GetTreeItemAccessible(parentIndex));
-  return rel;
+  return nsAccessible::GetRelationByType(aRelationType, aRelation);
 }
 
 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,32 +183,34 @@ 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)