Bug 873450 - Implement IA2 containing relations, r=tbsaunde
authorAndrew Quartey <andrew.quartey@gmail.com>
Fri, 25 Oct 2013 11:14:32 -0400
changeset 167029 f85c0d3d7f31305809905d708c83d7050fce04c3
parent 167028 8803d874cbea0d1e2894434ce153bb324f5960d3
child 167030 82d5d92a3eac70e5030e941c0565756e2e4219ea
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs873450
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 873450 - Implement IA2 containing relations, r=tbsaunde
accessible/public/nsIAccessibleRelation.idl
accessible/src/base/RelationType.h
accessible/src/base/RelationTypeMap.h
accessible/src/generic/Accessible.cpp
accessible/src/windows/msaa/AccessibleWrap.h
accessible/src/windows/msaa/ServiceProvider.cpp
accessible/tests/mochitest/relations.js
accessible/tests/mochitest/relations/test_general.html
--- a/accessible/public/nsIAccessibleRelation.idl
+++ b/accessible/public/nsIAccessibleRelation.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 #include "nsIArray.idl"
 
 interface nsIAccessible;
 
 /**
  * This interface gives access to an accessible's set of relations.
  */
-[scriptable, uuid(9f85fc0d-2969-48e6-b822-68140f7e5770)]
+[scriptable, uuid(55b308c4-2ae4-46bc-b4cd-4d4370e0a660)]
 interface nsIAccessibleRelation : nsISupports
 {
   /**
    * This object is labelled by a target object.
    */
   const unsigned long RELATION_LABELLED_BY = 0x00;
 
   /**
@@ -105,16 +105,31 @@ interface nsIAccessibleRelation : nsISup
 
   /**
    * Part of a form/dialog with a related default button. It is used for
    * MSAA/XPCOM, it isn't for IA2 or ATK.
    */
   const unsigned long RELATION_DEFAULT_BUTTON = 0x10;
 
   /**
+   * The target object is the containing document object.
+   */
+  const unsigned long RELATION_CONTAINING_DOCUMENT = 0x11;
+
+  /**
+   * The target object is the topmost containing document object in the tab pane.
+   */
+  const unsigned long RELATION_CONTAINING_TAB_PANE = 0x12;
+
+  /**
+   * The target object is the containing application object.
+   */
+  const unsigned long RELATION_CONTAINING_APPLICATION = 0x14;
+
+  /**
    * Returns the type of the relation.
    */
   readonly attribute unsigned long relationType;
 
   /**
    * Returns the number of targets for this relation.
    */
   readonly attribute unsigned long targetsCount;
--- a/accessible/src/base/RelationType.h
+++ b/accessible/src/base/RelationType.h
@@ -104,16 +104,36 @@ MOZ_BEGIN_ENUM_CLASS(RelationType)
   PARENT_WINDOW_OF = 0x0f,
 
   /**
    * Part of a form/dialog with a related default button. It is used for
    * MSAA/XPCOM, it isn't for IA2 or ATK.
    */
   DEFAULT_BUTTON = 0x10,
 
-  LAST = DEFAULT_BUTTON
+  /**
+   * The target object is the containing document object.
+   */
+  CONTAINING_DOCUMENT = 0x11,
+
+  /**
+   * The target object is the topmost containing document object in the tab pane.
+   */
+  CONTAINING_TAB_PANE = 0x12,
+
+  /**
+   * The target object is the containing window object.
+   */
+  CONTAINING_WINDOW = 0x13,
+
+  /**
+   * The target object is the containing application object.
+   */
+  CONTAINING_APPLICATION = 0x14,
+
+  LAST = CONTAINING_APPLICATION
 
 MOZ_END_ENUM_CLASS(RelationType)
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/base/RelationTypeMap.h
+++ b/accessible/src/base/RelationTypeMap.h
@@ -105,8 +105,26 @@ RELATIONTYPE(PARENT_WINDOW_OF,
              NAVRELATION_PARENT_WINDOW_OF,
              IA2_RELATION_PARENT_WINDOW_OF)
 
 RELATIONTYPE(DEFAULT_BUTTON,
              "default button",
              ATK_RELATION_NULL,
              NAVRELATION_DEFAULT_BUTTON,
              IA2_RELATION_NULL)
+
+RELATIONTYPE(CONTAINING_DOCUMENT,
+             "containing document",
+             ATK_RELATION_NULL,
+             NAVRELATION_CONTAINING_DOCUMENT,
+             IA2_RELATION_CONTAINING_DOCUMENT)
+
+RELATIONTYPE(CONTAINING_TAB_PANE,
+             "containing tab pane",
+             ATK_RELATION_NULL,
+             NAVRELATION_CONTAINING_TAB_PANE,
+             IA2_RELATION_CONTAINING_TAB_PANE)
+
+RELATIONTYPE(CONTAINING_APPLICATION,
+             "containing application",
+             ATK_RELATION_NULL,
+             NAVRELATION_CONTAINING_APPLICATION,
+             IA2_RELATION_CONTAINING_APPLICATION)
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -8,16 +8,18 @@
 #include "nsIXBLAccessible.h"
 
 #include "AccCollector.h"
 #include "AccGroupInfo.h"
 #include "AccIterator.h"
 #include "nsAccUtils.h"
 #include "nsAccessibleRelation.h"
 #include "nsAccessibilityService.h"
+#include "ApplicationAccessible.h"
+#include "nsCoreUtils.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIAccessibleRole.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "States.h"
@@ -2175,16 +2177,43 @@ Accessible::RelationByType(RelationType 
           }
           nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl));
           return Relation(mDoc, relatedContent);
         }
       }
       return Relation();
     }
 
+    case RelationType::CONTAINING_DOCUMENT:
+      return Relation(mDoc);
+
+    case RelationType::CONTAINING_TAB_PANE: {
+      nsCOMPtr<nsIDocShell> docShell =
+        nsCoreUtils::GetDocShellFor(GetNode());
+      if (docShell) {
+        // Walk up the parent chain without crossing the boundary at which item
+        // types change, preventing us from walking up out of tab content.
+        nsCOMPtr<nsIDocShellTreeItem> root;
+        docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
+        if (root) {
+          // If the item type is typeContent, we assume we are in browser tab
+          // content. Note, this includes content such as about:addons,
+          // for consistency.
+          int32_t itemType = 0;
+          root->GetItemType(&itemType);
+          if (itemType == nsIDocShellTreeItem::typeContent)
+            return Relation(nsAccUtils::GetDocAccessibleFor(root));
+        }
+      }
+      return  Relation();
+    }
+
+    case RelationType::CONTAINING_APPLICATION:
+      return Relation(ApplicationAcc());
+
     default:
       return Relation();
   }
 }
 
 NS_IMETHODIMP
 Accessible::GetRelations(nsIArray **aRelations)
 {
@@ -2209,17 +2238,20 @@ Accessible::GetRelations(nsIArray **aRel
     nsIAccessibleRelation::RELATION_FLOWS_TO,
     nsIAccessibleRelation::RELATION_FLOWS_FROM,
     nsIAccessibleRelation::RELATION_MEMBER_OF,
     nsIAccessibleRelation::RELATION_SUBWINDOW_OF,
     nsIAccessibleRelation::RELATION_EMBEDS,
     nsIAccessibleRelation::RELATION_EMBEDDED_BY,
     nsIAccessibleRelation::RELATION_POPUP_FOR,
     nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF,
-    nsIAccessibleRelation::RELATION_DEFAULT_BUTTON
+    nsIAccessibleRelation::RELATION_DEFAULT_BUTTON,
+    nsIAccessibleRelation::RELATION_CONTAINING_DOCUMENT,
+    nsIAccessibleRelation::RELATION_CONTAINING_TAB_PANE,
+    nsIAccessibleRelation::RELATION_CONTAINING_APPLICATION
   };
 
   for (uint32_t idx = 0; idx < ArrayLength(relationTypes); idx++) {
     nsCOMPtr<nsIAccessibleRelation> relation;
     nsresult rv = GetRelationByType(relationTypes[idx], getter_AddRefs(relation));
 
     if (NS_SUCCEEDED(rv) && relation) {
       uint32_t targets = 0;
--- a/accessible/src/windows/msaa/AccessibleWrap.h
+++ b/accessible/src/windows/msaa/AccessibleWrap.h
@@ -197,16 +197,19 @@ protected:
     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,
-    NAVRELATION_NODE_PARENT_OF = 0x1010
+    NAVRELATION_NODE_PARENT_OF = 0x1010,
+    NAVRELATION_CONTAINING_DOCUMENT = 0x1011,
+    NAVRELATION_CONTAINING_TAB_PANE = 0x1012,
+    NAVRELATION_CONTAINING_APPLICATION = 0x1014
   };
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/windows/msaa/ServiceProvider.cpp
+++ b/accessible/src/windows/msaa/ServiceProvider.cpp
@@ -6,16 +6,17 @@
 
 #include "ServiceProvider.h"
 
 #include "ApplicationAccessibleWrap.h"
 #include "Compatibility.h"
 #include "DocAccessible.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
+#include "Relation.h"
 #include "uiaRawElmProvider.h"
 
 #include "mozilla/Preferences.h"
 #include "nsIDocShell.h"
 
 #include "ISimpleDOMNode_i.c"
 
 namespace mozilla {
@@ -55,43 +56,22 @@ ServiceProvider::QueryService(REFGUID aG
   // A use case for this is for screen readers that need to switch context or
   // 'virtual buffer' when focus moves from one browser tab area to another.
   static const GUID SID_IAccessibleContentDocument =
     { 0xa5d8e1f3,0x3571,0x4d8f,{0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e} };
   if (aGuidService == SID_IAccessibleContentDocument) {
     if (aIID != IID_IAccessible)
       return E_NOINTERFACE;
 
-    nsCOMPtr<nsIDocShell> docShell =
-      nsCoreUtils::GetDocShellFor(mAccessible->GetNode());
-    if (!docShell)
-      return E_UNEXPECTED;
-
-    // Walk up the parent chain without crossing the boundary at which item
-    // types change, preventing us from walking up out of tab content.
-    nsCOMPtr<nsIDocShellTreeItem> root;
-    docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
-    if (!root)
-      return E_UNEXPECTED;
-
-
-    // If the item type is typeContent, we assume we are in browser tab content.
-    // Note this includes content such as about:addons, for consistency.
-    int32_t itemType;
-    root->GetItemType(&itemType);
-    if (itemType != nsIDocShellTreeItem::typeContent)
+    Relation rel = mAccessible->RelationByType(RelationType::CONTAINING_TAB_PANE);
+    AccessibleWrap* tabDoc = static_cast<AccessibleWrap*>(rel.Next());
+    if (!tabDoc)
       return E_NOINTERFACE;
 
-    // Make sure this is a document.
-    DocAccessible* docAcc = nsAccUtils::GetDocAccessibleFor(root);
-    if (!docAcc)
-      return E_UNEXPECTED;
-
-    *aInstancePtr = static_cast<IAccessible*>(docAcc);
-
+    *aInstancePtr = static_cast<IAccessible*>(tabDoc);
     (reinterpret_cast<IUnknown*>(*aInstancePtr))->AddRef();
     return S_OK;
   }
 
   // Can get to IAccessibleApplication from any node via QS
   if (aGuidService == IID_IAccessibleApplication ||
       (Compatibility::IsJAWS() && aIID == IID_IAccessibleApplication)) {
     ApplicationAccessibleWrap* applicationAcc =
--- a/accessible/tests/mochitest/relations.js
+++ b/accessible/tests/mochitest/relations.js
@@ -13,16 +13,19 @@ const RELATION_FLOWS_TO = nsIAccessibleR
 const RELATION_LABEL_FOR = nsIAccessibleRelation.RELATION_LABEL_FOR;
 const RELATION_LABELLED_BY = nsIAccessibleRelation.RELATION_LABELLED_BY;
 const RELATION_MEMBER_OF = nsIAccessibleRelation.RELATION_MEMBER_OF;
 const RELATION_NODE_CHILD_OF = nsIAccessibleRelation.RELATION_NODE_CHILD_OF;
 const RELATION_NODE_PARENT_OF = nsIAccessibleRelation.RELATION_NODE_PARENT_OF;
 const RELATION_PARENT_WINDOW_OF = nsIAccessibleRelation.RELATION_PARENT_WINDOW_OF;
 const RELATION_POPUP_FOR = nsIAccessibleRelation.RELATION_POPUP_FOR;
 const RELATION_SUBWINDOW_OF = nsIAccessibleRelation.RELATION_SUBWINDOW_OF;
+const RELATION_CONTAINING_DOCUMENT = nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT;
+const RELATION_CONTAINING_TAB_PANE = nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE;
+const RELATION_CONTAINING_APPLICATION = nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION;
 
 ////////////////////////////////////////////////////////////////////////////////
 // General
 
 /**
  * Test the accessible relation.
  *
  * @param aIdentifier          [in] identifier to get an accessible, may be ID
--- a/accessible/tests/mochitest/relations/test_general.html
+++ b/accessible/tests/mochitest/relations/test_general.html
@@ -162,16 +162,21 @@
       testRelation("caption", RELATION_LABEL_FOR, "table");
       testRelation("table", RELATION_LABELLED_BY, "caption");
 
       // 'labelled by'/'label for' relation for html:fieldset and
       // html:legend
       testRelation("legend", RELATION_LABEL_FOR, "fieldset");
       testRelation("fieldset", RELATION_LABELLED_BY, "legend");
 
+      // containing relations
+      testRelation("control1_1", RELATION_CONTAINING_DOCUMENT, document);
+      testRelation("control1_1", RELATION_CONTAINING_TAB_PANE, getTabDocAccessible("control1_1"));
+      testRelation("control1_1", RELATION_CONTAINING_APPLICATION, getApplicationAccessible());
+
       // finish test
       SimpleTest.finish();
     }
 
     disableLogging(); // from test_embeds.xul
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>