Bug 374487 - provide API to support multiple targets for the same relation, r=aaronlev
authorsurkov.alexander@gmail.com
Sat, 19 May 2007 19:41:33 -0700
changeset 1628 d8c140ab20e7118b86fa368522e364a0fb9a500c
parent 1627 3cb11068b724d2a75ee0e88a51d87f0b445e7208
child 1629 ef446573ca8dd62c70e2fe25d8361821ab8a2e94
push idunknown
push userunknown
push dateunknown
reviewersaaronlev
bugs374487
milestone1.9a5pre
Bug 374487 - provide API to support multiple targets for the same relation, r=aaronlev
accessible/public/Makefile.in
accessible/public/nsIAccessible.idl
accessible/public/nsIAccessibleRelation.idl
accessible/src/atk/nsAccessibleWrap.cpp
accessible/src/base/Makefile.in
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/base/nsAccessibleRelation.cpp
accessible/src/base/nsAccessibleRelation.h
accessible/src/base/nsRootAccessible.cpp
accessible/src/msaa/nsAccessibleWrap.cpp
accessible/src/msaa/nsAccessibleWrap.h
accessible/src/xul/nsXULTreeAccessible.cpp
--- a/accessible/public/Makefile.in
+++ b/accessible/public/Makefile.in
@@ -50,16 +50,17 @@ MODULE    = accessibility
 XPIDL_MODULE= accessibility
 GRE_MODULE	= 1
 
 XPIDLSRCS = \
       nsIAccessibleTypes.idl \
       nsIAccessibilityService.idl \
       nsIAccessibleRetrieval.idl \
       nsIAccessible.idl \
+      nsIAccessibleRelation.idl \
       nsIAccessibleRole.idl \
       nsIAccessibleStates.idl \
       nsPIAccessible.idl \
       nsIAccessibleCaret.idl \
       nsIAccessibleDocument.idl \
       nsPIAccessibleDocument.idl \
       nsIAccessibleProvider.idl \
       nsIAccessibleSelectable.idl \
--- a/accessible/public/nsIAccessible.idl
+++ b/accessible/public/nsIAccessible.idl
@@ -39,30 +39,31 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "nsIArray.idl"
 
 interface nsIPersistentProperties;
 interface nsIDOMDOMStringList;
+interface nsIAccessibleRelation;
 
 /**
  * A cross-platform interface that supports platform-specific 
  * accessibility APIs like MSAA and ATK. Contains the sum of what's needed
  * to support IAccessible as well as ATK's generic accessibility objects.
  * Can also be used by in-process accessibility clients to get information
  * about objects in the accessible tree. The accessible tree is a subset of 
  * nodes in the DOM tree -- such as documents, focusable elements and text.
  * Mozilla creates the implementations of nsIAccessible on demand.
  * See http://www.mozilla.org/projects/ui/accessibility for more information.
  *
  * @status UNDER_REVIEW
  */
-[scriptable, uuid(b3674866-49a9-4cf2-bfea-c00be2d4a695)]
+[scriptable, uuid(004b6882-2df1-49df-bb5f-0fb81a5b1edf)]
 interface nsIAccessible : nsISupports
 {
   /**
    * Parent node in accessible tree.
    */
   readonly attribute nsIAccessible parent;
 
   /**
@@ -217,21 +218,39 @@ interface nsIAccessible : nsISupports
   nsIAccessible getAccessibleAbove();
 
   /**
    * Accessible node geometrically below this one
    */
   nsIAccessible getAccessibleBelow();
 
   /**
-   * Accessible node related to this one 
+   * Return accessible related to this one by the given relation type (see.
+   * constants defined in nsIAccessibleRelation).
    */
   nsIAccessible getAccessibleRelated(in unsigned long aRelationType);
 
   /**
+   * Returns the number of accessible relations for this object.
+   */
+  readonly attribute unsigned long relationsCount;
+
+  /**
+   * Returns one accessible relation for this object.
+   *
+   * @param index - relation index (0-based)
+   */
+  nsIAccessibleRelation getRelation(in unsigned long index);
+
+  /**
+   * Returns multiple accessible relations for this object.
+   */
+  nsIArray getRelations();
+
+  /**
    * Return accessible's x and y coordinates relative to the screen and
    * accessible's width and height.
    */
   void getBounds(out long x, out long y, out long width, out long height);
 
   /**
    * Add or remove this accessible to the current selection
    */
@@ -279,86 +298,10 @@ interface nsIAccessible : nsISupports
    */
   void doAction(in PRUint8 index);   
 
   /**
    * Get a pointer to accessibility interface for this node, which is specific 
    * to the OS/accessibility toolkit we're running on.
    */
   [noscript] void getNativeInterface(out voidPtr aOutAccessible);
-
-  /**
-   * API states we map from opposite states
-   *   VISIBLE -- mapped as the opposite of INVISIBLE
-   *   SHOWING -- mapped as the opposite of OFFSCREEN
-   *
-   * ATK states we don't have in nsIAccessible:
-   *   ARMED -- no clear use case, used briefly when button is activated
-   *   HAS_TOOLTIP -- no known use case
-   *   ICONIFIED -- Mozilla does not have elements which are collapsable into icons
-   *   TRUNCATED -- need use case. Indicates that an object's onscreen content is truncated, e.g. a text value in a spreadsheet cell. No IA2 state.
-   */   
+};
 
-/**
- * Relation Types -- most of these come from ATK's atkrelationtype.h
- * When adding support for relations, make sure to add them to appropriate
- * places in nsAccessibleWrap implementations
- * RELATION_NULL:
- * RELATION_CONTROLLED_BY:    Controlled by one or more target objects.
- * RELATION_CONTROLLER_FOR:   Controller for one or more target objects.
- * RELATION_LABEL_FOR:        Label for one or more target objects.
- * RELATION_LABELLED_BY:      Labelled by one or more target objects.
- * RELATION_MEMBER_OF:        Member of a group of one or more target objects.
- * RELATION_NODE_CHILD_OF:    Cell in a treetable which is displayed because a
- *                            cell in the same col is expanded & identifies it.
- * RELATION_FLOWS_TO:         Has content that flows logically to another
- *                            object in a sequential way, e.g. text flow.
- * RELATION_FLOWS_FROM:       Has content that flows logically from another
- *                            object in a sequential way, e.g. text flow.
- * RELATION_SUBWINDOW_OF:     Subwindow attached to a component but otherwise 
- *                            not connected in the UI hierarchy to that component.
- * RELATION_EMBEDS:           Visually embeds another object's content, i.e.
- *                            this object's content flows around another's content.
- * RELATION_EMBEDDED_BY:      Inverse of RELATION_EMBEDS; this object's content
- *                            is visually embedded in another object.
- * RELATION_POPUP_FOR:        Popup for another object.
- * RELATION_PARENT_WINDOW_OF: Parent window of another object.
- * RELATION_DEFAULT_BUTTON:   Part of a form/dialog with a related default button.
- * RELATION_DESCRIBED_BY:     Described by one or more target objects.
- * RELATION_DESCRIPTION_FOR:  Description for one or more target objects.
- */
-
-  const unsigned long RELATION_NUL = 0x00;               // ATK_RELATION_NUL
-  const unsigned long RELATION_CONTROLLED_BY = 0x01;     // ATK_RELATION_CONTROLLED_BY
-  const unsigned long RELATION_CONTROLLER_FOR = 0x02;    // ATK_RELATION_CONTROLLER_FOR
-  const unsigned long RELATION_LABEL_FOR = 0x03;         // ATK_RELATION_LABEL_FOR
-  const unsigned long RELATION_LABELLED_BY = 0x04;       // ATK_RELATION_LABELLED_BY
-  const unsigned long RELATION_MEMBER_OF = 0x05;         // ATK_RELATION_MEMBER_OF
-  const unsigned long RELATION_NODE_CHILD_OF = 0x06;     // ATK_RELATION_NODE_CHILD_OF
-  const unsigned long RELATION_FLOWS_TO = 0x07;          // ATK_RELATION_FLOWS_TO
-  const unsigned long RELATION_FLOWS_FROM = 0x08;        // ATK_RELATION_FLOWS_FROM
-  const unsigned long RELATION_SUBWINDOW_OF = 0x09;      // ATK_RELATION_SUBWINDOW_OF
-  const unsigned long RELATION_EMBEDS = 0x0a;            // ATK_RELATION_EMBEDS
-  const unsigned long RELATION_EMBEDDED_BY = 0x0b;       // ATK_RELATION_EMBEDDED_BY
-  const unsigned long RELATION_POPUP_FOR = 0x0c;         // ATK_RELATION_POPUP_FOR
-  const unsigned long RELATION_PARENT_WINDOW_OF = 0x0d;  // ATK_RELATION_PARENT_WINDOW_OF
-  const unsigned long RELATION_DESCRIBED_BY = 0x0e;      // ATK_RELATION_DESCRIBED_BY
-  const unsigned long RELATION_DESCRIPTION_FOR = 0x0f;   // ATK_RELATION_DESCRIPTION_FOR
-  const unsigned long RELATION_DEFAULT_BUTTON = 0x4000;  // MSAA only, no ATK relation
-
-// MSAA relationship extensions to accNavigate
-  const unsigned long NAVRELATION_CONTROLLED_BY = 0x1000;
-  const unsigned long NAVRELATION_CONTROLLER_FOR = 0x1001;
-  const unsigned long NAVRELATION_LABEL_FOR = 0x1002;
-  const unsigned long NAVRELATION_LABELLED_BY = 0x1003;
-  const unsigned long NAVRELATION_MEMBER_OF = 0x1004;
-  const unsigned long NAVRELATION_NODE_CHILD_OF = 0x1005;
-  const unsigned long NAVRELATION_FLOWS_TO = 0x1006;
-  const unsigned long NAVRELATION_FLOWS_FROM = 0x1007;
-  const unsigned long NAVRELATION_SUBWINDOW_OF = 0x1008;
-  const unsigned long NAVRELATION_EMBEDS = 0x1009;
-  const unsigned long NAVRELATION_EMBEDDED_BY = 0x100a;
-  const unsigned long NAVRELATION_POPUP_FOR = 0x100b;
-  const unsigned long NAVRELATION_PARENT_WINDOW_OF = 0x100c;
-  const unsigned long NAVRELATION_DEFAULT_BUTTON = 0x100d;
-  const unsigned long NAVRELATION_DESCRIBED_BY = 0x100e;
-  const unsigned long NAVRELATION_DESCRIPTION_FOR = 0x100f;
-};
new file mode 100755
--- /dev/null
+++ b/accessible/public/nsIAccessibleRelation.idl
@@ -0,0 +1,164 @@
+/* -*- 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 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 "nsISupports.idl"
+#include "nsIArray.idl"
+
+interface nsIAccessible;
+
+/**
+ * This interface gives access to an accessible's set of relations.
+ * Be carefull, do not change constants until ATK has a structure to map gecko
+ * constants into ATK constants.
+ */
+[scriptable, uuid(f42a1589-70ab-4704-877f-4a9162bbe188)]
+interface nsIAccessibleRelation : nsISupports
+{
+
+  const unsigned long RELATION_NUL = 0x00;
+
+  /**
+   * Some attribute of this object is affected by a target object.
+   */
+  const unsigned long RELATION_CONTROLLED_BY = 0x01;
+
+  /**
+   * This object is interactive and controls some attribute of a target object.
+   */
+  const unsigned long RELATION_CONTROLLER_FOR = 0x02;
+
+  /**
+   * This object is label for a target object.
+   */
+  const unsigned long RELATION_LABEL_FOR = 0x03;
+
+  /**
+   * This object is labelled by a target object.
+   */
+  const unsigned long RELATION_LABELLED_BY = 0x04;
+
+  /**
+   * This object is a member of a group of one or more objects. When there is
+   * more than one object in the group each member may have one and the same
+   * target, e.g. a grouping object.  It is also possible that each member has
+   * multiple additional targets, e.g. one for every other member in the group.
+   */
+  const unsigned long RELATION_MEMBER_OF = 0x05;
+
+  /**
+   * This object is a child of a target object.
+   */
+  const unsigned long RELATION_NODE_CHILD_OF = 0x06;
+
+  /**
+   * Content flows from this object to a target object, i.e. has content that
+   * flows logically to another object in a sequential way, e.g. text flow.
+   */
+  const unsigned long RELATION_FLOWS_TO = 0x07;
+
+  /**
+   * Content flows to this object from a target object, i.e. has content that
+   * flows logically from another object in a sequential way, e.g. text flow.
+   */
+  const unsigned long RELATION_FLOWS_FROM = 0x08;
+
+  /**
+   * This object is a sub window of a target object.
+   */
+  const unsigned long RELATION_SUBWINDOW_OF = 0x09;
+
+  /**
+   * This object embeds a target object. This relation can be used on the
+   * OBJID_CLIENT accessible for a top level window to show where the content
+   * areas are.
+   */
+  const unsigned long RELATION_EMBEDS = 0x0a;
+
+  /**
+   * This object is embedded by a target object.
+   */
+  const unsigned long RELATION_EMBEDDED_BY = 0x0b;
+
+  /**
+   * This object is a transient component related to the target object. When
+   * this object is activated the target object doesn't loose focus.
+   */
+  const unsigned long RELATION_POPUP_FOR = 0x0c;
+
+  /**
+   * This object is a parent window of the target object.
+   */
+  const unsigned long RELATION_PARENT_WINDOW_OF = 0x0d;
+
+  /**
+   * This object is described by the target object.
+   */
+  const unsigned long RELATION_DESCRIBED_BY = 0x0e;
+
+  /**
+   * This object is describes the target object.
+   */
+  const unsigned long RELATION_DESCRIPTION_FOR = 0x0f;
+
+  /**
+   * Part of a form/dialog with a related default button. It is used for
+   * MSAA only, no for IA2 nor ATK.
+   */
+  const unsigned long RELATION_DEFAULT_BUTTON = 0x4000;
+
+  /**
+   * Returns the type of the relation.
+   */
+  readonly attribute unsigned long relationType;
+
+  /**
+   * Returns the number of targets for this relation.
+   */
+  readonly attribute unsigned long targetsCount;
+
+  /**
+   * Returns one accessible relation target.
+   * @param index - 0 based index of relation target.
+   */
+  nsIAccessible getTarget(in unsigned long index);
+
+  /**
+   * Returns multiple accessible relation targets.
+   */
+  nsIArray getTargets();
+};
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -992,26 +992,26 @@ refRelationSetCB(AtkObject *aAtkObj)
       return relation_set;
     }
     nsAccessibleWrap *accWrap =
         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
 
     AtkObject *accessible_array[1];
     AtkRelation* relation;
     
-    PRUint32 relationType[] = {nsIAccessible::RELATION_LABELLED_BY,
-                               nsIAccessible::RELATION_LABEL_FOR,
-                               nsIAccessible::RELATION_NODE_CHILD_OF,
-                               nsIAccessible::RELATION_CONTROLLED_BY,
-                               nsIAccessible::RELATION_CONTROLLER_FOR,
-                               nsIAccessible::RELATION_EMBEDS,
-                               nsIAccessible::RELATION_FLOWS_TO,
-                               nsIAccessible::RELATION_FLOWS_FROM,
-                               nsIAccessible::RELATION_DESCRIBED_BY,
-                               nsIAccessible::RELATION_DESCRIPTION_FOR,
+    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(relationType); i++) {
         relation = atk_relation_set_get_relation_by_type(relation_set, NS_STATIC_CAST(AtkRelationType, relationType[i]));
         if (relation) {
             atk_relation_set_remove(relation_set, relation);
         }
 
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -75,16 +75,17 @@ CPPSRCS = \
   nsAccessNode.cpp \
   nsAccessibleEventData.cpp \
   nsDocAccessible.cpp \
   nsOuterDocAccessible.cpp \
   nsAccessibilityAtoms.cpp \
   nsAccessibilityUtils.cpp \
   nsAccessibilityService.cpp \
   nsAccessible.cpp \
+  nsAccessibleRelation.cpp \
   nsAccessibleTreeWalker.cpp \
   nsBaseWidgetAccessible.cpp \
   nsFormControlAccessible.cpp \
   nsRootAccessible.cpp \
   nsCaretAccessible.cpp \
   nsTextAccessible.cpp \
   $(NULL)
 
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -33,16 +33,17 @@
  * 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 "nsAccessibleRelation.h"
 #include "nsIAccessibleDocument.h"
 #include "nsIDocument.h"
 #include "nsIDOMNSDocument.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIImageDocument.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
@@ -2682,99 +2683,99 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
   }
 
   nsCOMPtr<nsIDOMNode> relatedNode;
   nsAutoString relatedID;
 
   // Search for the related DOM node according to the specified "relation type"
   switch (aRelationType)
   {
-  case RELATION_LABEL_FOR:
+  case nsIAccessibleRelation::RELATION_LABEL_FOR:
     {
       if (content->Tag() == nsAccessibilityAtoms::label) {
         nsIAtom *relatedIDAttr = content->IsNodeOfType(nsINode::eHTML) ?
           nsAccessibilityAtoms::_for : nsAccessibilityAtoms::control;
         content->GetAttr(kNameSpaceID_None, relatedIDAttr, relatedID);
       }
       if (relatedID.IsEmpty()) {
         const PRUint32 kAncestorLevelsToSearch = 3;
         relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::labelledby,
                                                   kAncestorLevelsToSearch);
       }
       break;
     }
-  case RELATION_LABELLED_BY:
+  case nsIAccessibleRelation::RELATION_LABELLED_BY:
     {
       content->GetAttr(kNameSpaceID_WAIProperties,
                        nsAccessibilityAtoms::labelledby, relatedID);
       if (relatedID.IsEmpty()) {
         relatedNode = do_QueryInterface(GetLabelContent(content));
       }
       break;
     }
-  case RELATION_DESCRIBED_BY:
+  case nsIAccessibleRelation::RELATION_DESCRIBED_BY:
     {
       content->GetAttr(kNameSpaceID_WAIProperties,
                        nsAccessibilityAtoms::describedby, relatedID);
       if (relatedID.IsEmpty()) {
         nsIContent *description =
           FindNeighbourPointingToNode(content,
                                       nsAccessibilityAtoms::description,
                                       nsAccessibilityAtoms::control);
 
         relatedNode = do_QueryInterface(description);
       }
       break;
     }
-  case RELATION_DESCRIPTION_FOR:
+  case nsIAccessibleRelation::RELATION_DESCRIPTION_FOR:
     {
       const PRUint32 kAncestorLevelsToSearch = 3;
       relatedNode =
         FindNeighbourPointingToThis(nsAccessibilityAtoms::describedby,
                                     kAncestorLevelsToSearch);
 
       if (!relatedNode && content->Tag() == nsAccessibilityAtoms::description &&
           content->IsNodeOfType(nsINode::eXUL)) {
         // This affectively adds an optional control attribute to xul:description,
         // which only affects accessibility, by allowing the description to be
         // tied to a control.
         content->GetAttr(kNameSpaceID_None,
                          nsAccessibilityAtoms::control, relatedID);
       }
       break;
     }
-  case RELATION_NODE_CHILD_OF:
+  case nsIAccessibleRelation::RELATION_NODE_CHILD_OF:
     {
       relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::owns);
       break;
     }
-  case RELATION_CONTROLLED_BY:
+  case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
     {
       relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::controls);
       break;
     }
-  case RELATION_CONTROLLER_FOR:
+  case nsIAccessibleRelation::RELATION_CONTROLLER_FOR:
     {
       content->GetAttr(kNameSpaceID_WAIProperties,
                        nsAccessibilityAtoms::controls, relatedID);
       break;
     }
-  case RELATION_FLOWS_TO:
+  case nsIAccessibleRelation::RELATION_FLOWS_TO:
     {
       content->GetAttr(kNameSpaceID_WAIProperties,
                        nsAccessibilityAtoms::flowto, relatedID);
       break;
     }
-  case RELATION_FLOWS_FROM:
+  case nsIAccessibleRelation::RELATION_FLOWS_FROM:
     {
       relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::flowto);
       break;
     }
 
-  case RELATION_DEFAULT_BUTTON:
+  case nsIAccessibleRelation::RELATION_DEFAULT_BUTTON:
     {
       if (content->IsNodeOfType(nsINode::eHTML)) {
         nsCOMPtr<nsIForm> form;
         while ((form = do_QueryInterface(content)) == nsnull &&
                (content = content->GetParent()) != nsnull) /* nothing */ ;
 
         if (form) {
             relatedNode = do_QueryInterface(form->GetDefaultSubmitElement());
@@ -2832,24 +2833,82 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
     NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
     nsCOMPtr<nsIDOMElement> relatedEl;
     domDoc->GetElementById(relatedID, getter_AddRefs(relatedEl));
     relatedNode = do_QueryInterface(relatedEl);
   }
 
   // Return the corresponding accessible if the related DOM node is found
   if (relatedNode) {
-    nsCOMPtr<nsIAccessibilityService> accService =
-      do_GetService("@mozilla.org/accessibilityService;1");
+    nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
     NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
     return accService->GetAccessibleInWeakShell(relatedNode, mWeakShell, aRelated);
   }
   return NS_ERROR_FAILURE;
 }
 
+NS_IMETHODIMP
+nsAccessible::GetRelationsCount(PRUint32 *aCount)
+{
+  NS_ENSURE_ARG_POINTER(aCount);
+  *aCount = 0;
+
+  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)
+{
+  NS_ENSURE_ARG_POINTER(aRelation);
+  *aRelation = nsnull;
+
+  nsCOMPtr<nsIArray> relations;
+  nsresult rv = GetRelations(getter_AddRefs(relations));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIAccessibleRelation> relation;
+  rv = relations->QueryElementAt(aIndex, NS_GET_IID(nsIAccessibleRelation),
+                                 getter_AddRefs(relation));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_IF_ADDREF(*aRelation = relation);
+  return rv;
+}
+
+NS_IMETHODIMP
+nsAccessible::GetRelations(nsIArray **aRelations)
+{
+  NS_ENSURE_ARG_POINTER(aRelations);
+
+  nsCOMPtr<nsIMutableArray> relations = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  NS_ENSURE_TRUE(relations, NS_ERROR_OUT_OF_MEMORY);
+
+  // Latest nsIAccessibleRelation is RELATION_DESCRIPTION_FOR (0xof)
+  for (PRUint32 relType = 0; relType < 0x0f; ++relType) {
+    nsCOMPtr<nsIAccessible> accessible;
+    nsresult rv = GetAccessibleRelated(relType, getter_AddRefs(accessible));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (accessible) {
+      nsCOMPtr<nsIAccessibleRelation> relation =
+        new nsAccessibleRelation(relType, accessible);
+      NS_ENSURE_TRUE(relation, NS_ERROR_OUT_OF_MEMORY);
+
+      relations->AppendElement(relation, PR_FALSE);
+    }
+  }
+
+  NS_ADDREF(*aRelations = relations);
+  return NS_OK;
+}
+
 /* void extendSelection (); */
 NS_IMETHODIMP nsAccessible::ExtendSelection()
 {
   // XXX Should be implemented, but not high priority
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [noscript] void getNativeInterface(out voidPtr aOutAccessible); */
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -34,25 +34,28 @@
  * 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 _nsAccessible_H_
 #define _nsAccessible_H_
 
-#include "nsIAccessibleRole.h"
-#include "nsIAccessibleStates.h"
 #include "nsAccessNodeWrap.h"
 #include "nsAccessibilityUtils.h"
+
 #include "nsIAccessible.h"
 #include "nsPIAccessible.h"
 #include "nsIAccessibleHyperLink.h"
 #include "nsIAccessibleSelectable.h"
 #include "nsIAccessibleValue.h"
+#include "nsIAccessibleRole.h"
+#include "nsIAccessibleStates.h"
+#include "nsIAccessibleRelation.h"
+
 #include "nsIDOMNodeList.h"
 #include "nsINameSpaceManager.h"
 #include "nsWeakReference.h"
 #include "nsString.h"
 #include "nsIDOMDOMStringList.h"
 
 struct nsRect;
 class nsIContent;
new file mode 100755
--- /dev/null
+++ b/accessible/src/base/nsAccessibleRelation.cpp
@@ -0,0 +1,94 @@
+/* -*- 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 "nsIMutableArray.h"
+#include "nsComponentManagerUtils.h"
+
+nsAccessibleRelation::
+  nsAccessibleRelation(PRUint32 aType, nsIAccessible *aTarget) :
+  mType(aType), mTarget(aTarget)
+{
+}
+
+// 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 = 1;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAccessibleRelation::GetTarget(PRUint32 aIndex, nsIAccessible **aTarget)
+{
+  NS_ENSURE_ARG_POINTER(aTarget);
+
+  NS_IF_ADDREF(*aTarget = mTarget);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAccessibleRelation::GetTargets(nsIArray **aRelations)
+{
+  NS_ENSURE_ARG_POINTER(aRelations);
+
+  nsCOMPtr<nsIMutableArray> relations = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  NS_ENSURE_TRUE(relations, NS_ERROR_OUT_OF_MEMORY);
+
+  relations->AppendElement(mTarget, PR_FALSE);
+
+  NS_ADDREF(*aRelations = relations);
+  return NS_OK;
+}
new file mode 100755
--- /dev/null
+++ b/accessible/src/base/nsAccessibleRelation.h
@@ -0,0 +1,60 @@
+/* -*- 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"
+
+class nsAccessibleRelation: public nsIAccessibleRelation
+{
+public:
+  nsAccessibleRelation(PRUint32 aType, nsIAccessible *aTarget);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIACCESSIBLERELATION
+
+private:
+  PRUint32 mType;
+  nsCOMPtr<nsIAccessible> mTarget;
+};
+
+#endif
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -954,17 +954,17 @@ nsRootAccessible::GetContentDocShell(nsI
   return nsnull;
 }
 
 NS_IMETHODIMP nsRootAccessible::GetAccessibleRelated(PRUint32 aRelationType,
                                                      nsIAccessible **aRelated)
 {
   *aRelated = nsnull;
 
-  if (!mDOMNode || aRelationType != RELATION_EMBEDS) {
+  if (!mDOMNode || aRelationType != nsIAccessibleRelation::RELATION_EMBEDS) {
     return nsDocAccessibleWrap::GetAccessibleRelated(aRelationType, aRelated);
   }
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem = GetDocShellTreeItemFor(mDOMNode);   
   nsCOMPtr<nsIDocShellTreeItem> contentTreeItem = GetContentDocShell(treeItem);
   // there may be no content area, so we need a null check
   if (contentTreeItem) {
     nsCOMPtr<nsIAccessibleDocument> accDoc =
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -849,33 +849,66 @@ STDMETHODIMP nsAccessibleWrap::accNaviga
       xpAccessibleStart->GetPreviousSibling(getter_AddRefs(xpAccessibleResult));
       break;
     case NAVDIR_RIGHT:
       xpAccessibleStart->GetAccessibleToRight(getter_AddRefs(xpAccessibleResult));
       break;
     case NAVDIR_UP:
       xpAccessibleStart->GetAccessibleAbove(getter_AddRefs(xpAccessibleResult));
       break;
+
     // MSAA relationship extensions to accNavigate
-    case NAVRELATION_CONTROLLED_BY:    xpRelation = RELATION_CONTROLLED_BY;    break;
-    case NAVRELATION_CONTROLLER_FOR:   xpRelation = RELATION_CONTROLLER_FOR;   break;
-    case NAVRELATION_LABEL_FOR:        xpRelation = RELATION_LABEL_FOR;        break;
-    case NAVRELATION_LABELLED_BY:      xpRelation = RELATION_LABELLED_BY;      break;
-    case NAVRELATION_MEMBER_OF:        xpRelation = RELATION_MEMBER_OF;        break;
-    case NAVRELATION_NODE_CHILD_OF:    xpRelation = RELATION_NODE_CHILD_OF;    break;
-    case NAVRELATION_FLOWS_TO:         xpRelation = RELATION_FLOWS_TO;         break;
-    case NAVRELATION_FLOWS_FROM:       xpRelation = RELATION_FLOWS_FROM;       break;
-    case NAVRELATION_SUBWINDOW_OF:     xpRelation = RELATION_SUBWINDOW_OF;     break;
-    case NAVRELATION_EMBEDS:           xpRelation = RELATION_EMBEDS;           break;
-    case NAVRELATION_EMBEDDED_BY:      xpRelation = RELATION_EMBEDDED_BY;      break;
-    case NAVRELATION_POPUP_FOR:        xpRelation = RELATION_POPUP_FOR;        break;
-    case NAVRELATION_PARENT_WINDOW_OF: xpRelation = RELATION_PARENT_WINDOW_OF; break;
-    case NAVRELATION_DEFAULT_BUTTON:   xpRelation = RELATION_DEFAULT_BUTTON;   break;
-    case NAVRELATION_DESCRIBED_BY:     xpRelation = RELATION_DESCRIBED_BY;     break;
-    case NAVRELATION_DESCRIPTION_FOR:  xpRelation = RELATION_DESCRIPTION_FOR;  break;
+    case NAVRELATION_CONTROLLED_BY:
+      xpRelation = nsIAccessibleRelation::RELATION_CONTROLLED_BY;
+      break;
+    case NAVRELATION_CONTROLLER_FOR:
+      xpRelation = nsIAccessibleRelation::RELATION_CONTROLLER_FOR;
+      break;
+    case NAVRELATION_LABEL_FOR:
+      xpRelation = nsIAccessibleRelation::RELATION_LABEL_FOR;
+      break;
+    case NAVRELATION_LABELLED_BY:
+      xpRelation = nsIAccessibleRelation::RELATION_LABELLED_BY;
+      break;
+    case NAVRELATION_MEMBER_OF:
+      xpRelation = nsIAccessibleRelation::RELATION_MEMBER_OF;
+      break;
+    case NAVRELATION_NODE_CHILD_OF:
+      xpRelation = nsIAccessibleRelation::RELATION_NODE_CHILD_OF;
+      break;
+    case NAVRELATION_FLOWS_TO:
+      xpRelation = nsIAccessibleRelation::RELATION_FLOWS_TO;
+      break;
+    case NAVRELATION_FLOWS_FROM:
+      xpRelation = nsIAccessibleRelation::RELATION_FLOWS_FROM;
+      break;
+    case NAVRELATION_SUBWINDOW_OF:
+      xpRelation = nsIAccessibleRelation::RELATION_SUBWINDOW_OF;
+      break;
+    case NAVRELATION_EMBEDS:
+      xpRelation = nsIAccessibleRelation::RELATION_EMBEDS;
+      break;
+    case NAVRELATION_EMBEDDED_BY:
+      xpRelation = nsIAccessibleRelation::RELATION_EMBEDDED_BY;
+      break;
+    case NAVRELATION_POPUP_FOR:
+      xpRelation = nsIAccessibleRelation::RELATION_POPUP_FOR;
+      break;
+    case NAVRELATION_PARENT_WINDOW_OF:
+      xpRelation = nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF;
+      break;
+    case NAVRELATION_DEFAULT_BUTTON:
+      xpRelation = nsIAccessibleRelation::RELATION_DEFAULT_BUTTON;
+      break;
+    case NAVRELATION_DESCRIBED_BY:
+      xpRelation = nsIAccessibleRelation::RELATION_DESCRIBED_BY;
+      break;
+    case NAVRELATION_DESCRIPTION_FOR:
+      xpRelation = nsIAccessibleRelation::RELATION_DESCRIPTION_FOR;
+      break;
   }
 
   pvarEndUpAt->vt = VT_EMPTY;
 
   if (xpRelation) {
     nsresult rv = GetAccessibleRelated(xpRelation,
                                        getter_AddRefs(xpAccessibleResult));
     if (rv == NS_ERROR_NOT_IMPLEMENTED) {
--- a/accessible/src/msaa/nsAccessibleWrap.h
+++ b/accessible/src/msaa/nsAccessibleWrap.h
@@ -310,15 +310,34 @@ protected:
   // mEnumVARIANTPosition not the current accessible's position, but a "cursor" of 
   // where we are in the current list of children, with respect to
   // nsIEnumVariant::Reset(), Skip() and Next().
   PRUint16 mEnumVARIANTPosition;
 
   // Should this accessible be allowed to have any MSAA children
   static PRBool MustPrune(nsIAccessible *accessible)
     { PRUint32 role; return NS_SUCCEEDED(accessible->GetRole(&role)) && (role == nsIAccessibleRole::ROLE_ENTRY || role == nsIAccessibleRole::ROLE_PASSWORD_TEXT || role == nsIAccessibleRole::ROLE_PUSHBUTTON); }
+
+  enum navRelations {
+    NAVRELATION_CONTROLLED_BY = 0x1000,
+    NAVRELATION_CONTROLLER_FOR = 0x1001,
+    NAVRELATION_LABEL_FOR = 0x1002,
+    NAVRELATION_LABELLED_BY = 0x1003,
+    NAVRELATION_MEMBER_OF = 0x1004,
+    NAVRELATION_NODE_CHILD_OF = 0x1005,
+    NAVRELATION_FLOWS_TO = 0x1006,
+    NAVRELATION_FLOWS_FROM = 0x1007,
+    NAVRELATION_SUBWINDOW_OF = 0x1008,
+    NAVRELATION_EMBEDS = 0x1009,
+    NAVRELATION_EMBEDDED_BY = 0x100a,
+    NAVRELATION_POPUP_FOR = 0x100b,
+    NAVRELATION_PARENT_WINDOW_OF = 0x100c,
+    NAVRELATION_DEFAULT_BUTTON = 0x100d,
+    NAVRELATION_DESCRIBED_BY = 0x100e,
+    NAVRELATION_DESCRIPTION_FOR = 0x100f
+  };
 };
 
 // Define unsupported wrap classes here
 typedef class nsHTMLTextFieldAccessible    nsHTMLTextFieldAccessibleWrap;
 typedef class nsXULTextFieldAccessible     nsXULTextFieldAccessibleWrap;
 
 #endif
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -954,17 +954,17 @@ NS_IMETHODIMP nsXULTreeitemAccessible::T
 }
 
 NS_IMETHODIMP nsXULTreeitemAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAccessible **aRelated)
 {
   //currentlly only for ATK. and in the future, we'll sync MSAA and ATK same. 
   //that's why ATK specific code shows here
   *aRelated = nsnull;
 #ifdef MOZ_ACCESSIBILITY_ATK
-  if (aRelationType == RELATION_NODE_CHILD_OF) {
+  if (aRelationType == nsIAccessibleRelation::RELATION_NODE_CHILD_OF) {
     PRInt32 columnIndex;
     if (NS_SUCCEEDED(mColumn->GetIndex(&columnIndex)) && columnIndex == 0) {
       PRInt32 parentIndex;
       if (NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex))) {
         if (parentIndex == -1) {
           NS_IF_ADDREF(*aRelated = mParent);
           return NS_OK;
         } else {