Frank-Rainer Grahl 1 month ago
parent
commit
eba344f2de

+ 157 - 0
mozilla-release/patches/1260598-59a1.patch

@@ -0,0 +1,157 @@
+# HG changeset patch
+# User Samuel Thibault <samuel.thibault@ens-lyon.org>
+# Date 1513242420 -7200
+# Node ID 67e8486ad4c522b6487e36b8fd537f04881447f9
+# Parent  ee3fbfc0454abcf41f496f81033af1fea511f73c
+Bug 1260598 Make document events wait for chrome content insertion events r=surkov
+
+When switching from a tab to another, accessibility layers needs to get
+events about the tab switch before events about the newly-focused
+element of the document.
+
+This changeset does it so by first making IsUpdatePending() not only
+watch for the document's pending updates, but also its parent's pending
+updates, so that the document doesn't process focus events immediately,
+but queue them.
+
+Then, WillRefresh for the document should not process events until its
+parent chrome has finished processing its content insertion events
+(corresponding to the tab switch).
+
+Eventually, ScheduleContentInsertion can not afford leaving an empty
+array of notifications and not a schedule processing any more.
+(was introduced by c2aeece5eb10 'Bug 1242989 - keep content insertions
+in a hash')
+
+diff --git a/accessible/base/NotificationController.cpp b/accessible/base/NotificationController.cpp
+--- a/accessible/base/NotificationController.cpp
++++ b/accessible/base/NotificationController.cpp
+@@ -414,33 +414,33 @@ NotificationController::ScheduleChildDoc
+   ScheduleProcessing();
+ }
+ 
+ void
+ NotificationController::ScheduleContentInsertion(Accessible* aContainer,
+                                                  nsIContent* aStartChildNode,
+                                                  nsIContent* aEndChildNode)
+ {
+-  nsTArray<nsCOMPtr<nsIContent>>* list =
+-    mContentInsertions.LookupOrAdd(aContainer);
++  nsTArray<nsCOMPtr<nsIContent>> list;
+ 
+   bool needsProcessing = false;
+   nsIContent* node = aStartChildNode;
+   while (node != aEndChildNode) {
+     // Notification triggers for content insertion even if no content was
+     // actually inserted, check if the given content has a frame to discard
+     // this case early.
+     if (node->GetPrimaryFrame()) {
+-      if (list->AppendElement(node))
++      if (list.AppendElement(node))
+         needsProcessing = true;
+     }
+     node = node->GetNextSibling();
+   }
+ 
+   if (needsProcessing) {
++    mContentInsertions.LookupOrAdd(aContainer)->AppendElements(list);
+     ScheduleProcessing();
+   }
+ }
+ 
+ void
+ NotificationController::ScheduleProcessing()
+ {
+   // If notification flush isn't planed yet start notification flush
+@@ -454,21 +454,41 @@ NotificationController::ScheduleProcessi
+ ////////////////////////////////////////////////////////////////////////////////
+ // NotificationCollector: protected
+ 
+ bool
+ NotificationController::IsUpdatePending()
+ {
+   return mPresShell->IsLayoutFlushObserver() ||
+     mObservingState == eRefreshProcessingForUpdate ||
++    WaitingForParent() ||
+     mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
+     mTextHash.Count() != 0 ||
+     !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
+ }
+ 
++bool
++NotificationController::WaitingForParent()
++{
++  DocAccessible* parentdoc = mDocument->ParentDocument();
++  if (!parentdoc) {
++    return false;
++  }
++
++  NotificationController* parent = parentdoc->mNotificationController;
++  if (!parent || parent == this) {
++    // Do not wait for nothing or ourselves
++    return false;
++  }
++
++  // Wait for parent's notifications processing
++  return parent->mContentInsertions.Count() != 0 ||
++         parent->mNotifications.Length() != 0;
++}
++
+ void
+ NotificationController::ProcessMutationEvents()
+ {
+   // there is no reason to fire a hide event for a child of a show event
+   // target.  That can happen if something is inserted into the tree and
+   // removed before the next refresh driver tick, but it should not be
+   // observable outside gecko so it should be safe to coalesce away any such
+   // events.  This means that it should be fine to fire all of the hide events
+@@ -604,16 +624,22 @@ NotificationController::WillRefresh(mozi
+   // Wait until an update, we have started, or an interruptible reflow is
+   // finished.
+   if (mObservingState == eRefreshProcessing ||
+       mObservingState == eRefreshProcessingForUpdate ||
+       mPresShell->IsReflowInterrupted()) {
+     return;
+   }
+ 
++  // Wait for parent's notifications, to get proper ordering between e.g. tab
++  // event and content event.
++  if (WaitingForParent()) {
++    return;
++  }
++
+   // Any generic notifications should be queued if we're processing content
+   // insertions or generic notifications.
+   mObservingState = eRefreshProcessingForUpdate;
+ 
+   // Initial accessible tree construction.
+   if (!mDocument->HasLoadState(DocAccessible::eTreeConstructed)) {
+     // If document is not bound to parent at this point then the document is not
+     // ready yet (process notifications later).
+diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h
+--- a/accessible/base/NotificationController.h
++++ b/accessible/base/NotificationController.h
+@@ -269,16 +269,22 @@ protected:
+   nsCycleCollectingAutoRefCnt mRefCnt;
+   NS_DECL_OWNINGTHREAD
+ 
+   /**
+    * Return true if the accessible tree state update is pending.
+    */
+   bool IsUpdatePending();
+ 
++  /**
++   * Return true if we should wait for processing from the parent before we can
++   * process our own queue.
++   */
++  bool WaitingForParent();
++
+ private:
+   NotificationController(const NotificationController&);
+   NotificationController& operator = (const NotificationController&);
+ 
+   // nsARefreshObserver
+   virtual void WillRefresh(mozilla::TimeStamp aTime) override;
+ 
+   /**
+

+ 235 - 0
mozilla-release/patches/1363723-1-FIX-57a1.patch

@@ -0,0 +1,235 @@
+# HG changeset patch
+# User Eitan Isaacson <eitan@monotonous.org>
+# Date 1500911652 25200
+# Node ID 7faa02d1a6e235009e284fd3e5a7411305689a8a
+# Parent  88e195391a4a39b159ebfc56b7ad847d49700864
+Bug 1363723 - Prevent aria-owned nodes from getting into bad state. r=surkov
+
+diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp
+--- a/accessible/generic/DocAccessible.cpp
++++ b/accessible/generic/DocAccessible.cpp
+@@ -2151,16 +2151,21 @@ DocAccessible::DoARIAOwnsRelocation(Acce
+         continue;
+       }
+     }
+ 
+     MOZ_ASSERT(owned->SafeElementAt(idx) != child, "Already in place!");
+ 
+     // A new child is found, check for loops.
+     if (child->Parent() != aOwner) {
++      // Child is aria-owned by another container, skip.
++      if (child->IsRelocated()) {
++        continue;
++      }
++
+       Accessible* parent = aOwner;
+       while (parent && parent != child && !parent->IsDoc()) {
+         parent = parent->Parent();
+       }
+       // A referred child cannot be a parent of the owner.
+       if (parent == child) {
+         continue;
+       }
+@@ -2253,22 +2258,22 @@ bool
+ DocAccessible::MoveChild(Accessible* aChild, Accessible* aNewParent,
+                          int32_t aIdxInParent)
+ {
+   MOZ_ASSERT(aChild, "No child");
+   MOZ_ASSERT(aChild->Parent(), "No parent");
+   MOZ_ASSERT(aIdxInParent <= static_cast<int32_t>(aNewParent->ChildCount()),
+              "Wrong insertion point for a moving child");
+ 
++  Accessible* curParent = aChild->Parent();
++
+   if (!aNewParent->IsAcceptableChild(aChild->GetContent())) {
+     return false;
+   }
+ 
+-  Accessible* curParent = aChild->Parent();
+-
+ #ifdef A11Y_LOG
+   logging::TreeInfo("move child", 0,
+                     "old parent", curParent, "new parent", aNewParent,
+                     "child", aChild, nullptr);
+ #endif
+ 
+   // Forget aria-owns info in case of ARIA owned element. The caller is expected
+   // to update it if needed.
+diff --git a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
+--- a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
++++ b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
+@@ -184,51 +184,36 @@ async function removeContainer(browser, 
+ }
+ 
+ async function stealAndRecacheChildren(browser, accDoc) {
+   const id1 = "t3_container1";
+   const id2 = "t3_container2";
+   const acc1 = findAccessibleChildByID(accDoc, id1);
+   const acc2 = findAccessibleChildByID(accDoc, id2);
+ 
+-  /* ================ Steal from other ARIA owns ============================ */
++  /* ================ Attempt to steal from other ARIA owns ================= */
+   let onReorder = waitForEvent(EVENT_REORDER, id2);
+   await invokeSetAttribute(browser, id2, "aria-owns", "t3_child");
+-  await onReorder;
+-
+-  let tree = {
+-    SECTION: [ ]
+-  };
+-  testAccessibleTree(acc1, tree);
+-
+-  tree = {
+-    SECTION: [
+-      { CHECKBUTTON: [ ] }
+-    ]
+-  };
+-  testAccessibleTree(acc2, tree);
+-
+-  /* ================ Append element to recache children ==================== */
+-  onReorder = waitForEvent(EVENT_REORDER, id2);
+   await ContentTask.spawn(browser, id2, id => {
+     let div = content.document.createElement("div");
+     div.setAttribute("role", "radio");
+     content.document.getElementById(id).appendChild(div);
+   });
+   await onReorder;
+ 
+-  tree = {
+-    SECTION: [ ]
++  let tree = {
++    SECTION: [
++      { CHECKBUTTON: [ ] } // ARIA owned
++    ]
+   };
+   testAccessibleTree(acc1, tree);
+ 
+   tree = {
+     SECTION: [
+-      { RADIOBUTTON: [ ] },
+-      { CHECKBUTTON: [ ] } // ARIA owned
++      { RADIOBUTTON: [ ] }
+     ]
+   };
+   testAccessibleTree(acc2, tree);
+ }
+ 
+ async function showHiddenElement(browser, accDoc) {
+   const id = "t4_container1";
+   const acc = findAccessibleChildByID(accDoc, id);
+diff --git a/accessible/tests/mochitest/treeupdate/test_ariaowns.html b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
++++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+@@ -301,70 +301,80 @@
+       }
+ 
+       this.getID = function removeA11eteiner_getID() {
+         return "Remove an accessible DOM element containing an element referred by ARIA owns";
+       }
+     }
+ 
+     /**
+-     * Steal an element from other ARIA owns element. This use case guarantees
+-     * that result of setAttribute/removeAttribute doesn't depend on their order.
++     * Attempt to steal an element from other ARIA owns element. This should
++     * not be possible. The only child that will get owned into this
++     * container is a previously not aria-owned one.
+      */
+     function stealFromOtherARIAOwns() {
+       this.eventSeq = [
+-        new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
++        new invokerChecker(EVENT_REORDER, getNode("t3_container3"))
+       ];
+ 
+-      this.invoke = function stealFromOtherARIAOwns_invoke() {
+-        getNode("t3_container2").setAttribute("aria-owns", "t3_child");
++      this.invoke = function stealFromOtherARIAOwns_invoke()
++      {
++        getNode("t3_container3").setAttribute("aria-owns", "t3_child t3_child2");
+       }
+ 
+       this.finalCheck = function stealFromOtherARIAOwns_finalCheck() {
+         var tree =
+           { SECTION: [
++            { CHECKBUTTON: [
++            ] }
+           ] };
+         testAccessibleTree("t3_container1", tree);
+ 
+         tree =
+           { SECTION: [
++          ] };
++        testAccessibleTree("t3_container2", tree);
++
++        tree =
++          { SECTION: [
+             { CHECKBUTTON: [
+             ] }
+           ] };
+-        testAccessibleTree("t3_container2", tree);
++        testAccessibleTree("t3_container3", tree);
+       }
+ 
+-      this.getID = function stealFromOtherARIAOwns_getID() {
++      this.getID = function stealFromOtherARIAOwns_getID()
++      {
+         return "Steal an element from other ARIA owns element";
+       }
+     }
+ 
+     function appendElToRecacheChildren() {
+       this.eventSeq = [
+-        new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
++        new invokerChecker(EVENT_REORDER, getNode("t3_container3"))
+       ];
+ 
+       this.invoke = function appendElToRecacheChildren_invoke() {
+         var div = document.createElement("div");
+         div.setAttribute("role", "radio")
+-        getNode("t3_container2").appendChild(div);
++        getNode("t3_container3").appendChild(div);
+       }
+ 
+       this.finalCheck = function appendElToRecacheChildren_finalCheck() {
+         var tree =
+           { SECTION: [
+           ] };
+-        testAccessibleTree("t3_container1", tree);
++        testAccessibleTree("t3_container2", tree);
+ 
+         tree =
+           { SECTION: [
+             { RADIOBUTTON: [ ] },
+             { CHECKBUTTON: [ ] } // ARIA owned
+           ] };
+-        testAccessibleTree("t3_container2", tree);
++        testAccessibleTree("t3_container3", tree);
+       }
+ 
+       this.getID = function appendElToRecacheChildren_getID() {
+         return "Append a child under @aria-owns element to trigger children recache";
+       }
+     }
+ 
+     function showHiddenElement() {
+@@ -743,17 +753,20 @@
+ 
+   <div id="t2_container1" aria-owns="t2_owned"></div>
+   <div id="t2_container2">
+     <div id="t2_container3"><div id="t2_owned" role="checkbox"></div></div>
+   </div>
+ 
+   <div id="t3_container1" aria-owns="t3_child"></div>
+   <div id="t3_child" role="checkbox"></div>
+-  <div id="t3_container2"></div>
++  <div id="t3_container2">
++    <div id="t3_child2" role="checkbox"></div>
++  </div>
++  <div id="t3_container3"></div>
+ 
+   <div id="t4_container1" aria-owns="t4_child1 t4_child2"></div>
+   <div id="t4_container2">
+     <div id="t4_child1" style="display:none" role="checkbox"></div>
+     <div id="t4_child2" role="radio"></div>
+   </div>
+ 
+   <div id="t5_container">

+ 52 - 0
mozilla-release/patches/1363723-2-57a1.patch

@@ -0,0 +1,52 @@
+# HG changeset patch
+# User Eitan Isaacson <eitan@monotonous.org>
+# Date 1501884292 25200
+# Node ID a5d58cfbab429165b6812e50809eb0756099ab91
+# Parent  c541ddcbcac582fb517db3599289e8b012a656f4
+Bug 1363723 - Fix eslint failures. r=me
+
+
+diff --git a/accessible/tests/mochitest/treeupdate/test_ariaowns.html b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
++++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+@@ -310,18 +310,17 @@
+      * not be possible. The only child that will get owned into this
+      * container is a previously not aria-owned one.
+      */
+     function stealFromOtherARIAOwns() {
+       this.eventSeq = [
+         new invokerChecker(EVENT_REORDER, getNode("t3_container3"))
+       ];
+ 
+-      this.invoke = function stealFromOtherARIAOwns_invoke()
+-      {
++      this.invoke = function stealFromOtherARIAOwns_invoke() {
+         getNode("t3_container3").setAttribute("aria-owns", "t3_child t3_child2");
+       }
+ 
+       this.finalCheck = function stealFromOtherARIAOwns_finalCheck() {
+         var tree =
+           { SECTION: [
+             { CHECKBUTTON: [
+             ] }
+@@ -336,18 +335,17 @@
+         tree =
+           { SECTION: [
+             { CHECKBUTTON: [
+             ] }
+           ] };
+         testAccessibleTree("t3_container3", tree);
+       }
+ 
+-      this.getID = function stealFromOtherARIAOwns_getID()
+-      {
++      this.getID = function stealFromOtherARIAOwns_getID() {
+         return "Steal an element from other ARIA owns element";
+       }
+     }
+ 
+     function appendElToRecacheChildren() {
+       this.eventSeq = [
+         new invokerChecker(EVENT_REORDER, getNode("t3_container3"))
+       ];
+

+ 64 - 0
mozilla-release/patches/1402999-60a1.patch

@@ -0,0 +1,64 @@
+# HG changeset patch
+# User Eitan Isaacson <eitan@monotonous.org>
+# Date 1520323500 -7200
+# Node ID 2a0de8aa19f97208df6eb0678142ed0b63d29881
+# Parent  501e74dd33dac1ee479e26d6667dc15f5ed0a585
+Bug 1402999 - Don't process DOM event on dead document. r=surkov
+
+diff --git a/accessible/generic/RootAccessible.cpp b/accessible/generic/RootAccessible.cpp
+--- a/accessible/generic/RootAccessible.cpp
++++ b/accessible/generic/RootAccessible.cpp
+@@ -277,17 +277,20 @@ RootAccessible::ProcessDOMEvent(nsIDOMEv
+ 
+   if (eventType.EqualsLiteral("popuphiding")) {
+     HandlePopupHidingEvent(origTargetNode);
+     return;
+   }
+ 
+   DocAccessible* targetDocument = GetAccService()->
+     GetDocAccessible(origTargetNode->OwnerDoc());
+-  NS_ASSERTION(targetDocument, "No document while accessible is in document?!");
++  if (!targetDocument) {
++    // Document has ceased to exist.
++    return;
++  }
+ 
+   Accessible* accessible =
+     targetDocument->GetAccessibleOrContainer(origTargetNode);
+   if (!accessible)
+     return;
+ 
+ #ifdef MOZ_XUL
+   XULTreeAccessible* treeAcc = accessible->AsXULTree();
+diff --git a/accessible/tests/crashtests/1402999.html b/accessible/tests/crashtests/1402999.html
+new file mode 100644
+--- /dev/null
++++ b/accessible/tests/crashtests/1402999.html
+@@ -0,0 +1,11 @@
++<script>
++document.addEventListener("DOMContentLoaded", function(){
++  document.getElementById('a').click();
++  window.frames[0].document.body.appendChild(document.getElementById('b'));
++});
++</script>
++<cite id='b'>
++<label>
++<input/>
++<strong id='a'></strong>
++<iframe>
+diff --git a/accessible/tests/crashtests/crashtests.list b/accessible/tests/crashtests/crashtests.list
+--- a/accessible/tests/crashtests/crashtests.list
++++ b/accessible/tests/crashtests/crashtests.list
+@@ -1,10 +1,11 @@
+ load 448064.xhtml # This test instantiates a11y, so be careful about adding tests before it
+ load 471493.xul
+ asserts-if(!browserIsRemote,2) load 884202.html
+ load 890760.html
+ load 893515.html
+ load 1072792.xhtml
++load 1402999.html
+ 
+ # last_test_to_unload_testsuite.xul MUST be the last test in the list because it
+ # is responsible for shutting down accessibility service affecting later tests.
+ load last_test_to_unload_testsuite.xul
+

+ 200 - 0
mozilla-release/patches/1405796-59a1.patch

@@ -0,0 +1,200 @@
+# HG changeset patch
+# User Eitan Isaacson <eitan@monotonous.org>
+# Date 1513959900 18000
+# Node ID 10b290c3864352249245308df67214dce80f89cc
+# Parent  e6f4a2d1df9a4a50b1b659f87dca99d88a5ef63a
+Bug 1405796 - Don't traverse into relocated children in scoped TreeWalker. r=surkov
+
+diff --git a/accessible/base/TreeWalker.cpp b/accessible/base/TreeWalker.cpp
+--- a/accessible/base/TreeWalker.cpp
++++ b/accessible/base/TreeWalker.cpp
+@@ -71,16 +71,18 @@ TreeWalker::~TreeWalker()
+ 
+ Accessible*
+ TreeWalker::Scope(nsIContent* aAnchorNode)
+ {
+   Reset();
+ 
+   mAnchorNode = aAnchorNode;
+ 
++  mFlags |= eScoped;
++
+   bool skipSubtree = false;
+   Accessible* acc = AccessibleFor(aAnchorNode, 0, &skipSubtree);
+   if (acc) {
+     mPhase = eAtEnd;
+     return acc;
+   }
+ 
+   return skipSubtree ? nullptr : Next();
+@@ -107,16 +109,18 @@ TreeWalker::Seek(nsIContent* aChildNode)
+ 
+     if (!parentNode || !parentNode->IsElement()) {
+       return false;
+     }
+ 
+     // If ARIA owned child.
+     Accessible* child = mDoc->GetAccessible(childNode);
+     if (child && child->IsRelocated()) {
++      MOZ_ASSERT(!(mFlags & eScoped),
++        "Walker should not be scoped when seeking into relocated children");
+       if (child->Parent() != mContext) {
+         return false;
+       }
+ 
+       Accessible* ownedChild = nullptr;
+       while ((ownedChild = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++)) &&
+              ownedChild != child);
+ 
+@@ -144,22 +148,26 @@ Accessible*
+ TreeWalker::Next()
+ {
+   if (mStateStack.IsEmpty()) {
+     if (mPhase == eAtEnd) {
+       return nullptr;
+     }
+ 
+     if (mPhase == eAtDOM || mPhase == eAtARIAOwns) {
+-      mPhase = eAtARIAOwns;
+-      Accessible* child = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx);
+-      if (child) {
+-        mARIAOwnsIdx++;
+-        return child;
++      if (!(mFlags & eScoped)) {
++        mPhase = eAtARIAOwns;
++        Accessible* child = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx);
++        if (child) {
++          mARIAOwnsIdx++;
++          return child;
++        }
+       }
++      MOZ_ASSERT(!(mFlags & eScoped) || mPhase != eAtARIAOwns,
++        "Don't walk relocated children in scoped mode");
+       mPhase = eAtEnd;
+       return nullptr;
+     }
+ 
+     if (!mAnchorNode) {
+       mPhase = eAtEnd;
+       return nullptr;
+     }
+@@ -225,21 +233,27 @@ TreeWalker::Prev()
+ {
+   if (mStateStack.IsEmpty()) {
+     if (mPhase == eAtStart || mPhase == eAtDOM) {
+       mPhase = eAtStart;
+       return nullptr;
+     }
+ 
+     if (mPhase == eAtEnd) {
+-      mARIAOwnsIdx = mDoc->ARIAOwnedCount(mContext);
+-      mPhase = eAtARIAOwns;
++      if (mFlags & eScoped) {
++        mPhase = eAtDOM;
++      } else {
++        mPhase = eAtARIAOwns;
++        mARIAOwnsIdx = mDoc->ARIAOwnedCount(mContext);
++      }
+     }
+ 
+     if (mPhase == eAtARIAOwns) {
++      MOZ_ASSERT(!(mFlags & eScoped),
++        "Should not walk relocated children in scoped mode");
+       if (mARIAOwnsIdx > 0) {
+         return mDoc->ARIAOwnedAt(mContext, --mARIAOwnsIdx);
+       }
+ 
+       if (!mAnchorNode) {
+         mPhase = eAtStart;
+         return nullptr;
+       }
+diff --git a/accessible/base/TreeWalker.h b/accessible/base/TreeWalker.h
+--- a/accessible/base/TreeWalker.h
++++ b/accessible/base/TreeWalker.h
+@@ -24,17 +24,18 @@ class DocAccessible;
+  */
+ class TreeWalker final
+ {
+ public:
+   enum {
+     // used to walk the existing tree of the given node
+     eWalkCache = 1,
+     // used to walk the context tree starting from given node
+-    eWalkContextTree = 2 | eWalkCache
++    eWalkContextTree = 2 | eWalkCache,
++    eScoped = 4
+   };
+ 
+   /**
+    * Used to navigate and create if needed the accessible children.
+    */
+   explicit TreeWalker(Accessible* aContext);
+ 
+   /**
+diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp
+--- a/accessible/generic/DocAccessible.cpp
++++ b/accessible/generic/DocAccessible.cpp
+@@ -1848,16 +1848,17 @@ InsertIterator::Next()
+         return true;
+       }
+     }
+     else {
+       TreeWalker finder(container);
+       if (finder.Seek(node)) {
+         mChild = mWalker.Scope(node);
+         if (mChild) {
++          MOZ_ASSERT(!mChild->IsRelocated(), "child cannot be aria owned");
+           mChildBefore = finder.Prev();
+           return true;
+         }
+       }
+     }
+   }
+ 
+   return false;
+diff --git a/accessible/tests/browser/tree/browser_aria_owns.js b/accessible/tests/browser/tree/browser_aria_owns.js
+--- a/accessible/tests/browser/tree/browser_aria_owns.js
++++ b/accessible/tests/browser/tree/browser_aria_owns.js
+@@ -213,8 +213,41 @@ addAccessibleTask(`<div id="a"></div><di
+       document.documentElement.getBoundingClientRect();
+       document.body.setAttribute("aria-owns", "b a");
+       document.documentElement.remove();
+     });
+ 
+     testChildrenIds(accDoc, []);
+   }
+ );
++
++// Don't allow ordinal child to be placed after aria-owned child (bug 1405796)
++addAccessibleTask(`<div id="container"><div id="a">Hello</div></div>
++                   <div><div id="c">There</div><div id="d">There</div></div>`,
++  async function(browser, accDoc) {
++    let containerAcc = findAccessibleChildByID(accDoc, "container");
++
++    testChildrenIds(containerAcc, ["a"]);
++
++    await contentSpawnMutation(browser, MOVE, function() {
++      document.getElementById("container").setAttribute("aria-owns", "c");
++    });
++
++    testChildrenIds(containerAcc, ["a", "c"]);
++
++    await contentSpawnMutation(browser, MOVE, function() {
++      let span = document.createElement("span");
++      document.getElementById("container").appendChild(span);
++
++      let b = document.createElement("div");
++      b.id = "b";
++      document.getElementById("container").appendChild(b);
++    });
++
++    testChildrenIds(containerAcc, ["a", "b", "c"]);
++
++    await contentSpawnMutation(browser, MOVE, function() {
++      document.getElementById("container").setAttribute("aria-owns", "c d");
++    });
++
++    testChildrenIds(containerAcc, ["a", "b", "c", "d"]);
++  }
++);
+

+ 185 - 0
mozilla-release/patches/1408777-FIX-58a1.patch

@@ -0,0 +1,185 @@
+# HG changeset patch
+# User Dan Banner <dbugs@thebanners.uk>
+# Date 1508093430 -3600
+# Node ID 167e5e6fd9308fa6557f2010ac5c3821558e8015
+# Parent  6b35a1e24aad4d72b4b277c550584b6155ff0fe2
+Bug 1408777 - Automatically fix instances of missing semicolons in the tree. r=Standard8
+
+MozReview-Commit-ID: Jm8BRgt6mIv
+
+diff --git a/accessible/tests/mochitest/treeupdate/test_ariaowns.html b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
++++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+@@ -286,43 +286,43 @@
+       this.invoke = function removeA11eteiner_invoke() {
+         var tree =
+           { SECTION: [
+               { CHECKBUTTON: [ ] } // ARIA owned, 't2_owned'
+           ] };
+         testAccessibleTree("t2_container1", tree);
+ 
+         getNode("t2_container2").removeChild(getNode("t2_container3"));
+-      }
++      };
+ 
+       this.finalCheck = function removeA11eteiner_finalCheck() {
+         var tree =
+           { SECTION: [
+           ] };
+         testAccessibleTree("t2_container1", tree);
+-      }
++      };
+ 
+       this.getID = function removeA11eteiner_getID() {
+         return "Remove an accessible DOM element containing an element referred by ARIA owns";
+-      }
++      };
+     }
+ 
+     /**
+      * Attempt to steal an element from other ARIA owns element. This should
+      * not be possible. The only child that will get owned into this
+      * container is a previously not aria-owned one.
+      */
+     function stealFromOtherARIAOwns() {
+       this.eventSeq = [
+         new invokerChecker(EVENT_REORDER, getNode("t3_container3"))
+       ];
+ 
+       this.invoke = function stealFromOtherARIAOwns_invoke() {
+         getNode("t3_container3").setAttribute("aria-owns", "t3_child t3_child2");
+-      }
++      };
+ 
+       this.finalCheck = function stealFromOtherARIAOwns_finalCheck() {
+         var tree =
+           { SECTION: [
+             { CHECKBUTTON: [
+             ] }
+           ] };
+         testAccessibleTree("t3_container1", tree);
+@@ -333,110 +333,110 @@
+         testAccessibleTree("t3_container2", tree);
+ 
+         tree =
+           { SECTION: [
+             { CHECKBUTTON: [
+             ] }
+           ] };
+         testAccessibleTree("t3_container3", tree);
+-      }
++      };
+ 
+       this.getID = function stealFromOtherARIAOwns_getID() {
+         return "Steal an element from other ARIA owns element";
+-      }
++      };
+     }
+ 
+     function appendElToRecacheChildren() {
+       this.eventSeq = [
+         new invokerChecker(EVENT_REORDER, getNode("t3_container3"))
+       ];
+ 
+       this.invoke = function appendElToRecacheChildren_invoke() {
+         var div = document.createElement("div");
+-        div.setAttribute("role", "radio")
++        div.setAttribute("role", "radio");
+         getNode("t3_container3").appendChild(div);
+-      }
++      };
+ 
+       this.finalCheck = function appendElToRecacheChildren_finalCheck() {
+         var tree =
+           { SECTION: [
+           ] };
+         testAccessibleTree("t3_container2", tree);
+ 
+         tree =
+           { SECTION: [
+             { RADIOBUTTON: [ ] },
+             { CHECKBUTTON: [ ] } // ARIA owned
+           ] };
+         testAccessibleTree("t3_container3", tree);
+-      }
++      };
+ 
+       this.getID = function appendElToRecacheChildren_getID() {
+         return "Append a child under @aria-owns element to trigger children recache";
+-      }
++      };
+     }
+ 
+     function showHiddenElement() {
+       this.eventSeq = [
+         new invokerChecker(EVENT_REORDER, getNode("t4_container1"))
+       ];
+ 
+       this.invoke = function showHiddenElement_invoke() {
+         var tree =
+           { SECTION: [
+             { RADIOBUTTON: [] }
+           ] };
+         testAccessibleTree("t4_container1", tree);
+ 
+         getNode("t4_child1").style.display = "block";
+-      }
++      };
+ 
+       this.finalCheck = function showHiddenElement_finalCheck() {
+         var tree =
+           { SECTION: [
+             { CHECKBUTTON: [] },
+             { RADIOBUTTON: [] }
+           ] };
+         testAccessibleTree("t4_container1", tree);
+-      }
++      };
+ 
+       this.getID = function showHiddenElement_getID() {
+         return "Show hidden ARIA owns referred element";
+-      }
++      };
+     }
+ 
+     function rearrangeARIAOwns(aContainer, aAttr, aIdList, aRoleList) {
+       this.eventSeq = [];
+-      for (let id of aIdList) {
++      for (var id of aIdList) {
+         this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id)));
+       }
+ 
+-      for (let id of aIdList) {
++      for (var id of aIdList) {
+         this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id)));
+       }
+       this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer)));
+ 
+       this.invoke = function rearrangeARIAOwns_invoke() {
+         getNode(aContainer).setAttribute("aria-owns", aAttr);
+-      }
++      };
+ 
+       this.finalCheck = function rearrangeARIAOwns_finalCheck() {
+         var tree = { SECTION: [ ] };
+         for (var role of aRoleList) {
+           var ch = {};
+           ch[role] = [];
+           tree.SECTION.push(ch);
+         }
+         testAccessibleTree(aContainer, tree);
+-      }
++      };
+ 
+       this.getID = function rearrangeARIAOwns_getID() {
+         return `Rearrange @aria-owns attribute to '${aAttr}'`;
+-      }
++      };
+     }
+ 
+     function removeNotARIAOwnedEl(aContainer, aChild) {
+       this.eventSeq = [
+         new invokerChecker(EVENT_REORDER, aContainer)
+       ];
+ 
+       this.invoke = function removeNotARIAOwnedEl_invoke() {

+ 210 - 0
mozilla-release/patches/1416893-59a1.patch

@@ -0,0 +1,210 @@
+# HG changeset patch
+# User Yura Zenevich <yura.zenevich@gmail.com>
+# Date 1510608997 18000
+# Node ID 207a13b699ac7b2a3eb58384dac109c3269552d5
+# Parent  5fa423b95ce4c40101046f0b3d382b61a1293f3e
+Bug 1416893 - Added getConsumers method to nsIAccessibilityService. r=surkov
+
+MozReview-Commit-ID: EoBdYSxqEGz
+
+
+diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp
+--- a/accessible/base/nsAccessibilityService.cpp
++++ b/accessible/base/nsAccessibilityService.cpp
+@@ -1872,34 +1872,42 @@ nsAccessibilityService::UnsetConsumers(u
+     return;
+   }
+ 
+   gConsumers &= ~aConsumers;
+   NotifyOfConsumersChange();
+ }
+ 
+ void
++nsAccessibilityService::GetConsumers(nsAString& aString)
++{
++  const char16_t* kJSONFmt =
++    u"{ \"XPCOM\": %s, \"MainProcess\": %s, \"PlatformAPI\": %s }";
++  nsString json;
++  nsTextFormatter::ssprintf(json, kJSONFmt,
++    gConsumers & eXPCOM ? "true" : "false",
++    gConsumers & eMainProcess ? "true" : "false",
++    gConsumers & ePlatformAPI ? "true" : "false");
++  aString.Assign(json);
++}
++
++void
+ nsAccessibilityService::NotifyOfConsumersChange()
+ {
+   nsCOMPtr<nsIObserverService> observerService =
+     mozilla::services::GetObserverService();
+ 
+   if (!observerService) {
+     return;
+   }
+ 
+-  const char16_t* kJSONFmt =
+-    u"{ \"XPCOM\": %s, \"MainProcess\": %s, \"PlatformAPI\": %s }";
+-  nsString json;
+-  nsTextFormatter::ssprintf(json, kJSONFmt,
+-    gConsumers & eXPCOM ? "true" : "false",
+-    gConsumers & eMainProcess ? "true" : "false",
+-    gConsumers & ePlatformAPI ? "true" : "false");
++  nsAutoString consumers;
++  GetConsumers(consumers);
+   observerService->NotifyObservers(
+-    nullptr, "a11y-consumers-changed", json.get());
++    nullptr, "a11y-consumers-changed", consumers.get());
+ }
+ 
+ nsAccessibilityService*
+ GetOrCreateAccService(uint32_t aNewConsumer)
+ {
+   if (!nsAccessibilityService::gAccessibilityService) {
+     RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
+     if (!service->Init()) {
+diff --git a/accessible/base/nsAccessibilityService.h b/accessible/base/nsAccessibilityService.h
+--- a/accessible/base/nsAccessibilityService.h
++++ b/accessible/base/nsAccessibilityService.h
+@@ -305,16 +305,21 @@ private:
+                                 Accessible* aContext);
+ 
+   /**
+    * Notify observers about change of the accessibility service's consumers.
+    */
+   void NotifyOfConsumersChange();
+ 
+   /**
++   * Get a JSON string representing the accessibility service consumers.
++   */
++  void GetConsumers(nsAString& aString);
++
++  /**
+    * Set accessibility service consumers.
+    */
+   void SetConsumers(uint32_t aConsumers);
+ 
+   /**
+    * Unset accessibility service consumers.
+    */
+   void UnsetConsumers(uint32_t aConsumers);
+diff --git a/accessible/interfaces/nsIAccessibilityService.idl b/accessible/interfaces/nsIAccessibilityService.idl
+--- a/accessible/interfaces/nsIAccessibilityService.idl
++++ b/accessible/interfaces/nsIAccessibilityService.idl
+@@ -11,17 +11,17 @@ interface nsIWeakReference;
+ interface nsIPresShell;
+ interface nsIAccessiblePivot;
+ 
+ /**
+  * An interface for in-process accessibility clients wishing to get an
+  * nsIAccessible for a given DOM node.  More documentation at:
+  *   http://www.mozilla.org/projects/ui/accessibility
+  */
+-[scriptable, builtinclass, uuid(9a6f80fe-25cc-405c-9f8f-25869bc9f94e)]
++[scriptable, builtinclass, uuid(2188e3a0-c88e-11e7-8f1a-0800200c9a66)]
+ interface nsIAccessibilityService : nsISupports
+ {
+   /**
+    * Return application accessible.
+    */
+   nsIAccessible getApplicationAccessible();
+ 
+   /**
+@@ -92,9 +92,15 @@ interface nsIAccessibilityService : nsIS
+    * @see Logging.cpp for list of possible values.
+    */
+   void setLogging(in ACString aModules);
+ 
+   /**
+    * Return true if the given module is logged.
+    */
+   boolean isLogged(in AString aModule);
++
++  /**
++   * Get the current accessibility service consumers.
++   * @returns a JSON string representing the accessibility service consumers.
++   */
++  AString getConsumers();
+ };
+diff --git a/accessible/tests/browser/browser_shutdown_remote_no_reference.js b/accessible/tests/browser/browser_shutdown_remote_no_reference.js
+--- a/accessible/tests/browser/browser_shutdown_remote_no_reference.js
++++ b/accessible/tests/browser/browser_shutdown_remote_no_reference.js
+@@ -34,16 +34,20 @@ add_task(async function() {
+     await Promise.all([parentA11yInit, contentA11yInit]);
+     await parentConsumersChanged.then(data => Assert.deepEqual(data, {
+       XPCOM: true, MainProcess: false, PlatformAPI: false
+     }, "Accessibility service consumers in parent are correct."));
+     await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+       XPCOM: false, MainProcess: true, PlatformAPI: false
+     }, "Accessibility service consumers in content are correct."));
+ 
++    Assert.deepEqual(JSON.parse(accService.getConsumers()), {
++      XPCOM: true, MainProcess: false, PlatformAPI: false
++    }, "Accessibility service consumers in parent are correct.");
++
+     info("Removing a service in parent and waiting for service to be shut " +
+       "down in content");
+     // Remove a11y service reference in the main process.
+     let parentA11yShutdown = shutdownPromise();
+     let contentA11yShutdown = shutdownPromise(browser);
+     parentConsumersChanged = a11yConsumersChangedPromise();
+     contentConsumersChanged =
+       ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
+diff --git a/accessible/tests/browser/browser_shutdown_remote_own_reference.js b/accessible/tests/browser/browser_shutdown_remote_own_reference.js
+--- a/accessible/tests/browser/browser_shutdown_remote_own_reference.js
++++ b/accessible/tests/browser/browser_shutdown_remote_own_reference.js
+@@ -42,16 +42,22 @@ add_task(async function() {
+     // Add a new reference to the a11y service inside the content process.
+     loadFrameScripts(browser, `let accService = Components.classes[
+       '@mozilla.org/accessibilityService;1'].getService(
+         Components.interfaces.nsIAccessibilityService);`);
+     await contentConsumersChanged.then(data => Assert.deepEqual(data, {
+       XPCOM: true, MainProcess: true, PlatformAPI: false
+     }, "Accessibility service consumers in content are correct."));
+ 
++    const contentConsumers = await ContentTask.spawn(browser, {}, () =>
++      accService.getConsumers());
++    Assert.deepEqual(JSON.parse(contentConsumers), {
++      XPCOM: true, MainProcess: true, PlatformAPI: false
++    }, "Accessibility service consumers in parent are correct.");
++
+     info("Shutting down a service in parent and making sure the one in " +
+       "content stays alive");
+     let contentCanShutdown = false;
+     let parentA11yShutdown = shutdownPromise();
+     contentConsumersChanged =
+       ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
+     // This promise will resolve only if contentCanShutdown flag is set to true.
+     // If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
+diff --git a/accessible/xpcom/xpcAccessibilityService.cpp b/accessible/xpcom/xpcAccessibilityService.cpp
+--- a/accessible/xpcom/xpcAccessibilityService.cpp
++++ b/accessible/xpcom/xpcAccessibilityService.cpp
+@@ -253,16 +253,28 @@ xpcAccessibilityService::IsLogged(const 
+ 
+ #ifdef A11Y_LOG
+   *aIsLogged = logging::IsEnabled(aModule);
+ #endif
+ 
+   return NS_OK;
+ }
+ 
++NS_IMETHODIMP
++xpcAccessibilityService::GetConsumers(nsAString& aString)
++{
++  nsAccessibilityService* accService = GetAccService();
++  if (!accService) {
++    return NS_ERROR_SERVICE_NOT_AVAILABLE;
++  }
++
++  accService->GetConsumers(aString);
++  return NS_OK;
++}
++
+ ////////////////////////////////////////////////////////////////////////////////
+ // NS_GetAccessibilityService
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ nsresult
+ NS_GetAccessibilityService(nsIAccessibilityService** aResult)
+ {
+   NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
+

+ 195 - 0
mozilla-release/patches/1419131-59a1.patch

@@ -0,0 +1,195 @@
+# HG changeset patch
+# User Yura Zenevich <yura.zenevich@gmail.com>
+# Date 1511902924 18000
+# Node ID f7a11b900cd26272a12caf3ae673db13a98ddb42
+# Parent  622c05a8e7a1ccb130bfae4197e2a6eaedbe4dd8
+Bug 1419131 - adding a11y force disabled pref observer when accessibility service is being created. r=surkov
+
+MozReview-Commit-ID: G2pG3PcUMrE
+
+
+diff --git a/accessible/aom/AccessibleNode.cpp b/accessible/aom/AccessibleNode.cpp
+--- a/accessible/aom/AccessibleNode.cpp
++++ b/accessible/aom/AccessibleNode.cpp
+@@ -25,18 +25,22 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
+   NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_INTERFACE_MAP_END
+ 
+ NS_IMPL_CYCLE_COLLECTING_ADDREF(AccessibleNode)
+ NS_IMPL_CYCLE_COLLECTING_RELEASE(AccessibleNode)
+ 
+ AccessibleNode::AccessibleNode(nsINode* aNode) : mDOMNode(aNode)
+ {
+-  DocAccessible* doc =
+-    GetOrCreateAccService()->GetDocAccessible(mDOMNode->OwnerDoc());
++  nsAccessibilityService* accService = GetOrCreateAccService();
++  if (!accService) {
++    return;
++  }
++
++  DocAccessible* doc = accService->GetDocAccessible(mDOMNode->OwnerDoc());
+   if (doc) {
+     mIntl = doc->GetAccessible(mDOMNode);
+   }
+ }
+ 
+ AccessibleNode::~AccessibleNode()
+ {
+ }
+@@ -52,35 +56,42 @@ AccessibleNode::GetParentObject() const
+ {
+   return mDOMNode->GetParentObject();
+ }
+ 
+ void
+ AccessibleNode::GetRole(nsAString& aRole)
+ {
+   if (mIntl) {
+-    GetOrCreateAccService()->GetStringRole(mIntl->Role(), aRole);
+-    return;
++    nsAccessibilityService* accService = GetOrCreateAccService();
++    if (accService) {
++      accService->GetStringRole(mIntl->Role(), aRole);
++      return;
++    }
+   }
+ 
+   aRole.AssignLiteral("unknown");
+ }
+ 
+ void
+ AccessibleNode::GetStates(nsTArray<nsString>& aStates)
+ {
+-  if (mIntl) {
+-    if (!mStates) {
+-      mStates = GetOrCreateAccService()->GetStringStates(mIntl->State());
+-    }
++  nsAccessibilityService* accService = GetOrCreateAccService();
++  if (!mIntl || !accService) {
++    aStates.AppendElement(NS_LITERAL_STRING("defunct"));
++    return;
++  }
++
++  if (mStates) {
+     aStates = mStates->StringArray();
+     return;
+   }
+ 
+-  aStates.AppendElement(NS_LITERAL_STRING("defunct"));
++  mStates = accService->GetStringStates(mIntl->State());
++  aStates = mStates->StringArray();
+ }
+ 
+ void
+ AccessibleNode::GetAttributes(nsTArray<nsString>& aAttributes)
+ {
+   if (!mIntl) {
+     return;
+   }
+@@ -101,30 +112,31 @@ AccessibleNode::GetAttributes(nsTArray<n
+     prop->GetKey(attr);
+     aAttributes.AppendElement(NS_ConvertUTF8toUTF16(attr));
+   }
+ }
+ 
+ bool
+ AccessibleNode::Is(const Sequence<nsString>& aFlavors)
+ {
+-  if (!mIntl) {
++  nsAccessibilityService* accService = GetOrCreateAccService();
++  if (!mIntl || !accService) {
+     for (const auto& flavor : aFlavors) {
+       if (!flavor.EqualsLiteral("unknown") && !flavor.EqualsLiteral("defunct")) {
+         return false;
+       }
+     }
+     return true;
+   }
+ 
+   nsAutoString role;
+-  GetOrCreateAccService()->GetStringRole(mIntl->Role(), role);
++  accService->GetStringRole(mIntl->Role(), role);
+ 
+   if (!mStates) {
+-    mStates = GetOrCreateAccService()->GetStringStates(mIntl->State());
++    mStates = accService->GetStringStates(mIntl->State());
+   }
+ 
+   for (const auto& flavor : aFlavors) {
+     if (!flavor.Equals(role) && !mStates->Contains(flavor)) {
+       return false;
+     }
+   }
+   return true;
+diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp
+--- a/accessible/base/nsAccessibilityService.cpp
++++ b/accessible/base/nsAccessibilityService.cpp
+@@ -1899,16 +1899,21 @@ nsAccessibilityService::NotifyOfConsumer
+   GetConsumers(consumers);
+   observerService->NotifyObservers(
+     nullptr, "a11y-consumers-changed", consumers.get());
+ }
+ 
+ nsAccessibilityService*
+ GetOrCreateAccService(uint32_t aNewConsumer)
+ {
++  // Do not initialize accessibility if it is force disabled.
++  if (PlatformDisabledState() == ePlatformIsDisabled) {
++    return nullptr;
++  }
++
+   if (!nsAccessibilityService::gAccessibilityService) {
+     RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
+     if (!service->Init()) {
+       service->Shutdown();
+       return nullptr;
+     }
+   }
+ 
+diff --git a/accessible/xpcom/xpcAccessibilityService.cpp b/accessible/xpcom/xpcAccessibilityService.cpp
+--- a/accessible/xpcom/xpcAccessibilityService.cpp
++++ b/accessible/xpcom/xpcAccessibilityService.cpp
+@@ -41,17 +41,17 @@ xpcAccessibilityService::AddRef(void)
+   MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
+   if (!mRefCnt.isThreadSafe)
+     NS_ASSERT_OWNINGTHREAD(xpcAccessibilityService);
+   nsrefcnt count = ++mRefCnt;
+   NS_LOG_ADDREF(this, count, "xpcAccessibilityService", sizeof(*this));
+ 
+   // We want refcount to be > 1 because one reference is added in the XPCOM
+   // accessibility service getter.
+-  if (mRefCnt > 1 && PlatformDisabledState() != ePlatformIsDisabled) {
++  if (mRefCnt > 1) {
+     GetOrCreateAccService(nsAccessibilityService::eXPCOM);
+   }
+ 
+   return count;
+ }
+ 
+ NS_IMETHODIMP_(MozExternalRefCountType)
+ xpcAccessibilityService::Release(void)
+@@ -275,22 +275,19 @@ xpcAccessibilityService::GetConsumers(ns
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ nsresult
+ NS_GetAccessibilityService(nsIAccessibilityService** aResult)
+ {
+   NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
+   *aResult = nullptr;
+ 
+-  // Do not initialize accessibility if it is force disabled.
+-  if (PlatformDisabledState() == ePlatformIsDisabled) {
++  if (!GetOrCreateAccService(nsAccessibilityService::eXPCOM)) {
+     return NS_ERROR_SERVICE_NOT_AVAILABLE;
+   }
+ 
+-  GetOrCreateAccService(nsAccessibilityService::eXPCOM);
+-
+   xpcAccessibilityService* service = new xpcAccessibilityService();
+   NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
+   xpcAccessibilityService::gXPCAccessibilityService = service;
+   NS_ADDREF(*aResult = service);
+ 
+   return NS_OK;
+ }
+

+ 99 - 0
mozilla-release/patches/1427825-59a1.patch

@@ -0,0 +1,99 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1515005956 -3600
+# Node ID b0a210594814d1cc3795bd64e750d3d8d54124e7
+# Parent  c942e00b2186beb7013ccc3c766a9189c3ba61ae
+Bug 1427825: Make accessibility use the flattened tree more consistently. r=surkov
+
+MozReview-Commit-ID: 4mFkvqheZOK
+
+diff --git a/accessible/base/NotificationController.cpp b/accessible/base/NotificationController.cpp
+--- a/accessible/base/NotificationController.cpp
++++ b/accessible/base/NotificationController.cpp
+@@ -642,18 +642,18 @@ NotificationController::WillRefresh(mozi
+   // Process rendered text change notifications.
+   for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) {
+     nsCOMPtrHashKey<nsIContent>* entry = iter.Get();
+     nsIContent* textNode = entry->GetKey();
+     Accessible* textAcc = mDocument->GetAccessible(textNode);
+ 
+     // If the text node is not in tree or doesn't have frame then this case should
+     // have been handled already by content removal notifications.
+-    nsINode* containerNode = textNode->GetParentNode();
+-    if (!containerNode) {
++    nsINode* containerNode = textNode->GetFlattenedTreeParentNode();
++    if (!containerNode || textNode->OwnerDoc() != mDocument->DocumentNode()) {
+       NS_ASSERTION(!textAcc,
+                    "Text node was removed but accessible is kept alive!");
+       continue;
+     }
+ 
+     nsIFrame* textFrame = textNode->GetPrimaryFrame();
+     if (!textFrame) {
+       NS_ASSERTION(!textAcc,
+diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp
+--- a/accessible/generic/DocAccessible.cpp
++++ b/accessible/generic/DocAccessible.cpp
+@@ -1247,36 +1247,24 @@ DocAccessible::GetAccessibleByUniqueIDIn
+ }
+ 
+ Accessible*
+ DocAccessible::GetAccessibleOrContainer(nsINode* aNode) const
+ {
+   if (!aNode || !aNode->GetComposedDoc())
+     return nullptr;
+ 
+-  nsINode* currNode = aNode;
+-  Accessible* accessible = nullptr;
+-  while (!(accessible = GetAccessible(currNode))) {
+-    nsINode* parent = nullptr;
+-
+-    // If this is a content node, try to get a flattened parent content node.
+-    // This will smartly skip from the shadow root to the host element,
+-    // over parentless document fragment
+-    if (currNode->IsContent())
+-      parent = currNode->AsContent()->GetFlattenedTreeParent();
+-
+-    // Fallback to just get parent node, in case there is no parent content
+-    // node. Or current node is not a content node.
+-    if (!parent)
+-      parent = currNode->GetParentNode();
+-
+-    if (!(currNode = parent)) break;
++  for (nsINode* currNode = aNode; currNode;
++       currNode = currNode->GetFlattenedTreeParentNode()) {
++    if (Accessible* accessible = GetAccessible(currNode)) {
++      return accessible;
++    }
+   }
+ 
+-  return accessible;
++  return nullptr;
+ }
+ 
+ Accessible*
+ DocAccessible::GetAccessibleOrDescendant(nsINode* aNode) const
+ {
+   Accessible* acc = GetAccessible(aNode);
+   if (acc)
+     return acc;
+@@ -2212,17 +2200,18 @@ DocAccessible::PutChildrenBack(nsTArray<
+                       "old parent", owner, "child", child, nullptr);
+ #endif
+ 
+     // Unset relocated flag to find an insertion point for the child.
+     child->SetRelocated(false);
+ 
+     nsIContent* content = child->GetContent();
+     int32_t idxInParent = -1;
+-    Accessible* origContainer = AccessibleOrTrueContainer(content->GetParentNode());
++    Accessible* origContainer =
++      AccessibleOrTrueContainer(content->GetFlattenedTreeParentNode());
+     if (origContainer) {
+       TreeWalker walker(origContainer);
+       if (walker.Seek(content)) {
+         Accessible* prevChild = walker.Prev();
+         if (prevChild) {
+           idxInParent = prevChild->IndexInParent() + 1;
+           MOZ_DIAGNOSTIC_ASSERT(origContainer == prevChild->Parent(), "Broken tree");
+           origContainer = prevChild->Parent();

+ 277 - 0
mozilla-release/patches/1431256-1-61a1.patch

@@ -0,0 +1,277 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1521641333 14400
+#      Wed Mar 21 10:08:53 2018 -0400
+# Node ID fc4b465ae5c1d8e9910c3e5815e3f4cb2f083637
+# Parent  e1bd2a0806123389100e53c448c1c45cc44fa47b
+Bug 1431256 part 1: Accessible HandlerProvider: Implement a method to optimally retrieve all children in a single call. r=MarcoZ
+
+When considering a large document, a huge number of the children we return are text leaf nodes.
+Marshaling full objects is expensive, but for text leaf nodes, the client is only interested in the text and a few other pieces of information.
+Therefore, rather than returning the full object for text leaf accessibles, we just return the text and other necessary information.
+For other non-text children, we return the full object as usual.
+
+In addition, clients normally use the IEnumVARIANT interface to retrieve children in a single call.
+However, it doesn't allow you to specify a starting index.
+Therefore, you must first call the Reset method to reset the starting point to 0.
+Practically, this means an extra cross-process call whenever the caller fetches children.
+When dealing with a large document, this can be a significant number of wasted calls.
+This new method retrieves all children always starting at the first using a single call.
+
+MozReview-Commit-ID: A9lc7BBTWdb
+
+diff --git a/accessible/ipc/win/HandlerProvider.cpp b/accessible/ipc/win/HandlerProvider.cpp
+--- a/accessible/ipc/win/HandlerProvider.cpp
++++ b/accessible/ipc/win/HandlerProvider.cpp
+@@ -756,11 +756,159 @@ HandlerProvider::get_RelationsInfo(IARel
+                                  &HandlerProvider::GetRelationsInfoMainThread,
+                                  aRelations, aNRelations, &hr)) {
+     return E_FAIL;
+   }
+ 
+   return hr;
+ }
+ 
++// Helper function for GetAllChildrenMainThread.
++static bool
++SetChildDataForTextLeaf(NEWEST_IA2_INTERFACE* acc, AccChildData& data)
++{
++  const VARIANT kChildIdSelf = {VT_I4};
++  VARIANT varVal;
++
++  // 1. Check whether this is a text leaf.
++
++  // 1.1. A text leaf always has ROLE_SYSTEM_TEXT or ROLE_SYSTEM_WHITESPACE.
++  HRESULT hr = acc->get_accRole(kChildIdSelf, &varVal);
++  if (FAILED(hr)) {
++    return false;
++  }
++  if (varVal.vt != VT_I4) {
++    return false;
++  }
++  long role = varVal.lVal;
++  if (role != ROLE_SYSTEM_TEXT && role != ROLE_SYSTEM_WHITESPACE) {
++    return false;
++  }
++
++  // 1.2. A text leaf doesn't support IAccessibleText.
++  RefPtr<IAccessibleText> iaText;
++  hr = acc->QueryInterface(IID_IAccessibleText, getter_AddRefs(iaText));
++  if (SUCCEEDED(hr)) {
++    return false;
++  }
++
++  // 1.3. A text leaf doesn't have children.
++  long count;
++  hr = acc->get_accChildCount(&count);
++  if (FAILED(hr) || count != 0) {
++    return false;
++  }
++
++  // 2. Update |data| with the data for this text leaf.
++  // Because marshaling objects is more expensive than marshaling other data,
++  // we just marshal the data we need for text leaf children, rather than
++  // marshaling the full accessible object.
++
++  // |data| has already been zeroed, so we don't need to do anything if these
++  // calls fail.
++  acc->get_accName(kChildIdSelf, &data.mText);
++  data.mTextRole = role;
++  acc->get_uniqueID(&data.mTextId);
++  acc->get_accState(kChildIdSelf, &varVal);
++  data.mTextState = varVal.lVal;
++  acc->accLocation(&data.mTextLeft, &data.mTextTop, &data.mTextWidth,
++                   &data.mTextHeight, kChildIdSelf);
++
++  return true;
++}
++
++void
++HandlerProvider::GetAllChildrenMainThread(AccChildData** aChildren,
++                                          ULONG* aNChildren,
++                                          HRESULT* hr)
++{
++  MOZ_ASSERT(aChildren);
++  MOZ_ASSERT(aNChildren);
++  MOZ_ASSERT(NS_IsMainThread());
++
++  if (!mTargetUnk) {
++    *hr = CO_E_OBJNOTCONNECTED;
++    return;
++  }
++
++  RefPtr<NEWEST_IA2_INTERFACE> acc;
++  *hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID,
++    getter_AddRefs(acc));
++  if (FAILED(*hr)) {
++    return;
++  }
++
++  long count;
++  *hr = acc->get_accChildCount(&count);
++  if (FAILED(*hr)) {
++    return;
++  }
++  MOZ_ASSERT(count >= 0);
++
++  if (count == 0) {
++    *aChildren = nullptr;
++    *aNChildren = 0;
++    return;
++  }
++
++  RefPtr<IEnumVARIANT> enumVar;
++  *hr = mTargetUnk.get()->QueryInterface(IID_IEnumVARIANT,
++    getter_AddRefs(enumVar));
++  if (FAILED(*hr)) {
++    return;
++  }
++
++  auto rawChildren = MakeUnique<VARIANT[]>(count);
++  *hr = enumVar->Next((ULONG)count, rawChildren.get(), aNChildren);
++  if (FAILED(*hr)) {
++    *aChildren = nullptr;
++    *aNChildren = 0;
++    return;
++  }
++
++  *aChildren = static_cast<AccChildData*>(::CoTaskMemAlloc(
++    sizeof(AccChildData) * *aNChildren));
++  for (ULONG index = 0; index < *aNChildren; ++index) {
++    (*aChildren)[index] = {};
++    AccChildData& child = (*aChildren)[index];
++
++    MOZ_ASSERT(rawChildren[index].vt == VT_DISPATCH);
++    MOZ_ASSERT(rawChildren[index].pdispVal);
++    RefPtr<NEWEST_IA2_INTERFACE> childAcc;
++    *hr = rawChildren[index].pdispVal->QueryInterface(NEWEST_IA2_IID,
++      getter_AddRefs(childAcc));
++    rawChildren[index].pdispVal->Release();
++    MOZ_ASSERT(SUCCEEDED(*hr));
++    if (FAILED(*hr)) {
++      continue;
++    }
++
++    if (!SetChildDataForTextLeaf(childAcc, child)) {
++      // This isn't a text leaf. Marshal the accessible.
++      childAcc.forget(&child.mAccessible);
++      // We must wrap this accessible in an Interceptor.
++      ToWrappedObject(&child.mAccessible);
++    }
++  }
++
++  *hr = S_OK;
++}
++
++HRESULT
++HandlerProvider::get_AllChildren(AccChildData** aChildren,
++                                 ULONG* aNChildren)
++{
++  MOZ_ASSERT(mscom::IsCurrentThreadMTA());
++
++  HRESULT hr;
++  if (!mscom::InvokeOnMainThread("HandlerProvider::GetAllChildrenMainThread",
++                                 this,
++                                 &HandlerProvider::GetAllChildrenMainThread,
++                                 aChildren, aNChildren, &hr)) {
++    return E_FAIL;
++  }
++
++  return hr;
++}
++
+ } // namespace a11y
+ } // namespace mozilla
+ 
+diff --git a/accessible/ipc/win/HandlerProvider.h b/accessible/ipc/win/HandlerProvider.h
+--- a/accessible/ipc/win/HandlerProvider.h
++++ b/accessible/ipc/win/HandlerProvider.h
+@@ -59,16 +59,18 @@ public:
+   STDMETHODIMP Refresh(DynamicIA2Data* aOutData) override;
+   STDMETHODIMP get_AllTextInfo(BSTR* aText,
+                                IAccessibleHyperlink*** aHyperlinks,
+                                long* aNHyperlinks,
+                                IA2TextSegment** aAttribRuns,
+                                long* aNAttribRuns) override;
+   STDMETHODIMP get_RelationsInfo(IARelationData** aRelations,
+                                  long* aNRelations) override;
++  STDMETHODIMP get_AllChildren(AccChildData** aChildren,
++                               ULONG* aNChildren) override;
+ 
+ private:
+   ~HandlerProvider() = default;
+ 
+   void SetHandlerControlOnMainThread(DWORD aPid,
+                                      mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
+   void GetAndSerializePayload(const MutexAutoLock&,
+                               NotNull<mscom::IInterceptor*> aInterceptor);
+@@ -90,16 +92,18 @@ private:
+                                 IAccessibleHyperlink*** aHyperlinks,
+                                 long* aNHyperlinks,
+                                 IA2TextSegment** aAttribRuns,
+                                 long* aNAttribRuns,
+                                 HRESULT* result);
+   void GetRelationsInfoMainThread(IARelationData** aRelations,
+                                   long* aNRelations,
+                                   HRESULT* result);
++  void GetAllChildrenMainThread(AccChildData** aChildren, ULONG* aNChildren,
++                                HRESULT* result);
+ 
+   Atomic<uint32_t>                  mRefCnt;
+   Mutex                             mMutex; // Protects mSerializer
+   const IID                         mTargetUnkIid;
+   mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only
+   UniquePtr<mscom::StructToStream>  mSerializer;
+   RefPtr<IUnknown>                  mFastMarshalUnk;
+ };
+diff --git a/accessible/ipc/win/handler/HandlerData.idl b/accessible/ipc/win/handler/HandlerData.idl
+--- a/accessible/ipc/win/handler/HandlerData.idl
++++ b/accessible/ipc/win/handler/HandlerData.idl
+@@ -146,31 +146,47 @@ interface IHandlerControl : IUnknown
+ }
+ 
+ typedef struct _IARelationData 
+ {
+   BSTR mType;
+   long mNTargets;
+ } IARelationData;
+ 
++typedef struct _AccChildData
++{
++  NEWEST_IA2_INTERFACE* mAccessible;
++  BSTR mText;
++  long mTextRole;
++  long mTextId;
++  long mTextState;
++  long mTextLeft;
++  long mTextTop;
++  long mTextWidth;
++  long mTextHeight;
++} AccChildData;
++
+ [object,
+  uuid(IGECKOBACKCHANNEL_IID),
+  pointer_default(unique)]
+ interface IGeckoBackChannel : IUnknown
+ {
+   [propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl);
+   HRESULT Refresh([out] DynamicIA2Data* aOutData);
+   [propget] HRESULT AllTextInfo([out] BSTR* aText,
+     [out, size_is(,*aNHyperlinks)] IAccessibleHyperlink*** aHyperlinks,
+     [out] long* aNHyperlinks,
+     [out, size_is(,*aNAttribRuns)] IA2TextSegment** aAttribRuns,
+     [out] long* aNAttribRuns);
+   [propget] HRESULT RelationsInfo(
+     [out, size_is(,*aNRelations)] IARelationData** aRelations,
+     [out] long* aNRelations);
++  [propget] HRESULT AllChildren(
++    [out, size_is(,*aNChildren)] AccChildData** aChildren,
++    [out] ULONG* aNChildren);
+ }
+ 
+ [uuid(1e545f07-f108-4912-9471-546827a80983)]
+ library AccessibleHandlerTypeLib
+ {
+   /**
+    * This definition is required in order for the handler implementation to
+    * support IDispatch (aka Automation). This is used by interpreted language

+ 556 - 0
mozilla-release/patches/1431256-2-61a1.patch

@@ -0,0 +1,556 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1521644171 14400
+#      Wed Mar 21 10:56:11 2018 -0400
+# Node ID 580a1123de819a3798a53c9c14516d438fcb1046
+# Parent  fc4b465ae5c1d8e9910c3e5815e3f4cb2f083637
+Bug 1431256 part 2: AccessibleHandler: Implementation of IAccessible2 for text leaf accessibles using data provided in AccChildData. r=MarcoZ
+
+For text leaf accessibles, the HandlerProvider::AllChildren property provides text and other necessary information in an AccChildData struct, rather than providing the full accessible object.
+Therefore, we must provide a specific local implementation of IAccessible2 which answers queries based on the data provided in this struct.
+
+MozReview-Commit-ID: 8BYMF59EoTe
+
+diff --git a/accessible/ipc/win/handler/HandlerTextLeaf.cpp b/accessible/ipc/win/handler/HandlerTextLeaf.cpp
+new file mode 100644
+--- /dev/null
++++ b/accessible/ipc/win/handler/HandlerTextLeaf.cpp
+@@ -0,0 +1,402 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#if defined(MOZILLA_INTERNAL_API)
++#error This code is NOT for internal Gecko use!
++#endif // defined(MOZILLA_INTERNAL_API)
++
++#include "HandlerTextLeaf.h"
++#include "mozilla/Assertions.h"
++
++namespace mozilla {
++namespace a11y {
++
++HandlerTextLeaf::HandlerTextLeaf(IDispatch* aParent,
++                                 long aIndexInParent, HWND aHwnd,
++                                 AccChildData& aData)
++: mParent(aParent)
++, mIndexInParent(aIndexInParent)
++, mHwnd(aHwnd)
++, mData(aData)
++{
++  MOZ_ASSERT(aParent);
++}
++
++HandlerTextLeaf::~HandlerTextLeaf()
++{
++  if (mData.mText) {
++    ::SysFreeString(mData.mText);
++  }
++}
++
++IMPL_IUNKNOWN_QUERY_HEAD(HandlerTextLeaf)
++IMPL_IUNKNOWN_QUERY_IFACE(IDispatch)
++IMPL_IUNKNOWN_QUERY_IFACE(IAccessible)
++IMPL_IUNKNOWN_QUERY_IFACE(IAccessible2)
++IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
++IMPL_IUNKNOWN_QUERY_TAIL
++
++/*** IDispatch ***/
++
++HRESULT
++HandlerTextLeaf::GetTypeInfoCount(UINT *pctinfo)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
++                               LCID lcid, DISPID *rgDispId)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
++                        WORD wFlags, DISPPARAMS *pDispParams,
++                        VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
++                        UINT *puArgErr)
++{
++  return E_NOTIMPL;
++}
++
++/*** IAccessible ***/
++
++HRESULT
++HandlerTextLeaf::get_accParent(IDispatch **ppdispParent)
++{
++  if (!ppdispParent) {
++    return E_INVALIDARG;
++  }
++
++  RefPtr<IDispatch> parent(mParent);
++  parent.forget(ppdispParent);
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_accChildCount(long *pcountChildren)
++{
++  if (!pcountChildren) {
++    return E_INVALIDARG;
++  }
++
++  *pcountChildren = 0;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accName(VARIANT varChild, BSTR *pszName)
++{
++  if (varChild.lVal != CHILDID_SELF || !pszName) {
++    return E_INVALIDARG;
++  }
++
++  *pszName = CopyBSTR(mData.mText);
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_accValue(VARIANT varChild, BSTR *pszValue)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accDescription(VARIANT varChild, BSTR *pszDescription)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accRole(VARIANT varChild, VARIANT *pvarRole)
++{
++  if (varChild.lVal != CHILDID_SELF || !pvarRole) {
++    return E_INVALIDARG;
++  }
++
++  pvarRole->vt = VT_I4;
++  pvarRole->lVal = mData.mTextRole;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_accState(VARIANT varChild, VARIANT *pvarState)
++{
++  if (varChild.lVal != CHILDID_SELF || !pvarState) {
++    return E_INVALIDARG;
++  }
++
++  pvarState->vt = VT_I4;
++  pvarState->lVal = mData.mTextState;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_accHelp(VARIANT varChild, BSTR *pszHelp)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild,
++                                  long *pidTopic)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accKeyboardShortcut(VARIANT varChild,
++                                         BSTR *pszKeyboardShortcut)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accFocus(VARIANT *pvarChild)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accSelection(VARIANT *pvarChildren)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_accDefaultAction(VARIANT varChild,
++                                      BSTR *pszDefaultAction)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::accSelect(long flagsSelect, VARIANT varChild)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::accLocation(long *pxLeft, long *pyTop, long *pcxWidth,
++                             long *pcyHeight, VARIANT varChild)
++{
++  if (varChild.lVal != CHILDID_SELF || !pxLeft || !pyTop || !pcxWidth ||
++      !pcyHeight) {
++    return E_INVALIDARG;
++  }
++
++  *pxLeft = mData.mTextLeft;
++  *pyTop = mData.mTextTop;
++  *pcxWidth = mData.mTextWidth;
++  *pcyHeight = mData.mTextHeight;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::accNavigate(long navDir, VARIANT varStart,
++                             VARIANT *pvarEndUpAt)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::accHitTest( long xLeft, long yTop, VARIANT *pvarChild)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::accDoDefaultAction(VARIANT varChild)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::put_accName(VARIANT varChild, BSTR szName)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::put_accValue(VARIANT varChild, BSTR szValue)
++{
++  return E_NOTIMPL;
++}
++
++/*** IAccessible2 ***/
++
++HRESULT
++HandlerTextLeaf::get_nRelations(long* nRelations)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_relation(long relationIndex,
++                              IAccessibleRelation** relation)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_relations(long maxRelations,
++                               IAccessibleRelation** relations,
++                               long* nRelations)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::role(long* role)
++{
++  if (!role) {
++    return E_INVALIDARG;
++  }
++
++  *role = mData.mTextRole;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::scrollTo(IA2ScrollType scrollType)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::scrollToPoint(IA2CoordinateType coordinateType, long x,
++                               long y)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_groupPosition(long* groupLevel, long* similarItemsInGroup,
++                                   long* positionInGroup)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_states(AccessibleStates* states)
++{
++  if (!states) {
++    return E_INVALIDARG;
++  }
++
++  *states = 0;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_extendedRole(BSTR* extendedRole)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_localizedExtendedRole(BSTR* localizedExtendedRole)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_nExtendedStates(long* nExtendedStates)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_extendedStates(long maxExtendedStates,
++                                    BSTR** extendedStates,
++                                    long* nExtendedStates)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_localizedExtendedStates(long maxLocalizedExtendedStates,
++                                             BSTR** localizedExtendedStates,
++                                             long* nLocalizedExtendedStates)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_uniqueID(long* uniqueID)
++{
++  if (!uniqueID) {
++    return E_INVALIDARG;
++  }
++
++  *uniqueID = mData.mTextId;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_windowHandle(HWND* windowHandle)
++{
++  if (!windowHandle) {
++    return E_INVALIDARG;
++  }
++
++  *windowHandle = mHwnd;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_indexInParent(long* indexInParent)
++{
++  if (!indexInParent) {
++    return E_INVALIDARG;
++  }
++
++  *indexInParent = mIndexInParent;
++  return S_OK;
++}
++
++HRESULT
++HandlerTextLeaf::get_locale(IA2Locale* locale)
++{
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerTextLeaf::get_attributes(BSTR* attributes)
++{
++  return E_NOTIMPL;
++}
++
++/*** IServiceProvider ***/
++
++HRESULT
++HandlerTextLeaf::QueryService(REFGUID aServiceId, REFIID aIid,
++                              void** aOutInterface)
++{
++  if (aIid == IID_IAccessible2) {
++    RefPtr<IAccessible2> ia2(this);
++    ia2.forget(aOutInterface);
++    return S_OK;
++  }
++
++  return E_INVALIDARG;
++}
++
++} // namespace a11y
++} // namespace mozilla
+diff --git a/accessible/ipc/win/handler/HandlerTextLeaf.h b/accessible/ipc/win/handler/HandlerTextLeaf.h
+new file mode 100644
+--- /dev/null
++++ b/accessible/ipc/win/handler/HandlerTextLeaf.h
+@@ -0,0 +1,110 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#if defined(MOZILLA_INTERNAL_API)
++#error This code is NOT for internal Gecko use!
++#endif // defined(MOZILLA_INTERNAL_API)
++
++#ifndef mozilla_a11y_HandlerTextLeaf_h
++#define mozilla_a11y_HandlerTextLeaf_h
++
++#include "AccessibleHandler.h"
++#include "IUnknownImpl.h"
++#include "mozilla/RefPtr.h"
++
++namespace mozilla {
++namespace a11y {
++
++class HandlerTextLeaf final : public IAccessible2
++                              , public IServiceProvider
++{
++public:
++  explicit HandlerTextLeaf(IDispatch* aParent, long aIndexInParent,
++                           HWND aHwnd, AccChildData& aData);
++
++  DECL_IUNKNOWN
++
++  // IDispatch
++  STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) override;
++  STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override;
++  STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
++                             LCID lcid, DISPID *rgDispId) override;
++  STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
++                      DISPPARAMS *pDispParams, VARIANT *pVarResult,
++                      EXCEPINFO *pExcepInfo, UINT *puArgErr) override;
++
++  // IAccessible
++  STDMETHODIMP get_accParent(IDispatch **ppdispParent) override;
++  STDMETHODIMP get_accChildCount(long *pcountChildren) override;
++  STDMETHODIMP get_accChild(VARIANT varChild, IDispatch **ppdispChild) override;
++  STDMETHODIMP get_accName(VARIANT varChild, BSTR *pszName) override;
++  STDMETHODIMP get_accValue(VARIANT varChild, BSTR *pszValue) override;
++  STDMETHODIMP get_accDescription(VARIANT varChild, BSTR *pszDescription) override;
++  STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole) override;
++  STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState) override;
++  STDMETHODIMP get_accHelp(VARIANT varChild, BSTR *pszHelp) override;
++  STDMETHODIMP get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild,
++                                long *pidTopic) override;
++  STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild,
++                                       BSTR *pszKeyboardShortcut) override;
++  STDMETHODIMP get_accFocus(VARIANT *pvarChild) override;
++  STDMETHODIMP get_accSelection(VARIANT *pvarChildren) override;
++  STDMETHODIMP get_accDefaultAction(VARIANT varChild,
++                                    BSTR *pszDefaultAction) override;
++  STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild) override;
++  STDMETHODIMP accLocation(long *pxLeft, long *pyTop, long *pcxWidth,
++                           long *pcyHeight, VARIANT varChild) override;
++  STDMETHODIMP accNavigate(long navDir, VARIANT varStart,
++                           VARIANT *pvarEndUpAt) override;
++  STDMETHODIMP accHitTest( long xLeft, long yTop, VARIANT *pvarChild) override;
++  STDMETHODIMP accDoDefaultAction(VARIANT varChild) override;
++  STDMETHODIMP put_accName(VARIANT varChild, BSTR szName) override;
++  STDMETHODIMP put_accValue(VARIANT varChild, BSTR szValue) override;
++
++  // IAccessible2
++  STDMETHODIMP get_nRelations(long* nRelations) override;
++  STDMETHODIMP get_relation(long relationIndex,
++                            IAccessibleRelation** relation) override;
++  STDMETHODIMP get_relations(long maxRelations, IAccessibleRelation** relations,
++                             long* nRelations) override;
++  STDMETHODIMP role(long* role) override;
++  STDMETHODIMP scrollTo(IA2ScrollType scrollType) override;
++  STDMETHODIMP scrollToPoint(IA2CoordinateType coordinateType, long x,
++                             long y) override;
++  STDMETHODIMP get_groupPosition(long* groupLevel, long* similarItemsInGroup,
++                                 long* positionInGroup) override;
++  STDMETHODIMP get_states(AccessibleStates* states) override;
++  STDMETHODIMP get_extendedRole(BSTR* extendedRole) override;
++  STDMETHODIMP get_localizedExtendedRole(BSTR* localizedExtendedRole) override;
++  STDMETHODIMP get_nExtendedStates(long* nExtendedStates) override;
++  STDMETHODIMP get_extendedStates(long maxExtendedStates, BSTR** extendedStates,
++                                  long* nExtendedStates) override;
++  STDMETHODIMP get_localizedExtendedStates(long maxLocalizedExtendedStates,
++                                           BSTR** localizedExtendedStates,
++                                           long* nLocalizedExtendedStates) override;
++  STDMETHODIMP get_uniqueID(long* uniqueID) override;
++  STDMETHODIMP get_windowHandle(HWND* windowHandle) override;
++  STDMETHODIMP get_indexInParent(long* indexInParent) override;
++  STDMETHODIMP get_locale(IA2Locale* locale) override;
++  STDMETHODIMP get_attributes(BSTR* attributes) override;
++
++  // IServiceProvider
++  STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aIid,
++                            void** aOutInterface) override;
++
++private:
++  ~HandlerTextLeaf();
++
++  RefPtr<IDispatch> mParent;
++  long mIndexInParent;
++  HWND mHwnd;
++  AccChildData mData;
++};
++
++} // namespace a11y
++} // namespace mozilla
++
++#endif // mozilla_a11y_HandlerTextLeaf_h
+diff --git a/accessible/ipc/win/handler/moz.build b/accessible/ipc/win/handler/moz.build
+--- a/accessible/ipc/win/handler/moz.build
++++ b/accessible/ipc/win/handler/moz.build
+@@ -19,16 +19,17 @@ LOCAL_INCLUDES += [
+ SOURCES += [
+     '!dlldata.c',
+     '!HandlerData_c.c',
+     '!HandlerData_i.c',
+     '!HandlerData_p.c',
+     'AccessibleHandler.cpp',
+     'AccessibleHandlerControl.cpp',
+     'HandlerRelation.cpp',
++    'HandlerTextLeaf.cpp',
+ ]
+ 
+ GENERATED_FILES += [
+     'dlldata.c',
+     'HandlerData.h',
+     'HandlerData.tlb',
+     'HandlerData_c.c',
+     'HandlerData_i.c',

+ 326 - 0
mozilla-release/patches/1431256-3-61a1.patch

@@ -0,0 +1,326 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1521644625 14400
+#      Wed Mar 21 11:03:45 2018 -0400
+# Node ID 7e3ec61fa95274530ca48fba49e263811c9f3d2b
+# Parent  580a1123de819a3798a53c9c14516d438fcb1046
+Bug 1431256 part 3: AccessibleHandler: When a client requests children, fetch them optimally using a single cross-process call. r=MarcoZ
+
+This implements IEnumVARIANT locally using the new method provided by HandlerProvider.
+This avoids marshaling full objects for text leaf accessibles (instead using HandlerTextLeaf), which is much faster.
+It also avoids a pointless cross-process call to IEnumVARIANT::Reset (and possibly IEnumVARIANT::Clone).
+Finally, it caches children after the first query so that clients (such as UI Automation) which walk children one by one don't incur separate cross-process calls for every child.
+
+MozReview-Commit-ID: KUIXQoXxInQ
+
+diff --git a/accessible/ipc/win/handler/AccessibleHandler.cpp b/accessible/ipc/win/handler/AccessibleHandler.cpp
+--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
++++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
+@@ -7,16 +7,17 @@
+ #if defined(MOZILLA_INTERNAL_API)
+ #error This code is NOT for internal Gecko use!
+ #endif // defined(MOZILLA_INTERNAL_API)
+ 
+ #define INITGUID
+ 
+ #include "AccessibleHandler.h"
+ #include "AccessibleHandlerControl.h"
++#include "HandlerChildEnumerator.h"
+ #include "HandlerRelation.h"
+ 
+ #include "Factory.h"
+ #include "HandlerData.h"
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/a11y/HandlerDataCleanup.h"
+ #include "mozilla/mscom/Registration.h"
+ #include "mozilla/UniquePtr.h"
+@@ -401,16 +402,23 @@ AccessibleHandler::QueryHandlerInterface
+   }
+ 
+   if (aIid == IID_IProvideClassInfo) {
+     RefPtr<IProvideClassInfo> clsInfo(this);
+     clsInfo.forget(aOutInterface);
+     return S_OK;
+   }
+ 
++  if (aIid == IID_IEnumVARIANT && mCachedData.mGeckoBackChannel) {
++    RefPtr<IEnumVARIANT> childEnum(
++      new HandlerChildEnumerator(this, mCachedData.mGeckoBackChannel));
++    childEnum.forget(aOutInterface);
++    return S_OK;
++  }
++
+   return E_NOINTERFACE;
+ }
+ 
+ HRESULT
+ AccessibleHandler::ReadHandlerPayload(IStream* aStream, REFIID aIid)
+ {
+   if (!aStream) {
+     return E_INVALIDARG;
+diff --git a/accessible/ipc/win/handler/HandlerChildEnumerator.cpp b/accessible/ipc/win/handler/HandlerChildEnumerator.cpp
+new file mode 100644
+--- /dev/null
++++ b/accessible/ipc/win/handler/HandlerChildEnumerator.cpp
+@@ -0,0 +1,183 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#if defined(MOZILLA_INTERNAL_API)
++#error This code is NOT for internal Gecko use!
++#endif // defined(MOZILLA_INTERNAL_API)
++
++#include "HandlerChildEnumerator.h"
++#include "HandlerTextLeaf.h"
++#include "mozilla/Assertions.h"
++
++namespace mozilla {
++namespace a11y {
++
++HandlerChildEnumerator::HandlerChildEnumerator(AccessibleHandler* aHandler,
++    IGeckoBackChannel* aGeckoBackChannel)
++  : mHandler(aHandler)
++  , mGeckoBackChannel(aGeckoBackChannel)
++  , mChildCount(0)
++  , mNextChild(0)
++{
++  MOZ_ASSERT(aHandler);
++  MOZ_ASSERT(aGeckoBackChannel);
++}
++
++HandlerChildEnumerator::HandlerChildEnumerator(
++    const HandlerChildEnumerator& aEnumerator)
++  : mHandler(aEnumerator.mHandler)
++  , mGeckoBackChannel(aEnumerator.mGeckoBackChannel)
++  , mChildCount(aEnumerator.mChildCount)
++  , mNextChild(aEnumerator.mNextChild)
++{
++  if (mChildCount == 0) {
++    return;
++  }
++  mChildren = MakeUnique<VARIANT[]>(mChildCount);
++  CopyMemory(mChildren.get(), aEnumerator.mChildren.get(),
++             sizeof(VARIANT) * mChildCount);
++  for (ULONG index = 0; index < mChildCount; ++index) {
++    mChildren[index].pdispVal->AddRef();
++  }
++}
++
++HandlerChildEnumerator::~HandlerChildEnumerator()
++{
++  ClearCache();
++}
++
++void
++HandlerChildEnumerator::ClearCache()
++{
++  if (!mChildren) {
++    return;
++  }
++
++  for (ULONG index = 0; index < mChildCount; ++index) {
++    mChildren[index].pdispVal->Release();
++  }
++
++  mChildren = nullptr;
++  mChildCount = 0;
++}
++
++HRESULT
++HandlerChildEnumerator::MaybeCacheChildren()
++{
++  if (mChildren) {
++    // Already cached.
++    return S_OK;
++  }
++
++  AccChildData* children;
++  HRESULT hr = mGeckoBackChannel->get_AllChildren(&children, &mChildCount);
++  if (FAILED(hr)) {
++    mChildCount = 0;
++    ClearCache();
++    return hr;
++  }
++
++  HWND hwnd = nullptr;
++  hr = mHandler->get_windowHandle(&hwnd);
++  MOZ_ASSERT(SUCCEEDED(hr));
++
++  RefPtr<IDispatch> parent;
++  hr = mHandler->QueryInterface(IID_IDispatch, getter_AddRefs(parent));
++  MOZ_ASSERT(SUCCEEDED(hr));
++
++  mChildren = MakeUnique<VARIANT[]>(mChildCount);
++  for (ULONG index = 0; index < mChildCount; ++index) {
++    AccChildData& data = children[index];
++    VARIANT& child = mChildren[index];
++    if (data.mAccessible) {
++      RefPtr<IDispatch> disp;
++      hr = data.mAccessible->QueryInterface(IID_IDispatch,
++                                            getter_AddRefs(disp));
++      data.mAccessible->Release();
++      MOZ_ASSERT(SUCCEEDED(hr));
++      if (FAILED(hr)) {
++        child.vt = VT_EMPTY;
++        continue;
++      }
++      child.vt = VT_DISPATCH;
++      disp.forget(&child.pdispVal);
++    } else {
++      // Text leaf.
++      RefPtr<IDispatch> leaf(
++        new HandlerTextLeaf(parent, index, hwnd, data));
++      child.vt = VT_DISPATCH;
++      leaf.forget(&child.pdispVal);
++    }
++  }
++
++  ::CoTaskMemFree(children);
++  return S_OK;
++}
++
++IMPL_IUNKNOWN_QUERY_HEAD(HandlerChildEnumerator)
++IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT)
++IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler)
++
++/*** IEnumVARIANT ***/
++
++HRESULT
++HandlerChildEnumerator::Clone(IEnumVARIANT** aPpEnum)
++{
++  RefPtr<HandlerChildEnumerator> newEnum(new HandlerChildEnumerator(*this));
++  newEnum.forget(aPpEnum);
++  return S_OK;
++}
++
++HRESULT
++HandlerChildEnumerator::Next(ULONG aCelt, VARIANT* aRgVar,
++                             ULONG* aPCeltFetched)
++{
++  if (!aRgVar || aCelt == 0) {
++    return E_INVALIDARG;
++  }
++
++  HRESULT hr = MaybeCacheChildren();
++  if (FAILED(hr)) {
++    return hr;
++  }
++
++  for (ULONG index = 0; index < aCelt; ++index) {
++    if (mNextChild >= mChildCount) {
++      // Less elements remaining than were requested.
++      if (aPCeltFetched) {
++        *aPCeltFetched = index;
++      }
++      return S_FALSE;
++    }
++    aRgVar[index] = mChildren[mNextChild];
++    aRgVar[index].pdispVal->AddRef();
++    ++mNextChild;
++  }
++  *aPCeltFetched = aCelt;
++  return S_OK;
++}
++
++HRESULT
++HandlerChildEnumerator::Reset()
++{
++  mNextChild = 0;
++  ClearCache();
++  return S_OK;
++}
++
++HRESULT
++HandlerChildEnumerator::Skip(ULONG aCelt)
++{
++  mNextChild += aCelt;
++  if (mNextChild > mChildCount) {
++    // Less elements remaining than the client requested to skip.
++    return S_FALSE;
++  }
++  return S_OK;
++}
++
++} // namespace a11y
++} // namespace mozilla
+diff --git a/accessible/ipc/win/handler/HandlerChildEnumerator.h b/accessible/ipc/win/handler/HandlerChildEnumerator.h
+new file mode 100644
+--- /dev/null
++++ b/accessible/ipc/win/handler/HandlerChildEnumerator.h
+@@ -0,0 +1,52 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#if defined(MOZILLA_INTERNAL_API)
++#error This code is NOT for internal Gecko use!
++#endif // defined(MOZILLA_INTERNAL_API)
++
++#ifndef mozilla_a11y_HandlerChildEnumerator_h
++#define mozilla_a11y_HandlerChildEnumerator_h
++
++#include "AccessibleHandler.h"
++#include "IUnknownImpl.h"
++#include "mozilla/RefPtr.h"
++
++namespace mozilla {
++namespace a11y {
++
++class HandlerChildEnumerator final : public IEnumVARIANT
++{
++public:
++  explicit HandlerChildEnumerator(AccessibleHandler* aHandler,
++                                  IGeckoBackChannel* aGeckoBackChannel);
++
++  DECL_IUNKNOWN
++
++  // IEnumVARIANT
++  STDMETHODIMP Clone(IEnumVARIANT** aPpEnum) override;
++  STDMETHODIMP Next(ULONG aCelt, VARIANT* aRgVar,
++                    ULONG* aPCeltFetched) override;
++  STDMETHODIMP Reset() override;
++  STDMETHODIMP Skip(ULONG aCelt) override;
++
++private:
++  explicit HandlerChildEnumerator(const HandlerChildEnumerator& aEnumerator);
++  ~HandlerChildEnumerator();
++  void ClearCache();
++  HRESULT MaybeCacheChildren();
++
++  RefPtr<AccessibleHandler> mHandler;
++  RefPtr<IGeckoBackChannel> mGeckoBackChannel;
++  UniquePtr<VARIANT[]> mChildren;
++  ULONG mChildCount;
++  ULONG mNextChild;
++};
++
++} // namespace a11y
++} // namespace mozilla
++
++#endif // mozilla_a11y_HandlerChildEnumerator_h
+diff --git a/accessible/ipc/win/handler/moz.build b/accessible/ipc/win/handler/moz.build
+--- a/accessible/ipc/win/handler/moz.build
++++ b/accessible/ipc/win/handler/moz.build
+@@ -18,16 +18,17 @@ LOCAL_INCLUDES += [
+ 
+ SOURCES += [
+     '!dlldata.c',
+     '!HandlerData_c.c',
+     '!HandlerData_i.c',
+     '!HandlerData_p.c',
+     'AccessibleHandler.cpp',
+     'AccessibleHandlerControl.cpp',
++    'HandlerChildEnumerator.cpp',
+     'HandlerRelation.cpp',
+     'HandlerTextLeaf.cpp',
+ ]
+ 
+ GENERATED_FILES += [
+     'dlldata.c',
+     'HandlerData.h',
+     'HandlerData.tlb',

+ 140 - 0
mozilla-release/patches/1431256-4-61a1.patch

@@ -0,0 +1,140 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1516326042 -36000
+#      Fri Jan 19 11:40:42 2018 +1000
+# Node ID 8f68422b3307dc910732da8f07ceb9accbc74873
+# Parent  7e3ec61fa95274530ca48fba49e263811c9f3d2b
+Bug 1431256 part 4: Remove IEnumVARIANT from the AccessibleHandler payload. r=MarcoZ
+
+Now that the handler implements IEnumVARIANT itself (and uses our own internal method to retrieve the children), caching this remote interface is pointless.
+
+MozReview-Commit-ID: FyagiEcHMP2
+
+diff --git a/accessible/ipc/win/HandlerProvider.cpp b/accessible/ipc/win/HandlerProvider.cpp
+--- a/accessible/ipc/win/HandlerProvider.cpp
++++ b/accessible/ipc/win/HandlerProvider.cpp
+@@ -214,22 +214,16 @@ HandlerProvider::BuildStaticIA2Data(
+     // IA2 should always be present, so something has
+     // gone very wrong if this fails.
+     aOutData->mIA2 = nullptr;
+     return;
+   }
+ 
+   // Some of these interfaces aren't present on all accessibles,
+   // so it's not a failure if these interfaces can't be fetched.
+-  hr = aInterceptor->GetInterceptorForIID(IID_IEnumVARIANT,
+-                                          (void**)&aOutData->mIEnumVARIANT);
+-  if (FAILED(hr)) {
+-    aOutData->mIEnumVARIANT = nullptr;
+-  }
+-
+   hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHypertext2,
+                                           (void**)&aOutData->mIAHypertext);
+   if (FAILED(hr)) {
+     aOutData->mIAHypertext = nullptr;
+   }
+ 
+   hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHyperlink,
+                                           (void**)&aOutData->mIAHyperlink);
+diff --git a/accessible/ipc/win/handler/AccessibleHandler.cpp b/accessible/ipc/win/handler/AccessibleHandler.cpp
+--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
++++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
+@@ -353,19 +353,17 @@ AccessibleHandler::QueryHandlerInterface
+     return S_OK;
+   }
+ 
+   if (HasPayload()) {
+     // The proxy manager caches interfaces marshaled in the payload
+     // and returns them on QI without a cross-process call.
+     // However, it doesn't know about interfaces which don't exist.
+     // We can determine this from the payload.
+-    if ((aIid == IID_IEnumVARIANT &&
+-         !mCachedData.mStaticData.mIEnumVARIANT) ||
+-        ((aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext ||
++    if (((aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext ||
+           aIid == IID_IAccessibleHypertext2) &&
+          !mCachedData.mStaticData.mIAHypertext) ||
+         ((aIid == IID_IAccessibleAction || aIid == IID_IAccessibleHyperlink) &&
+          !mCachedData.mStaticData.mIAHyperlink) ||
+         (aIid == IID_IAccessibleTable &&
+          !mCachedData.mStaticData.mIATable) ||
+         (aIid == IID_IAccessibleTable2 &&
+          !mCachedData.mStaticData.mIATable2) ||
+@@ -403,16 +401,19 @@ AccessibleHandler::QueryHandlerInterface
+ 
+   if (aIid == IID_IProvideClassInfo) {
+     RefPtr<IProvideClassInfo> clsInfo(this);
+     clsInfo.forget(aOutInterface);
+     return S_OK;
+   }
+ 
+   if (aIid == IID_IEnumVARIANT && mCachedData.mGeckoBackChannel) {
++    if (&mCachedData.mDynamicData.mChildCount == 0) {
++      return E_NOINTERFACE;
++    }
+     RefPtr<IEnumVARIANT> childEnum(
+       new HandlerChildEnumerator(this, mCachedData.mGeckoBackChannel));
+     childEnum.forget(aOutInterface);
+     return S_OK;
+   }
+ 
+   return E_NOINTERFACE;
+ }
+diff --git a/accessible/ipc/win/handler/HandlerData.idl b/accessible/ipc/win/handler/HandlerData.idl
+--- a/accessible/ipc/win/handler/HandlerData.idl
++++ b/accessible/ipc/win/handler/HandlerData.idl
+@@ -2,31 +2,29 @@
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "mozilla-config.h"
+ #include "AccessibleHandler.h"
+ 
+-import "oaidl.idl";
+ import "ocidl.idl";
+ import "ServProv.idl";
+ 
+ import "Accessible2_3.idl";
+ import "AccessibleHypertext2.idl";
+ import "AccessibleHyperlink.idl";
+ import "AccessibleTable.idl";
+ import "AccessibleTable2.idl";
+ import "AccessibleTableCell.idl";
+ 
+ typedef struct _StaticIA2Data
+ {
+   NEWEST_IA2_INTERFACE* mIA2;
+-  IEnumVARIANT* mIEnumVARIANT;
+   IAccessibleHypertext2* mIAHypertext;
+   IAccessibleHyperlink* mIAHyperlink;
+   IAccessibleTable* mIATable;
+   IAccessibleTable2* mIATable2;
+   IAccessibleTableCell* mIATableCell;
+ } StaticIA2Data;
+ 
+ typedef struct _DynamicIA2Data
+diff --git a/accessible/ipc/win/handler/HandlerDataCleanup.h b/accessible/ipc/win/handler/HandlerDataCleanup.h
+--- a/accessible/ipc/win/handler/HandlerDataCleanup.h
++++ b/accessible/ipc/win/handler/HandlerDataCleanup.h
+@@ -18,19 +18,16 @@ ReleaseStaticIA2DataInterfaces(StaticIA2
+ {
+   // Only interfaces of the proxied object wrapped by this handler should be
+   // released here, never other objects!
+   // For example, if StaticIA2Data were to include accParent in future,
+   // that must not be released here.
+   if (aData.mIA2) {
+     aData.mIA2->Release();
+   }
+-  if (aData.mIEnumVARIANT) {
+-    aData.mIEnumVARIANT->Release();
+-  }
+   if (aData.mIAHypertext) {
+     aData.mIAHypertext->Release();
+   }
+   if (aData.mIAHyperlink) {
+     aData.mIAHyperlink->Release();
+   }
+   if (aData.mIATable) {
+     aData.mIATable->Release();

+ 34 - 0
mozilla-release/patches/1431256-5-61a1.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1521755854 14400
+#      Thu Mar 22 17:57:34 2018 -0400
+# Node ID aa06fb8316c272ecf735aecb59673544d6423631
+# Parent  610872970d04f4b63e28f9764a321460b658fb26
+Bug 1431256 correction: AccessibleHandler: Really return E_NOINTERFACE for IEnumVARIANT if there are no children. r=MarcoZ
+
+A typo meant we were checking the address of mChildCount, not the value.
+
+MozReview-Commit-ID: 7Hit3FBy9pr
+
+diff --git a/accessible/ipc/win/handler/AccessibleHandler.cpp b/accessible/ipc/win/handler/AccessibleHandler.cpp
+--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
++++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
+@@ -401,17 +401,17 @@ AccessibleHandler::QueryHandlerInterface
+ 
+   if (aIid == IID_IProvideClassInfo) {
+     RefPtr<IProvideClassInfo> clsInfo(this);
+     clsInfo.forget(aOutInterface);
+     return S_OK;
+   }
+ 
+   if (aIid == IID_IEnumVARIANT && mCachedData.mGeckoBackChannel) {
+-    if (&mCachedData.mDynamicData.mChildCount == 0) {
++    if (mCachedData.mDynamicData.mChildCount == 0) {
+       return E_NOINTERFACE;
+     }
+     RefPtr<IEnumVARIANT> childEnum(
+       new HandlerChildEnumerator(this, mCachedData.mGeckoBackChannel));
+     childEnum.forget(aOutInterface);
+     return S_OK;
+   }
+ 

+ 213 - 0
mozilla-release/patches/1431264-1-60a1.patch

@@ -0,0 +1,213 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1517526977 -36000
+#      Fri Feb 02 09:16:17 2018 +1000
+# Node ID b11b10cebf25ad658c44aa432c05fe10665b1d38
+# Parent  9ffe77b5c891cecc4f39d411be9d33d108d2b433
+Bug 1431264 part 1: Accessible HandlerProvider: Implement a method to retrieve info for all relations in a single call. r=MarcoZ
+
+IAccessible2::relations allows you to fetch IAccessibleRelation objects for all relations.
+However, you must first call IAccessible2::nRelations to get the number of relations.
+In addition, getting the type and number of targets for each relation requires additional calls.
+This new method allows all of this to be retrieved in a single cross-process call.
+
+MozReview-Commit-ID: 3zEIjxEyMP5
+
+diff --git a/accessible/ipc/win/HandlerProvider.cpp b/accessible/ipc/win/HandlerProvider.cpp
+--- a/accessible/ipc/win/HandlerProvider.cpp
++++ b/accessible/ipc/win/HandlerProvider.cpp
+@@ -5,16 +5,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #define INITGUID
+ 
+ #include "mozilla/a11y/HandlerProvider.h"
+ 
+ #include "Accessible2_3.h"
+ #include "AccessibleDocument.h"
++#include "AccessibleRelation.h"
+ #include "AccessibleTable.h"
+ #include "AccessibleTable2.h"
+ #include "AccessibleTableCell.h"
+ #include "HandlerData.h"
+ #include "HandlerData_i.c"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/a11y/AccessibleWrap.h"
+ #include "mozilla/a11y/HandlerDataCleanup.h"
+@@ -23,16 +24,17 @@
+ #include "mozilla/mscom/AgileReference.h"
+ #include "mozilla/mscom/FastMarshaler.h"
+ #include "mozilla/mscom/Interceptor.h"
+ #include "mozilla/mscom/MainThreadHandoff.h"
+ #include "mozilla/mscom/MainThreadInvoker.h"
+ #include "mozilla/mscom/Ptr.h"
+ #include "mozilla/mscom/StructStream.h"
+ #include "mozilla/mscom/Utils.h"
++#include "mozilla/UniquePtr.h"
+ #include "nsThreadUtils.h"
+ #include "nsTArray.h"
+ 
+ #include <memory.h>
+ 
+ namespace mozilla {
+ namespace a11y {
+ 
+@@ -655,11 +657,75 @@ HandlerProvider::get_AllTextInfo(BSTR* a
+                                  aText, aHyperlinks, aNHyperlinks,
+                                  aAttribRuns, aNAttribRuns, &hr)) {
+     return E_FAIL;
+   }
+ 
+   return hr;
+ }
+ 
++void
++HandlerProvider::GetRelationsInfoMainThread(IARelationData** aRelations,
++                                            long* aNRelations,
++                                            HRESULT* hr)
++{
++  MOZ_ASSERT(aRelations);
++  MOZ_ASSERT(aNRelations);
++  MOZ_ASSERT(NS_IsMainThread());
++  MOZ_ASSERT(mTargetUnk);
++
++  RefPtr<NEWEST_IA2_INTERFACE> acc;
++  *hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID,
++    getter_AddRefs(acc));
++  if (FAILED(*hr)) {
++    return;
++  }
++
++  *hr = acc->get_nRelations(aNRelations);
++  if (FAILED(*hr)) {
++    return;
++  }
++
++  auto rawRels = MakeUnique<IAccessibleRelation*[]>(*aNRelations);
++  *hr = acc->get_relations(*aNRelations, rawRels.get(), aNRelations);
++  if (FAILED(*hr)) {
++    return;
++  }
++
++  *aRelations = static_cast<IARelationData*>(::CoTaskMemAlloc(
++    sizeof(IARelationData) * *aNRelations));
++  for (long index = 0; index < *aNRelations; ++index) {
++    IAccessibleRelation* rawRel = rawRels[index];
++    IARelationData& relData = (*aRelations)[index];
++    *hr = rawRel->get_relationType(&relData.mType);
++    if (FAILED(*hr)) {
++      relData.mType = nullptr;
++    }
++    *hr = rawRel->get_nTargets(&relData.mNTargets);
++    if (FAILED(*hr)) {
++      relData.mNTargets = -1;
++    }
++    rawRel->Release();
++  }
++
++  *hr = S_OK;
++}
++
++HRESULT
++HandlerProvider::get_RelationsInfo(IARelationData** aRelations,
++                                   long* aNRelations)
++{
++  MOZ_ASSERT(mscom::IsCurrentThreadMTA());
++
++  HRESULT hr;
++  if (!mscom::InvokeOnMainThread("HandlerProvider::GetRelationsInfoMainThread",
++                                 this,
++                                 &HandlerProvider::GetRelationsInfoMainThread,
++                                 aRelations, aNRelations, &hr)) {
++    return E_FAIL;
++  }
++
++  return hr;
++}
++
+ } // namespace a11y
+ } // namespace mozilla
+ 
+diff --git a/accessible/ipc/win/HandlerProvider.h b/accessible/ipc/win/HandlerProvider.h
+--- a/accessible/ipc/win/HandlerProvider.h
++++ b/accessible/ipc/win/HandlerProvider.h
+@@ -55,16 +55,18 @@ public:
+   // IGeckoBackChannel
+   STDMETHODIMP put_HandlerControl(long aPid, IHandlerControl* aCtrl) override;
+   STDMETHODIMP Refresh(DynamicIA2Data* aOutData) override;
+   STDMETHODIMP get_AllTextInfo(BSTR* aText,
+                                IAccessibleHyperlink*** aHyperlinks,
+                                long* aNHyperlinks,
+                                IA2TextSegment** aAttribRuns,
+                                long* aNAttribRuns) override;
++  STDMETHODIMP get_RelationsInfo(IARelationData** aRelations,
++                                 long* aNRelations) override;
+ 
+ private:
+   ~HandlerProvider() = default;
+ 
+   void SetHandlerControlOnMainThread(DWORD aPid,
+                                      mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
+   void GetAndSerializePayload(const MutexAutoLock&,
+                               NotNull<mscom::IInterceptor*> aInterceptor);
+@@ -83,16 +85,19 @@ private:
+   // This is intended for objects returned from method calls on the main thread.
+   template<typename Interface> HRESULT ToWrappedObject(Interface** aObj);
+   void GetAllTextInfoMainThread(BSTR* aText,
+                                 IAccessibleHyperlink*** aHyperlinks,
+                                 long* aNHyperlinks,
+                                 IA2TextSegment** aAttribRuns,
+                                 long* aNAttribRuns,
+                                 HRESULT* result);
++  void GetRelationsInfoMainThread(IARelationData** aRelations,
++                                  long* aNRelations,
++                                  HRESULT* result);
+ 
+   Atomic<uint32_t>                  mRefCnt;
+   Mutex                             mMutex; // Protects mSerializer
+   const IID                         mTargetUnkIid;
+   mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only
+   UniquePtr<mscom::StructToStream>  mSerializer;
+   RefPtr<IUnknown>                  mFastMarshalUnk;
+ };
+diff --git a/accessible/ipc/win/handler/HandlerData.idl b/accessible/ipc/win/handler/HandlerData.idl
+--- a/accessible/ipc/win/handler/HandlerData.idl
++++ b/accessible/ipc/win/handler/HandlerData.idl
+@@ -140,28 +140,37 @@ interface HandlerData
+ interface IHandlerControl : IUnknown
+ {
+   HRESULT Invalidate();
+   HRESULT OnTextChange([in] long aHwnd, [in] long aIA2UniqueId,
+                        [in] VARIANT_BOOL aIsInsert,
+                        [in] IA2TextSegment* aText);
+ }
+ 
++typedef struct _IARelationData 
++{
++  BSTR mType;
++  long mNTargets;
++} IARelationData;
++
+ [object,
+  uuid(IGECKOBACKCHANNEL_IID),
+  pointer_default(unique)]
+ interface IGeckoBackChannel : IUnknown
+ {
+   [propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl);
+   HRESULT Refresh([out] DynamicIA2Data* aOutData);
+   [propget] HRESULT AllTextInfo([out] BSTR* aText,
+     [out, size_is(,*aNHyperlinks)] IAccessibleHyperlink*** aHyperlinks,
+     [out] long* aNHyperlinks,
+     [out, size_is(,*aNAttribRuns)] IA2TextSegment** aAttribRuns,
+     [out] long* aNAttribRuns);
++  [propget] HRESULT RelationsInfo(
++    [out, size_is(,*aNRelations)] IARelationData** aRelations,
++    [out] long* aNRelations);
+ }
+ 
+ [uuid(1e545f07-f108-4912-9471-546827a80983)]
+ library AccessibleHandlerTypeLib
+ {
+   /**
+    * This definition is required in order for the handler implementation to
+    * support IDispatch (aka Automation). This is used by interpreted language

+ 242 - 0
mozilla-release/patches/1431264-2-60a1.patch

@@ -0,0 +1,242 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1517528116 -36000
+#      Fri Feb 02 09:35:16 2018 +1000
+# Node ID 85acda76be9cfe6b5ad611baf016e3d459d7331b
+# Parent  b11b10cebf25ad658c44aa432c05fe10665b1d38
+Bug 1431264 part 2: AccessibleHandler: Local implementation of IAccessibleRelation using data provided in IARelationData. r=MarcoZ
+
+The HandlerProvider::RelationsInfo method provides the type and number of targets for each relation in an IARelationData struct.
+This local implementaition of IAccessibleRelation is constructed with an IARelationData struct and serves a single relation.
+It uses the data from the struct to answer queries, except for actual targets.
+For targets, it makes a remote call to IA2_2::relationTargetsOfType to answer the query.
+We use relationTargetsOfType instead of IARelation::targets because marshaling so many IARelation pointers is a major bottleneck.
+
+MozReview-Commit-ID: Dva00FhoSbx
+
+diff --git a/accessible/ipc/win/handler/HandlerRelation.cpp b/accessible/ipc/win/handler/HandlerRelation.cpp
+new file mode 100644
+--- /dev/null
++++ b/accessible/ipc/win/handler/HandlerRelation.cpp
+@@ -0,0 +1,148 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#if defined(MOZILLA_INTERNAL_API)
++#error This code is NOT for internal Gecko use!
++#endif // defined(MOZILLA_INTERNAL_API)
++
++#include "HandlerRelation.h"
++#include "mozilla/Assertions.h"
++
++#include "AccessibleRelation_i.c"
++
++namespace mozilla {
++namespace a11y {
++
++HandlerRelation::HandlerRelation(AccessibleHandler* aHandler,
++                                 IARelationData& aData)
++  : mHandler(aHandler)
++  , mData(aData)
++  , mTargets(nullptr)
++{
++  // This instance now owns any pointers, so ensure no one else can
++  // manipulate them.
++  aData.mType = nullptr;
++}
++
++HandlerRelation::~HandlerRelation()
++{
++  if (mData.mType) {
++    ::SysFreeString(mData.mType);
++  }
++
++  if (mTargets) {
++    for (long index = 0; index < mData.mNTargets; ++index) {
++      mTargets[index]->Release();
++    }
++    ::CoTaskMemFree(mTargets);
++    mTargets = nullptr;
++  }
++}
++
++HRESULT
++HandlerRelation::GetTargets()
++{
++  if (mTargets) {
++    // Already cached.
++    return S_OK;
++  }
++
++  // Marshaling all of the IAccessibleRelation objects across processes is
++  // slow, and the client probably only wants targets for a few of them.
++  // Therefore, we just use IAccessible2_2::relationTargetsOfType, passing
++  // the type we have cached. This is a bit inefficient because Gecko has
++  // to look up the relation twice, but it's significantly faster than
++  // marshaling the relation objects regardless.
++  return mHandler->get_relationTargetsOfType(mData.mType, 0,
++                                             &mTargets, &mData.mNTargets);
++}
++
++IMPL_IUNKNOWN1(HandlerRelation, IAccessibleRelation)
++
++/*** IAccessibleRelation ***/
++
++HRESULT
++HandlerRelation::get_relationType(BSTR* aType)
++{
++  if (!aType) {
++    return E_INVALIDARG;
++  }
++  if (!mData.mType) {
++    return E_FAIL;
++  }
++  *aType = CopyBSTR(mData.mType);
++  return S_OK;
++}
++
++HRESULT
++HandlerRelation::get_localizedRelationType(BSTR* aLocalizedType)
++{
++  // This is not implemented as per ia2AccessibleRelation.
++  return E_NOTIMPL;
++}
++
++HRESULT
++HandlerRelation::get_nTargets(long* aNTargets)
++{
++  if (!aNTargets) {
++    return E_INVALIDARG;
++  }
++  if (mData.mNTargets == -1) {
++    return E_FAIL;
++  }
++  *aNTargets = mData.mNTargets;
++  return S_OK;
++}
++
++HRESULT
++HandlerRelation::get_target(long aIndex, IUnknown** aTarget)
++{
++  if (!aTarget) {
++    return E_INVALIDARG;
++  }
++
++  HRESULT hr = GetTargets();
++  if (FAILED(hr)) {
++    return hr;
++  }
++  if ( aIndex >= mData.mNTargets) {
++    return E_INVALIDARG;
++  }
++
++  *aTarget = mTargets[aIndex];
++  (*aTarget)->AddRef();
++  return S_OK;
++}
++
++HRESULT
++HandlerRelation::get_targets(long aMaxTargets, IUnknown** aTargets,
++                             long* aNTargets)
++{
++  if (aMaxTargets == 0 || !aTargets || !aNTargets) {
++    return E_INVALIDARG;
++  }
++
++  HRESULT hr = GetTargets();
++  if (FAILED(hr)) {
++    return hr;
++  }
++
++  if (mData.mNTargets > aMaxTargets) {
++    // Don't give back more targets than were requested.
++    *aNTargets = aMaxTargets;
++  } else {
++    *aNTargets = mData.mNTargets;
++  }
++
++  for (long index = 0; index < *aNTargets; ++index) {
++    aTargets[index] = mTargets[index];
++    aTargets[index]->AddRef();
++  }
++  return S_OK;
++}
++
++} // namespace a11y
++} // namespace mozilla
+diff --git a/accessible/ipc/win/handler/HandlerRelation.h b/accessible/ipc/win/handler/HandlerRelation.h
+new file mode 100644
+--- /dev/null
++++ b/accessible/ipc/win/handler/HandlerRelation.h
+@@ -0,0 +1,47 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#if defined(MOZILLA_INTERNAL_API)
++#error This code is NOT for internal Gecko use!
++#endif // defined(MOZILLA_INTERNAL_API)
++
++#ifndef mozilla_a11y_HandlerRelation_h
++#define mozilla_a11y_HandlerRelation_h
++
++#include "AccessibleHandler.h"
++#include "IUnknownImpl.h"
++#include "mozilla/RefPtr.h"
++
++namespace mozilla {
++namespace a11y {
++
++class HandlerRelation final : public IAccessibleRelation
++{
++public:
++  explicit HandlerRelation(AccessibleHandler* aHandler, IARelationData& aData);
++
++  DECL_IUNKNOWN
++
++  // IAccessibleRelation
++  STDMETHODIMP get_relationType(BSTR* aType) override;
++  STDMETHODIMP get_localizedRelationType(BSTR* aLocalizedType) override;
++  STDMETHODIMP get_nTargets(long* aNTargets) override;
++  STDMETHODIMP get_target(long aIndex, IUnknown** aTarget) override;
++  STDMETHODIMP get_targets(long aMaxTargets, IUnknown** aTargets,
++                           long *aNTargets) override;
++
++private:
++  virtual ~HandlerRelation();
++  HRESULT GetTargets();
++  RefPtr<AccessibleHandler> mHandler;
++  IARelationData mData;
++  IUnknown** mTargets;
++};
++
++} // namespace a11y
++} // namespace mozilla
++
++#endif // mozilla_a11y_HandlerRelation_h
+diff --git a/accessible/ipc/win/handler/moz.build b/accessible/ipc/win/handler/moz.build
+--- a/accessible/ipc/win/handler/moz.build
++++ b/accessible/ipc/win/handler/moz.build
+@@ -18,16 +18,17 @@ LOCAL_INCLUDES += [
+ 
+ SOURCES += [
+     '!dlldata.c',
+     '!HandlerData_c.c',
+     '!HandlerData_i.c',
+     '!HandlerData_p.c',
+     'AccessibleHandler.cpp',
+     'AccessibleHandlerControl.cpp',
++    'HandlerRelation.cpp',
+ ]
+ 
+ GENERATED_FILES += [
+     'dlldata.c',
+     'HandlerData.h',
+     'HandlerData.tlb',
+     'HandlerData_c.c',
+     'HandlerData_i.c',

+ 273 - 0
mozilla-release/patches/1431264-3-60a1.patch

@@ -0,0 +1,273 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1517528331 -36000
+#      Fri Feb 02 09:38:51 2018 +1000
+# Node ID 7fe5e2760a88dcfc14d640b4aa5a95e1da4cc0a1
+# Parent  85acda76be9cfe6b5ad611baf016e3d459d7331b
+Bug 1431264 part 3: AccessibleHandler: If a client wants to query all relations, fetch as much info as possible in a single cross-process call. r=MarcoZ
+
+If a client calls IAccessible2::nRelations, it's likely that it will next call IAccessible2::relations to query each relation.
+Furthermore, it's likely the client will call relationType and nTargets on each relation.
+Therefore, fetch all of this info when nRelations is called.
+The number of relations is immediately returned to the client.
+The rest of the info is cached and returned to the client when the appropriate methods are called.
+The info is only cached for one call; i.e. after the client calls relations once, the cache is dropped.
+This makes memory management simpler and lowers the risk of cache invalidation problems.
+
+MozReview-Commit-ID: IBoJbu42osG
+
+diff --git a/accessible/ipc/win/handler/AccessibleHandler.cpp b/accessible/ipc/win/handler/AccessibleHandler.cpp
+--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
++++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
+@@ -7,16 +7,17 @@
+ #if defined(MOZILLA_INTERNAL_API)
+ #error This code is NOT for internal Gecko use!
+ #endif // defined(MOZILLA_INTERNAL_API)
+ 
+ #define INITGUID
+ 
+ #include "AccessibleHandler.h"
+ #include "AccessibleHandlerControl.h"
++#include "HandlerRelation.h"
+ 
+ #include "Factory.h"
+ #include "HandlerData.h"
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/a11y/HandlerDataCleanup.h"
+ #include "mozilla/mscom/Registration.h"
+ #include "mozilla/UniquePtr.h"
+ 
+@@ -73,16 +74,18 @@ AccessibleHandler::AccessibleHandler(IUn
+   , mIATableCellPassThru(nullptr)
+   , mIAHypertextPassThru(nullptr)
+   , mCachedData()
+   , mCacheGen(0)
+   , mCachedHyperlinks(nullptr)
+   , mCachedNHyperlinks(-1)
+   , mCachedTextAttribRuns(nullptr)
+   , mCachedNTextAttribRuns(-1)
++  , mCachedRelations(nullptr)
++  , mCachedNRelations(-1)
+ {
+   RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetOrCreateSingleton());
+   MOZ_ASSERT(ctl);
+   if (!ctl) {
+     if (aResult) {
+       *aResult = E_UNEXPECTED;
+     }
+     return;
+@@ -94,16 +97,17 @@ AccessibleHandler::AccessibleHandler(IUn
+ AccessibleHandler::~AccessibleHandler()
+ {
+   // No need to zero memory, since we're being destroyed anyway.
+   CleanupDynamicIA2Data(mCachedData.mDynamicData, false);
+   if (mCachedData.mGeckoBackChannel) {
+     mCachedData.mGeckoBackChannel->Release();
+   }
+   ClearTextCache();
++  ClearRelationCache();
+ }
+ 
+ HRESULT
+ AccessibleHandler::ResolveIA2()
+ {
+   if (mIA2PassThru) {
+     return S_OK;
+   }
+@@ -250,16 +254,50 @@ AccessibleHandler::ClearTextCache()
+     // This array is internal to us, so we must always free it.
+     ::CoTaskMemFree(mCachedTextAttribRuns);
+     mCachedTextAttribRuns = nullptr;
+     mCachedNTextAttribRuns = -1;
+   }
+ }
+ 
+ HRESULT
++AccessibleHandler::GetRelationsInfo()
++{
++  MOZ_ASSERT(mCachedData.mGeckoBackChannel);
++
++  ClearRelationCache();
++
++  return mCachedData.mGeckoBackChannel->get_RelationsInfo(&mCachedRelations,
++    &mCachedNRelations);
++}
++
++void
++AccessibleHandler::ClearRelationCache()
++{
++  if (mCachedNRelations == -1) {
++    // No cache; nothing to do.
++    return;
++  }
++
++  // We cached relations, but the client never retrieved them.
++  if (mCachedRelations) {
++    for (long index = 0; index < mCachedNRelations; ++index) {
++      IARelationData& relData = mCachedRelations[index];
++      if (relData.mType) {
++        ::SysFreeString(relData.mType);
++      }
++    }
++    // This array is internal to us, so we must always free it.
++    ::CoTaskMemFree(mCachedRelations);
++    mCachedRelations = nullptr;
++  }
++  mCachedNRelations = -1;
++}
++
++HRESULT
+ AccessibleHandler::ResolveIDispatch()
+ {
+   if (mDispatch) {
+     return S_OK;
+   }
+ 
+   HRESULT hr;
+ 
+@@ -557,22 +595,16 @@ AccessibleHandler::Invoke(DISPID dispIdM
+   if (FAILED(hr)) {
+     return hr;
+   }
+ 
+   return mDispatch->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams,
+                            pVarResult, pExcepInfo, puArgErr);
+ }
+ 
+-inline static BSTR
+-CopyBSTR(BSTR aSrc)
+-{
+-  return ::SysAllocStringLen(aSrc, ::SysStringLen(aSrc));
+-}
+-
+ #define BEGIN_CACHE_ACCESS \
+   { \
+     HRESULT hr; \
+     if (FAILED(hr = MaybeUpdateCachedData())) { \
+       return hr; \
+     } \
+   }
+ 
+@@ -905,17 +937,33 @@ AccessibleHandler::put_accValue(VARIANT 
+   return E_NOTIMPL;
+ }
+ 
+ /*** IAccessible2 ***/
+ 
+ HRESULT
+ AccessibleHandler::get_nRelations(long* nRelations)
+ {
+-  HRESULT hr = ResolveIA2();
++  if (!nRelations) {
++    return E_INVALIDARG;
++  }
++
++  HRESULT hr;
++  if (mCachedData.mGeckoBackChannel) {
++    // If the caller wants nRelations, they will almost certainly want the
++    // actual relations too.
++    hr = GetRelationsInfo();
++    if (SUCCEEDED(hr)) {
++      *nRelations = mCachedNRelations;
++      return S_OK;
++    }
++    // We fall back to a normal call if this fails.
++  }
++
++  hr = ResolveIA2();
+   if (FAILED(hr)) {
+     return hr;
+   }
+   return mIA2PassThru->get_nRelations(nRelations);
+ }
+ 
+ HRESULT
+ AccessibleHandler::get_relation(long relationIndex,
+@@ -928,16 +976,38 @@ AccessibleHandler::get_relation(long rel
+   return mIA2PassThru->get_relation(relationIndex, relation);
+ }
+ 
+ HRESULT
+ AccessibleHandler::get_relations(long maxRelations,
+                                  IAccessibleRelation** relations,
+                                  long* nRelations)
+ {
++  if (maxRelations == 0 || !relations || !nRelations) {
++    return E_INVALIDARG;
++  }
++
++  // We currently only support retrieval of *all* cached relations at once.
++  if (mCachedNRelations != -1 && maxRelations >= mCachedNRelations) {
++    for (long index = 0; index < mCachedNRelations; ++index) {
++      IARelationData& relData = mCachedRelations[index];
++      RefPtr<IAccessibleRelation> hrel(new HandlerRelation(this, relData));
++      hrel.forget(&relations[index]);
++    }
++    *nRelations = mCachedNRelations;
++    // Clean up the cache, since we only cache for one call.
++    // We don't use ClearRelationCache here because that scans for data to free
++    // in the array and we don't we need that. The HandlerRelation instances
++    // will handle freeing of the data.
++    ::CoTaskMemFree(mCachedRelations);
++    mCachedRelations = nullptr;
++    mCachedNRelations = -1;
++    return S_OK;
++  }
++
+   HRESULT hr = ResolveIA2();
+   if (FAILED(hr)) {
+     return hr;
+   }
+   return mIA2PassThru->get_relations(maxRelations, relations, nRelations);
+ }
+ 
+ HRESULT
+diff --git a/accessible/ipc/win/handler/AccessibleHandler.h b/accessible/ipc/win/handler/AccessibleHandler.h
+--- a/accessible/ipc/win/handler/AccessibleHandler.h
++++ b/accessible/ipc/win/handler/AccessibleHandler.h
+@@ -249,16 +249,18 @@ private:
+   HRESULT ResolveIA2();
+   HRESULT ResolveIDispatch();
+   HRESULT ResolveIAHyperlink();
+   HRESULT ResolveIAHypertext();
+   HRESULT ResolveIATableCell();
+   HRESULT MaybeUpdateCachedData();
+   HRESULT GetAllTextInfo(BSTR* aText);
+   void ClearTextCache();
++  HRESULT GetRelationsInfo();
++  void ClearRelationCache();
+ 
+   RefPtr<IUnknown>                  mDispatchUnk;
+   /**
+    * Handlers aggregate their proxies. This means that their proxies delegate
+    * their IUnknown implementation to us.
+    *
+    * mDispatchUnk and the result of Handler::GetProxy() are both strong
+    * references to the aggregated objects. OTOH, any interfaces that are QI'd
+@@ -283,18 +285,26 @@ private:
+   IAccessibleHypertext2*             mIAHypertextPassThru; // weak
+   IA2Payload                        mCachedData;
+   UniquePtr<mscom::StructToStream>  mSerializer;
+   uint32_t                          mCacheGen;
+   IAccessibleHyperlink**            mCachedHyperlinks;
+   long                              mCachedNHyperlinks;
+   IA2TextSegment*                   mCachedTextAttribRuns;
+   long                              mCachedNTextAttribRuns;
++  IARelationData*                   mCachedRelations;
++  long                              mCachedNRelations;
+ };
+ 
++inline static BSTR
++CopyBSTR(BSTR aSrc)
++{
++  return ::SysAllocStringLen(aSrc, ::SysStringLen(aSrc));
++}
++
+ } // namespace a11y
+ } // namespace mozilla
+ 
+ #endif // !defined(MOZILLA_INTERNAL_API)
+ 
+ #endif // defined(__midl)
+ 
+ #endif // mozilla_a11y_AccessibleHandler_h

+ 219 - 0
mozilla-release/patches/1432513-60a1.patch

@@ -0,0 +1,219 @@
+# HG changeset patch
+# User Joanmarie Diggs <jdiggs@igalia.com>
+# Date 1516693020 -7200
+# Node ID 04401448f881b9fe3ec6a5e8558aae22166313a4
+# Parent  a09e41857cf3c9ce6c444222be725f2ba864c9cc
+Bug 1432513 - Implement ARIA Graphics roles r=surkov
+Recognize the graphics-document, graphics-object, and graphics-symbol
+ARIA roles, mapping them to the DOCUMENT, GROUPING, and GRAPHIC internal
+roles respectively.
+
+diff --git a/accessible/base/ARIAMap.cpp b/accessible/base/ARIAMap.cpp
+--- a/accessible/base/ARIAMap.cpp
++++ b/accessible/base/ARIAMap.cpp
+@@ -612,16 +612,47 @@ static const nsRoleMapEntry sWAIRoleMaps
+     roles::FORM,
+     kUseMapRole,
+     eNoValue,
+     eNoAction,
+     eNoLiveAttr,
+     eLandmark,
+     kNoReqStates
+   },
++  { // graphics-document
++    &nsGkAtoms::graphicsDocument,
++    roles::DOCUMENT,
++    kUseMapRole,
++    eNoValue,
++    eNoAction,
++    eNoLiveAttr,
++    kGenericAccType,
++    kNoReqStates,
++    eReadonlyUntilEditable
++  },
++  { // graphics-object
++    &nsGkAtoms::graphicsObject,
++    roles::GROUPING,
++    kUseMapRole,
++    eNoValue,
++    eNoAction,
++    eNoLiveAttr,
++    kGenericAccType,
++    kNoReqStates
++  },
++  { // graphics-symbol
++    &nsGkAtoms::graphicsSymbol,
++    roles::GRAPHIC,
++    kUseMapRole,
++    eNoValue,
++    eNoAction,
++    eNoLiveAttr,
++    kGenericAccType,
++    kNoReqStates
++  },
+   { // grid
+     &nsGkAtoms::grid,
+     roles::TABLE,
+     kUseMapRole,
+     eNoValue,
+     eNoAction,
+     eNoLiveAttr,
+     eSelect | eTable,
+diff --git a/accessible/tests/mochitest/attributes/a11y.ini b/accessible/tests/mochitest/attributes/a11y.ini
+--- a/accessible/tests/mochitest/attributes/a11y.ini
++++ b/accessible/tests/mochitest/attributes/a11y.ini
+@@ -1,13 +1,14 @@
+ [DEFAULT]
+ support-files =
+   !/accessible/tests/mochitest/*.js
+ 
+ [test_dpub_aria_xml-roles.html]
++[test_graphics_aria_xml-roles.html]
+ [test_obj.html]
+ [test_obj_css.html]
+ [test_obj_css.xul]
+ [test_obj_group.html]
+ [test_obj_group.xul]
+ [test_obj_group_tree.xul]
+ [test_tag.html]
+ [test_xml-roles.html]
+diff --git a/accessible/tests/mochitest/attributes/test_graphics_aria_xml-roles.html b/accessible/tests/mochitest/attributes/test_graphics_aria_xml-roles.html
+new file mode 100644
+--- /dev/null
++++ b/accessible/tests/mochitest/attributes/test_graphics_aria_xml-roles.html
+@@ -0,0 +1,49 @@
++<!DOCTYPE html>
++<html>
++<head>
++  <title>XML roles tests</title>
++  <link rel="stylesheet" type="text/css"
++        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
++
++  <script type="application/javascript"
++          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
++
++  <script type="application/javascript"
++          src="../common.js"></script>
++  <script type="application/javascript"
++          src="../role.js"></script>
++  <script type="application/javascript"
++          src="../attributes.js"></script>
++
++  <script type="application/javascript">
++
++    function doTest() {
++      // Graphics ARIA roles should be exposed via the xml-roles object attribute.
++      let graphics_attrs = [
++        "graphics-document",
++        "graphics-object",
++        "graphics-symbol"
++      ];
++      for (let attr of graphics_attrs) {
++        testAttrs(attr, {"xml-roles": attr}, true);
++      }
++      SimpleTest.finish();
++    }
++    SimpleTest.waitForExplicitFinish();
++    addA11yLoadEvent(doTest);
++  </script>
++</head>
++<body>
++  <a target="_blank"
++     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1432513"
++     title="implement ARIA Graphics roles">
++    Bug 1432513
++  </a>
++  <p id="display"></p>
++  <div id="content" style="display: none"></div>
++  <pre id="test"></pre>
++  <div id="graphics-document" role="graphics-document">document</div>
++  <div id="graphics-object" role="graphics-object">object</div>
++  <div id="graphics-symbol" role="graphics-symbol">symbol</div>
++</body>
++</html>
+diff --git a/accessible/tests/mochitest/role/a11y.ini b/accessible/tests/mochitest/role/a11y.ini
+--- a/accessible/tests/mochitest/role/a11y.ini
++++ b/accessible/tests/mochitest/role/a11y.ini
+@@ -3,9 +3,10 @@ support-files =
+   !/accessible/tests/mochitest/*.js
+   !/accessible/tests/mochitest/moz.png
+ 
+ [test_aria.html]
+ [test_aria.xul]
+ [test_dpub_aria.html]
+ [test_general.html]
+ [test_general.xul]
++[test_graphics_aria.html]
+ [test_svg.html]
+diff --git a/accessible/tests/mochitest/role/test_graphics_aria.html b/accessible/tests/mochitest/role/test_graphics_aria.html
+new file mode 100644
+--- /dev/null
++++ b/accessible/tests/mochitest/role/test_graphics_aria.html
+@@ -0,0 +1,43 @@
++<!DOCTYPE html>
++<html>
++<head>
++  <title>Test Graphics ARIA roles</title>
++
++  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
++
++  <script type="application/javascript"
++          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
++
++  <script type="application/javascript"
++          src="../common.js"></script>
++  <script type="application/javascript"
++          src="../role.js"></script>
++
++  <script type="application/javascript">
++
++    function doTest() {
++      // Graphics ARIA role map.
++      testRole("graphics-document", ROLE_DOCUMENT);
++      testRole("graphics-object", ROLE_GROUPING);
++      testRole("graphics-symbol", ROLE_GRAPHIC);
++      SimpleTest.finish();
++    }
++
++    SimpleTest.waitForExplicitFinish();
++    addA11yLoadEvent(doTest);
++  </script>
++</head>
++<body>
++  <a target="_blank"
++     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1432513"
++     title="implement ARIA Graphics roles">
++    Bug 1432513
++  </a>
++  <p id="display"></p>
++  <div id="content" style="display: none"></div>
++  <pre id="test"></pre>
++  <div id="graphics-document" role="graphics-document">document</div>
++  <div id="graphics-object" role="graphics-object">object</div>
++  <div id="graphics-symbol" role="graphics-symbol">symbol</div>
++</body>
++</html>
+diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
+--- a/dom/base/nsGkAtomList.h
++++ b/dom/base/nsGkAtomList.h
+@@ -498,16 +498,19 @@ GK_ATOM(from, "from")
+ GK_ATOM(fullscreenchange, "fullscreenchange")
+ GK_ATOM(fullscreenerror, "fullscreenerror")
+ GK_ATOM(functionAvailable, "function-available")
+ GK_ATOM(freshProcess, "freshProcess")
+ GK_ATOM(generateId, "generate-id")
+ GK_ATOM(getter, "getter")
+ GK_ATOM(glyphchar, "glyphchar")
+ GK_ATOM(glyphid, "glyphid")
++GK_ATOM(graphicsDocument, "graphics-document")
++GK_ATOM(graphicsObject, "graphics-object")
++GK_ATOM(graphicsSymbol, "graphics-symbol")
+ GK_ATOM(grid, "grid")
+ GK_ATOM(grippy, "grippy")
+ GK_ATOM(group, "group")
+ GK_ATOM(groupingSeparator, "grouping-separator")
+ GK_ATOM(groupingSize, "grouping-size")
+ GK_ATOM(grow, "grow")
+ GK_ATOM(gutter, "gutter")
+ GK_ATOM(h1, "h1")
+

+ 325 - 0
mozilla-release/patches/1433891-60a1.patch

@@ -0,0 +1,325 @@
+# HG changeset patch
+# User Joanmarie Diggs <jdiggs@igalia.com>
+# Date 1517911980 -7200
+# Node ID 1564fec091b4cccc4b2fd652132e8c9dcdbbdb91
+# Parent  96333b8e8e2586295b11a05ec9eae868f47957c4
+Bug 1433891 - ARIA documents should be easily distinguishable from native ones r=marcoz
+Gecko has two document roles: roles::DOCUMENT_FRAME and roles::DOCUMENT.
+However, the former was not being used at all; the latter was being used
+for both ARIA documents and for the native document container. We can
+therefore fix this issue by repurposing the unused internal role:
+
+* Rename the role from roles::DOCUMENT_FRAME to roles::NON_NATIVE_DOCUMENT,
+  and add clarification to the doc strings in Role.h
+* Ensure load events are still emitted for ARIA documents (bug 759833)
+* Update the ARIA-document mochitests to reflect the above changes
+* Change the ATK role mapping for roles::DOCUMENT (the native container)
+  from ATK_ROLE_DOCUMENT_FRAME TO ATK_ROLE_DOCUMENT_WEB.
+* On IAccessible2, map roles::NON_NATIVE_DOCUMENT to ROLE_SYSTEM_DOCUMENT.
+  This should cause there to be no change in behavior for that platform.
+* On macOS map roles::NON_NATIVE_DOCUMENT to NSAccessibilityGroupRole
+  with a subrole of AXDocument.
+
+diff --git a/accessible/base/ARIAMap.cpp b/accessible/base/ARIAMap.cpp
+--- a/accessible/base/ARIAMap.cpp
++++ b/accessible/base/ARIAMap.cpp
+@@ -573,17 +573,17 @@ static const nsRoleMapEntry sWAIRoleMaps
+     eNoValue,
+     eNoAction,
+     eNoLiveAttr,
+     eLandmark,
+     kNoReqStates
+   },
+   { // document
+     &nsGkAtoms::document,
+-    roles::DOCUMENT,
++    roles::NON_NATIVE_DOCUMENT,
+     kUseMapRole,
+     eNoValue,
+     eNoAction,
+     eNoLiveAttr,
+     kGenericAccType,
+     kNoReqStates,
+     eReadonlyUntilEditable
+   },
+@@ -614,17 +614,17 @@ static const nsRoleMapEntry sWAIRoleMaps
+     eNoValue,
+     eNoAction,
+     eNoLiveAttr,
+     eLandmark,
+     kNoReqStates
+   },
+   { // graphics-document
+     &nsGkAtoms::graphicsDocument,
+-    roles::DOCUMENT,
++    roles::NON_NATIVE_DOCUMENT,
+     kUseMapRole,
+     eNoValue,
+     eNoAction,
+     eNoLiveAttr,
+     kGenericAccType,
+     kNoReqStates,
+     eReadonlyUntilEditable
+   },
+diff --git a/accessible/base/Role.h b/accessible/base/Role.h
+--- a/accessible/base/Role.h
++++ b/accessible/base/Role.h
+@@ -106,17 +106,17 @@ enum Role {
+   /**
+    * Represents a main window for an application. It is used for
+    * role="application". Also refer to APP_ROOT
+    */
+   APPLICATION = 14,
+ 
+   /**
+    * Represents a document window. A document window is always contained within
+-   * an application window. It is used for role="document".
++   * an application window. For role="document", see NON_NATIVE_DOCUMENT.
+    */
+   DOCUMENT = 15,
+ 
+   /**
+    * Represents a pane within a frame or document window. Users can navigate
+    * between panes and within the contents of the current pane, but cannot
+    * navigate between items in different panes. Thus, panes represent a level
+    * of grouping lower than frame windows or documents, but above individual
+@@ -638,23 +638,22 @@ enum Role {
+   ENTRY = 102,
+ 
+   /**
+    * A caption describing another object.
+    */
+   CAPTION = 103,
+ 
+   /**
+-   * A visual frame or container which contains a view of document content.
+-   * Document frames may occur within another Document instance, in which case
+-   * the second document may be said to be embedded in the containing instance.
+-   * HTML frames are often DOCUMENT_FRAME. Either this object, or a
+-   * singleton descendant, should implement the Document interface.
++   * An element containing content that assistive technology users may want to
++   * browse in a reading mode, rather than a focus/interactive/application mode.
++   * This role is used for role="document". For the container which holds the
++   * content of a web page, see DOCUMENT.
+    */
+-  DOCUMENT_FRAME = 104,
++  NON_NATIVE_DOCUMENT = 104,
+ 
+   /**
+    * Heading.
+    */
+   HEADING = 105,
+ 
+   /**
+    * An object representing a page of document content.  It is used in documents
+diff --git a/accessible/base/RoleMap.h b/accessible/base/RoleMap.h
+--- a/accessible/base/RoleMap.h
++++ b/accessible/base/RoleMap.h
+@@ -124,17 +124,17 @@ ROLE(APPLICATION,
+      ATK_ROLE_EMBEDDED,
+      NSAccessibilityGroupRole,  //Unused on OS X. the system will take care of this.
+      ROLE_SYSTEM_APPLICATION,
+      ROLE_SYSTEM_APPLICATION,
+      eNoNameRule)
+ 
+ ROLE(DOCUMENT,
+      "document",
+-     ATK_ROLE_DOCUMENT_FRAME,
++     ATK_ROLE_DOCUMENT_WEB,
+      @"AXWebArea",
+      ROLE_SYSTEM_DOCUMENT,
+      ROLE_SYSTEM_DOCUMENT,
+      eNoNameRule)
+ 
+ /**
+  *  msaa comment:
+  *   We used to map to ROLE_SYSTEM_PANE, but JAWS would
+@@ -844,22 +844,22 @@ ROLE(ENTRY,
+ ROLE(CAPTION,
+      "caption",
+      ATK_ROLE_CAPTION,
+      NSAccessibilityStaticTextRole,
+      USE_ROLE_STRING,
+      IA2_ROLE_CAPTION,
+      eNameFromSubtreeIfReqRule)
+ 
+-ROLE(DOCUMENT_FRAME,
+-     "document frame",
++ROLE(NON_NATIVE_DOCUMENT,
++     "non-native document",
+      ATK_ROLE_DOCUMENT_FRAME,
+-     NSAccessibilityScrollAreaRole,
++     NSAccessibilityGroupRole,
+      USE_ROLE_STRING,
+-     IA2_ROLE_UNKNOWN,
++     ROLE_SYSTEM_DOCUMENT,
+      eNoNameRule)
+ 
+ ROLE(HEADING,
+      "heading",
+      ATK_ROLE_HEADING,
+      @"AXHeading",
+      USE_ROLE_STRING,
+      IA2_ROLE_HEADING,
+diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp
+--- a/accessible/generic/DocAccessible.cpp
++++ b/accessible/generic/DocAccessible.cpp
+@@ -2346,17 +2346,17 @@ DocAccessible::CacheChildrenInSubtree(Ac
+   // Fire events for ARIA elements.
+   if (!aRoot->HasARIARole()) {
+     return;
+   }
+ 
+   // XXX: we should delay document load complete event if the ARIA document
+   // has aria-busy.
+   roles::Role role = aRoot->ARIARole();
+-  if (!aRoot->IsDoc() && (role == roles::DIALOG || role == roles::DOCUMENT)) {
++  if (!aRoot->IsDoc() && (role == roles::DIALOG || role == roles::NON_NATIVE_DOCUMENT)) {
+     FireDelayedEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, aRoot);
+   }
+ }
+ 
+ void
+ DocAccessible::UncacheChildrenInSubtree(Accessible* aRoot)
+ {
+   aRoot->mStateFlags |= eIsNotInDocument;
+diff --git a/accessible/interfaces/nsIAccessibleRole.idl b/accessible/interfaces/nsIAccessibleRole.idl
+--- a/accessible/interfaces/nsIAccessibleRole.idl
++++ b/accessible/interfaces/nsIAccessibleRole.idl
+@@ -99,17 +99,17 @@ interface nsIAccessibleRole : nsISupport
+   /**
+    * Represents a main window for an application. It is used for
+    * role="application". Also refer to ROLE_APP_ROOT
+    */
+   const unsigned long ROLE_APPLICATION = 14;
+ 
+   /**
+    * Represents a document window. A document window is always contained within
+-   * an application window. It is used for role="document".
++   * an application window. For role="document", see NON_NATIVE_DOCUMENT.
+    */
+   const unsigned long ROLE_DOCUMENT = 15;
+ 
+   /**
+    * Represents a pane within a frame or document window. Users can navigate
+    * between panes and within the contents of the current pane, but cannot
+    * navigate between items in different panes. Thus, panes represent a level
+    * of grouping lower than frame windows or documents, but above individual
+@@ -632,23 +632,22 @@ interface nsIAccessibleRole : nsISupport
+   const unsigned long ROLE_ENTRY = 102;
+ 
+   /**
+    * A caption describing another object.
+    */
+   const unsigned long ROLE_CAPTION = 103;
+ 
+   /**
+-   * A visual frame or container which contains a view of document content.
+-   * Document frames may occur within another Document instance, in which case
+-   * the second document may be said to be embedded in the containing instance.
+-   * HTML frames are often ROLE_DOCUMENT_FRAME. Either this object, or a
+-   * singleton descendant, should implement the Document interface.
++   * An element containing content that assistive technology users may want to
++   * browse in a reading mode, rather than a focus/interactive/application mode.
++   * This role is used for role="document". For the container which holds the
++   * content of a web page, see ROLE_DOCUMENT.
+    */
+-  const unsigned long ROLE_DOCUMENT_FRAME = 104;
++  const unsigned long ROLE_NON_NATIVE_DOCUMENT = 104;
+ 
+   /**
+    * Heading.
+    */
+   const unsigned long ROLE_HEADING = 105;
+ 
+   /**
+    * An object representing a page of document content.  It is used in documents
+diff --git a/accessible/mac/mozAccessible.mm b/accessible/mac/mozAccessible.mm
+--- a/accessible/mac/mozAccessible.mm
++++ b/accessible/mac/mozAccessible.mm
+@@ -912,16 +912,19 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
+       return @"AXDocumentNote";
+ 
+     case roles::OUTLINEITEM:
+       return @"AXOutlineRow";
+ 
+     case roles::ARTICLE:
+       return @"AXDocumentArticle";
+ 
++    case roles::NON_NATIVE_DOCUMENT:
++      return @"AXDocument";
++
+     // macOS added an AXSubrole value to distinguish generic AXGroup objects
+     // from those which are AXGroups as a result of an explicit ARIA role,
+     // such as the non-landmark, non-listitem text containers in DPub ARIA.
+     case roles::FOOTNOTE:
+     case roles::SECTION:
+       if (roleAtom)
+         return @"AXApplicationGroup";
+       break;
+diff --git a/accessible/tests/mochitest/role.js b/accessible/tests/mochitest/role.js
+--- a/accessible/tests/mochitest/role.js
++++ b/accessible/tests/mochitest/role.js
+@@ -80,16 +80,17 @@ const ROLE_MATHML_STACK_GROUP = nsIAcces
+ const ROLE_MATHML_STACK_ROW = nsIAccessibleRole.ROLE_MATHML_STACK_ROW;
+ const ROLE_MATHML_STACK_CARRIES = nsIAccessibleRole.ROLE_MATHML_STACK_CARRIES;
+ const ROLE_MATHML_STACK_CARRY = nsIAccessibleRole.ROLE_MATHML_STACK_CARRY;
+ const ROLE_MATHML_STACK_LINE = nsIAccessibleRole.ROLE_MATHML_STACK_LINE;
+ const ROLE_MENUBAR = nsIAccessibleRole.ROLE_MENUBAR;
+ const ROLE_MENUITEM = nsIAccessibleRole.ROLE_MENUITEM;
+ const ROLE_MENUPOPUP = nsIAccessibleRole.ROLE_MENUPOPUP;
+ const ROLE_NAVIGATION = nsIAccessibleRole.ROLE_NAVIGATION;
++const ROLE_NON_NATIVE_DOCUMENT = nsIAccessibleRole.ROLE_NON_NATIVE_DOCUMENT;
+ const ROLE_NOTHING = nsIAccessibleRole.ROLE_NOTHING;
+ const ROLE_NOTE = nsIAccessibleRole.ROLE_NOTE;
+ const ROLE_OPTION = nsIAccessibleRole.ROLE_OPTION;
+ const ROLE_OUTLINE = nsIAccessibleRole.ROLE_OUTLINE;
+ const ROLE_OUTLINEITEM = nsIAccessibleRole.ROLE_OUTLINEITEM;
+ const ROLE_PAGETAB = nsIAccessibleRole.ROLE_PAGETAB;
+ const ROLE_PAGETABLIST = nsIAccessibleRole.ROLE_PAGETABLIST;
+ const ROLE_PANE = nsIAccessibleRole.ROLE_PANE;
+diff --git a/accessible/tests/mochitest/role/test_aria.html b/accessible/tests/mochitest/role/test_aria.html
+--- a/accessible/tests/mochitest/role/test_aria.html
++++ b/accessible/tests/mochitest/role/test_aria.html
+@@ -22,17 +22,17 @@
+       testRole("aria_application", ROLE_APPLICATION);
+       testRole("aria_article", ROLE_ARTICLE);
+       testRole("aria_button", ROLE_PUSHBUTTON);
+       testRole("aria_checkbox", ROLE_CHECKBUTTON);
+       testRole("aria_columnheader", ROLE_COLUMNHEADER);
+       testRole("aria_combobox", ROLE_EDITCOMBOBOX);
+       testRole("aria_dialog", ROLE_DIALOG);
+       testRole("aria_directory", ROLE_LIST);
+-      testRole("aria_document", ROLE_DOCUMENT);
++      testRole("aria_document", ROLE_NON_NATIVE_DOCUMENT);
+       testRole("aria_form", ROLE_FORM);
+       testRole("aria_feed", ROLE_GROUPING);
+       testRole("aria_figure", ROLE_FIGURE);
+       testRole("aria_grid", ROLE_TABLE);
+       testRole("aria_gridcell", ROLE_GRID_CELL);
+       testRole("aria_group", ROLE_GROUPING);
+       testRole("aria_heading", ROLE_HEADING);
+       testRole("aria_img", ROLE_GRAPHIC);
+diff --git a/accessible/tests/mochitest/role/test_graphics_aria.html b/accessible/tests/mochitest/role/test_graphics_aria.html
+--- a/accessible/tests/mochitest/role/test_graphics_aria.html
++++ b/accessible/tests/mochitest/role/test_graphics_aria.html
+@@ -12,17 +12,17 @@
+           src="../common.js"></script>
+   <script type="application/javascript"
+           src="../role.js"></script>
+ 
+   <script type="application/javascript">
+ 
+     function doTest() {
+       // Graphics ARIA role map.
+-      testRole("graphics-document", ROLE_DOCUMENT);
++      testRole("graphics-document", ROLE_NON_NATIVE_DOCUMENT);
+       testRole("graphics-object", ROLE_GROUPING);
+       testRole("graphics-symbol", ROLE_GRAPHIC);
+       SimpleTest.finish();
+     }
+ 
+     SimpleTest.waitForExplicitFinish();
+     addA11yLoadEvent(doTest);
+   </script>
+

+ 89 - 0
mozilla-release/patches/1442196-60a1.patch

@@ -0,0 +1,89 @@
+# HG changeset patch
+# User Marco Zehe <mzehe@mozilla.com>
+# Date 1520249855 -3600
+# Node ID 916d91f23f895a441ffe375ff245d4c62a4bb41a
+# Parent  518c959486b0aac7200055d75b5d2175cbb28d6c
+Bug 1442196 - Expose an XML role of 'form' on a form element if it has an accessible name, r=surkov
+
+MozReview-Commit-ID: 8vhHcWyg2
+
+diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp
+--- a/accessible/generic/HyperTextAccessible.cpp
++++ b/accessible/generic/HyperTextAccessible.cpp
+@@ -1149,16 +1149,23 @@ HyperTextAccessible::LandmarkRole() cons
+ 
+   // Only return xml-roles "region" if the section has an accessible name.
+   if (mContent->IsHTMLElement(nsGkAtoms::section)) {
+     nsAutoString name;
+     const_cast<HyperTextAccessible*>(this)->Name(name);
+     return name.IsEmpty() ? nullptr : nsGkAtoms::region;
+   }
+ 
++  // Only return xml-roles "form" if the form has an accessible name.
++  if (mContent->IsHTMLElement(nsGkAtoms::form)) {
++    nsAutoString name;
++    const_cast<HyperTextAccessible*>(this)->Name(name);
++    return name.IsEmpty() ? nullptr : nsGkAtoms::form;
++  }
++
+   return nullptr;
+ }
+ 
+ int32_t
+ HyperTextAccessible::OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType)
+ {
+   nsIFrame* hyperFrame = GetFrame();
+   if (!hyperFrame)
+diff --git a/accessible/tests/mochitest/elm/test_HTMLSpec.html b/accessible/tests/mochitest/elm/test_HTMLSpec.html
+--- a/accessible/tests/mochitest/elm/test_HTMLSpec.html
++++ b/accessible/tests/mochitest/elm/test_HTMLSpec.html
+@@ -538,20 +538,29 @@
+       testElm("footer_in_fieldset", obj);
+       testElm("footer_in_figure", obj);
+       testElm("footer_in_td", obj);
+ 
+       // ////////////////////////////////////////////////////////////////////////
+       // HTML:form
+ 
+       obj = {
+-        role: ROLE_FORM
++        role: ROLE_FORM,
++        absentAttributes: { "xml-roles": "form" }
+       };
+       testElm("form", obj);
+ 
++      // HTML:form with an accessible name
++
++      obj = {
++        role: ROLE_FORM,
++        attributes: { "xml-roles": "form" }
++      };
++      testElm("named_form", obj);
++
+       // ////////////////////////////////////////////////////////////////////////
+       // // HTML:frameset, HTML:frame and HTML:iframe
+ 
+       obj = {
+         INTERNAL_FRAME: [ { // HTML:iframe
+           DOCUMENT: [ {
+             INTERNAL_FRAME: [ { // HTML:frame
+               DOCUMENT: [ { role: ROLE_TEXT_LEAF} ]
+@@ -1544,16 +1553,17 @@
+   <figure>
+     <footer id="footer_in_figure">Some copyright info</footer>
+   </figure>
+   <table><tr><td>
+     <footer id="footer_in_td">Some copyright info</footer>
+   </td></tr></table>
+ 
+   <form id="form"></form>
++  <form id="named_form" aria-label="New form"></form>
+ 
+   <iframe id="frameset_container"
+           src="data:text/html,<html><frameset><frame src='data:text/html,hi'></frame></frameset></html>">
+   </iframe>
+ 
+   <h1 id="h1">heading1</h1>
+   <h2 id="h2">heading2</h2>
+   <h3 id="h3">heading3</h3>
+

+ 36 - 0
mozilla-release/patches/1444003-60a1.patch

@@ -0,0 +1,36 @@
+# HG changeset patch
+# User Yura Zenevich <yura.zenevich@gmail.com>
+# Date 1520529611 18000
+# Node ID 93881140d6d6ab2e73a7ba89a5feb9145a7534d6
+# Parent  4ae9c864cc76fba9865a293490ac37e33deb753a
+Bug 1444003 - remove shutdown timer when xpcAccessibleService's refcount grows over 1. r=surkov
+
+MozReview-Commit-ID: 8qQWdRkE1tb
+
+
+diff --git a/accessible/xpcom/xpcAccessibilityService.cpp b/accessible/xpcom/xpcAccessibilityService.cpp
+--- a/accessible/xpcom/xpcAccessibilityService.cpp
++++ b/accessible/xpcom/xpcAccessibilityService.cpp
+@@ -42,16 +42,21 @@ xpcAccessibilityService::AddRef(void)
+   if (!mRefCnt.isThreadSafe)
+     NS_ASSERT_OWNINGTHREAD(xpcAccessibilityService);
+   nsrefcnt count = ++mRefCnt;
+   NS_LOG_ADDREF(this, count, "xpcAccessibilityService", sizeof(*this));
+ 
+   // We want refcount to be > 1 because one reference is added in the XPCOM
+   // accessibility service getter.
+   if (mRefCnt > 1) {
++    if (mShutdownTimer) {
++      mShutdownTimer->Cancel();
++      mShutdownTimer = nullptr;
++    }
++
+     GetOrCreateAccService(nsAccessibilityService::eXPCOM);
+   }
+ 
+   return count;
+ }
+ 
+ NS_IMETHODIMP_(MozExternalRefCountType)
+ xpcAccessibilityService::Release(void)
+

+ 29 - 0
mozilla-release/patches/1444633-60a1.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User L. David Baron <dbaron@dbaron.org>
+# Date 1520829253 25200
+# Node ID b28213a70982f163998f473f51827d9be943c44a
+# Parent  46ecaa2d13e948c3af8e44434baaf14d79337e95
+Bug 1444633: Include nsString.h in TextAttrs.h. r=dholbert
+
+diff --git a/accessible/base/TextAttrs.h b/accessible/base/TextAttrs.h
+--- a/accessible/base/TextAttrs.h
++++ b/accessible/base/TextAttrs.h
+@@ -3,16 +3,17 @@
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #ifndef nsTextAttrs_h_
+ #define nsTextAttrs_h_
+ 
+ #include "nsCOMPtr.h"
+ #include "nsColor.h"
++#include "nsString.h"
+ #include "nsStyleConsts.h"
+ 
+ class nsIFrame;
+ class nsIPersistentProperties;
+ class nsIContent;
+ class nsDeviceContext;
+ 
+ namespace mozilla {
+

+ 171 - 0
mozilla-release/patches/1444851-61a1.patch

@@ -0,0 +1,171 @@
+# HG changeset patch
+# User James Teh <jteh@mozilla.com>
+# Date 1521450198 -7200
+# Node ID d71a9ebb920ac0d2eade586c56502852cc14da46
+# Parent  60d8158308b2ce3e4c7066c03099c7f99c4f362a
+Bug 1444851 - a11y::HandlerProvider: Clear the interceptor target reference when disconnecting remotes. r=aklotz
+
+If a handlerProvider call is pending on another thread, CoDisconnectObject won't release this HandlerProvider immediately.
+However, the interceptor and its target might be destroyed.
+
+MozReview-Commit-ID: 75SyPMIpit0
+
+diff --git a/accessible/ipc/win/HandlerProvider.cpp b/accessible/ipc/win/HandlerProvider.cpp
+--- a/accessible/ipc/win/HandlerProvider.cpp
++++ b/accessible/ipc/win/HandlerProvider.cpp
+@@ -256,19 +256,22 @@ HandlerProvider::BuildStaticIA2Data(
+   }
+ }
+ 
+ void
+ HandlerProvider::BuildDynamicIA2Data(DynamicIA2Data* aOutIA2Data)
+ {
+   MOZ_ASSERT(aOutIA2Data);
+   MOZ_ASSERT(NS_IsMainThread());
+-  MOZ_ASSERT(mTargetUnk);
+   MOZ_ASSERT(IsTargetInterfaceCacheable());
+ 
++  if (!mTargetUnk) {
++    return;
++  }
++
+   RefPtr<NEWEST_IA2_INTERFACE> target;
+   HRESULT hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID,
+     getter_AddRefs(target));
+   if (FAILED(hr)) {
+     return;
+   }
+ 
+   hr = E_UNEXPECTED;
+@@ -462,16 +465,21 @@ HandlerProvider::MarshalAs(REFIID aIid)
+   }
+   // Otherwise we juse return the identity.
+   return aIid;
+ }
+ 
+ HRESULT
+ HandlerProvider::DisconnectHandlerRemotes()
+ {
++  // If a handlerProvider call is pending on another thread,
++  // CoDisconnectObject won't release this HandlerProvider immediately.
++  // However, the interceptor and its target (mTargetUnk) might be destroyed.
++  mTargetUnk = nullptr;
++
+   IUnknown* unk = static_cast<IGeckoBackChannel*>(this);
+   return ::CoDisconnectObject(unk, 0);
+ }
+ 
+ REFIID
+ HandlerProvider::GetEffectiveOutParamIid(REFIID aCallIid,
+                                          ULONG aCallMethod)
+ {
+@@ -539,16 +547,20 @@ HandlerProvider::put_HandlerControl(long
+   return S_OK;
+ }
+ 
+ HRESULT
+ HandlerProvider::Refresh(DynamicIA2Data* aOutData)
+ {
+   MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+ 
++  if (!mTargetUnk) {
++    return CO_E_OBJNOTCONNECTED;
++  }
++
+   if (!mscom::InvokeOnMainThread("HandlerProvider::BuildDynamicIA2Data",
+                                  this, &HandlerProvider::BuildDynamicIA2Data,
+                                  aOutData)) {
+     return E_FAIL;
+   }
+ 
+   return S_OK;
+ }
+@@ -576,17 +588,21 @@ HandlerProvider::GetAllTextInfoMainThrea
+                                           long* aNAttribRuns, HRESULT* result)
+ {
+   MOZ_ASSERT(aText);
+   MOZ_ASSERT(aHyperlinks);
+   MOZ_ASSERT(aNHyperlinks);
+   MOZ_ASSERT(aAttribRuns);
+   MOZ_ASSERT(aNAttribRuns);
+   MOZ_ASSERT(NS_IsMainThread());
+-  MOZ_ASSERT(mTargetUnk);
++
++  if (!mTargetUnk) {
++    *result = CO_E_OBJNOTCONNECTED;
++    return;
++  }
+ 
+   RefPtr<IAccessibleHypertext2> ht;
+   HRESULT hr = mTargetUnk->QueryInterface(IID_IAccessibleHypertext2,
+                                           getter_AddRefs(ht));
+   if (FAILED(hr)) {
+     *result = hr;
+     return;
+   }
+@@ -652,16 +668,20 @@ HRESULT
+ HandlerProvider::get_AllTextInfo(BSTR* aText,
+                                  IAccessibleHyperlink*** aHyperlinks,
+                                  long* aNHyperlinks,
+                                  IA2TextSegment** aAttribRuns,
+                                  long* aNAttribRuns)
+ {
+   MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+ 
++  if (!mTargetUnk) {
++    return CO_E_OBJNOTCONNECTED;
++  }
++
+   HRESULT hr;
+   if (!mscom::InvokeOnMainThread("HandlerProvider::GetAllTextInfoMainThread",
+                                  this,
+                                  &HandlerProvider::GetAllTextInfoMainThread,
+                                  aText, aHyperlinks, aNHyperlinks,
+                                  aAttribRuns, aNAttribRuns, &hr)) {
+     return E_FAIL;
+   }
+@@ -672,17 +692,21 @@ HandlerProvider::get_AllTextInfo(BSTR* a
+ void
+ HandlerProvider::GetRelationsInfoMainThread(IARelationData** aRelations,
+                                             long* aNRelations,
+                                             HRESULT* hr)
+ {
+   MOZ_ASSERT(aRelations);
+   MOZ_ASSERT(aNRelations);
+   MOZ_ASSERT(NS_IsMainThread());
+-  MOZ_ASSERT(mTargetUnk);
++
++  if (!mTargetUnk) {
++    *hr = CO_E_OBJNOTCONNECTED;
++    return;
++  }
+ 
+   RefPtr<NEWEST_IA2_INTERFACE> acc;
+   *hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID,
+     getter_AddRefs(acc));
+   if (FAILED(*hr)) {
+     return;
+   }
+ 
+@@ -717,16 +741,20 @@ HandlerProvider::GetRelationsInfoMainThr
+ }
+ 
+ HRESULT
+ HandlerProvider::get_RelationsInfo(IARelationData** aRelations,
+                                    long* aNRelations)
+ {
+   MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+ 
++  if (!mTargetUnk) {
++    return CO_E_OBJNOTCONNECTED;
++  }
++
+   HRESULT hr;
+   if (!mscom::InvokeOnMainThread("HandlerProvider::GetRelationsInfoMainThread",
+                                  this,
+                                  &HandlerProvider::GetRelationsInfoMainThread,
+                                  aRelations, aNRelations, &hr)) {
+     return E_FAIL;
+   }
+ 
+

+ 198 - 0
mozilla-release/patches/1449530-1-61a1.patch

@@ -0,0 +1,198 @@
+# HG changeset patch
+# User Alexander Surkov <surkov.alexander@gmail.com>
+# Date 1522765617 14400
+# Node ID a11cb2c5d1f9f9159a62cb3b311f369a32019869
+# Parent  b9a19d50f51cec21ad141b1acb5f46c89fd85590
+Bug 1449530 - clean up ATK states mapping, r=eeejay
+
+diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp
+--- a/accessible/atk/AccessibleWrap.cpp
++++ b/accessible/atk/AccessibleWrap.cpp
+@@ -925,30 +925,28 @@ static void
+ TranslateStates(uint64_t aState, AtkStateSet* aStateSet)
+ {
+   // atk doesn't have a read only state so read only things shouldn't be
+   // editable.
+   if (aState & states::READONLY)
+     aState &= ~states::EDITABLE;
+ 
+   // Convert every state to an entry in AtkStateMap
+-  uint32_t stateIndex = 0;
+   uint64_t bitMask = 1;
+-  while (gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState) {
++  for (auto stateIndex = 0U; stateIndex < gAtkStateMapLen; stateIndex++) {
+     if (gAtkStateMap[stateIndex].atkState) { // There's potentially an ATK state for this
+       bool isStateOn = (aState & bitMask) != 0;
+       if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) {
+         isStateOn = !isStateOn;
+       }
+       if (isStateOn) {
+         atk_state_set_add_state(aStateSet, gAtkStateMap[stateIndex].atkState);
+       }
+     }
+     bitMask <<= 1;
+-    ++ stateIndex;
+   }
+ }
+ 
+ AtkStateSet *
+ refStateSetCB(AtkObject *aAtkObj)
+ {
+   AtkStateSet *state_set = nullptr;
+   state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj);
+@@ -1534,34 +1532,42 @@ a11y::ProxyCaretMoveEvent(ProxyAccessibl
+ {
+   AtkObject* wrapper = GetWrapperFor(aTarget);
+   g_signal_emit_by_name(wrapper, "text_caret_moved", aOffset);
+ }
+ 
+ void
+ MaiAtkObject::FireStateChangeEvent(uint64_t aState, bool aEnabled)
+ {
+-    int32_t stateIndex = AtkStateMap::GetStateIndexFor(aState);
+-    if (stateIndex >= 0) {
+-        NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState,
+-                     "No such state");
++  auto state = aState;
++  int32_t stateIndex = -1;
++  while (state > 0) {
++    ++stateIndex;
++    state >>= 1;
++  }
+ 
+-        if (gAtkStateMap[stateIndex].atkState != kNone) {
+-            NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange,
+-                         "State changes should not fired for this state");
++  MOZ_ASSERT(stateIndex >= 0 && stateIndex < gAtkStateMapLen,
++             "No ATK state for internal state was found");
++  if (stateIndex < 0 || stateIndex >= static_cast<int32_t>(gAtkStateMapLen)) {
++    return;
++  }
+ 
+-            if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite)
+-                aEnabled = !aEnabled;
++  if (gAtkStateMap[stateIndex].atkState != kNone) {
++    MOZ_ASSERT(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange,
++                 "State changes should not fired for this state");
+ 
+-            // Fire state change for first state if there is one to map
+-            atk_object_notify_state_change(&parent,
+-                                           gAtkStateMap[stateIndex].atkState,
+-                                           aEnabled);
+-        }
++    if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) {
++      aEnabled = !aEnabled;
+     }
++
++    // Fire state change for first state if there is one to map
++    atk_object_notify_state_change(&parent,
++                                   gAtkStateMap[stateIndex].atkState,
++                                   aEnabled);
++  }
+ }
+ 
+ void
+ a11y::ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
+                            int32_t aStart, uint32_t aLen, bool aIsInsert,
+                            bool aFromUser)
+ {
+   MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
+diff --git a/accessible/atk/nsStateMap.h b/accessible/atk/nsStateMap.h
+--- a/accessible/atk/nsStateMap.h
++++ b/accessible/atk/nsStateMap.h
+@@ -2,16 +2,18 @@
+ /* vim: set ts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include <atk/atk.h>
+ #include "AccessibleWrap.h"
+ 
++#include <type_traits>
++
+ /******************************************************************************
+ The following accessible states aren't translated, just ignored:
+   STATE_READONLY:        Supported indirectly via EXT_STATE_EDITABLE
+   STATE_HOTTRACKED:      No ATK equivalent.  No known use case.
+                          The nsIAccessible state is not currently supported.
+   STATE_FLOATING:        No ATK equivalent.  No known use case.
+                          The nsIAccessible state is not currently supported.
+   STATE_MOVEABLE:        No ATK equivalent.  No known use case.
+@@ -34,34 +36,23 @@ The following ATK states are not support
+   ATK_STATE_TRUNCATED:   No clear use case. Indicates that an object's onscreen content is truncated,
+                          e.g. a text value in a spreadsheet cell. No IA2 state.
+ ******************************************************************************/
+ 
+ enum EStateMapEntryType {
+   kMapDirectly,
+   kMapOpposite,   // For example, UNAVAILABLE is the opposite of ENABLED
+   kNoStateChange, // Don't fire state change event
+-  kNoSuchState
+ };
+ 
+ const AtkStateType kNone = ATK_STATE_INVALID;
+ 
+ struct AtkStateMap {
+   AtkStateType atkState;
+   EStateMapEntryType stateMapEntryType;
+-
+-  static int32_t GetStateIndexFor(uint64_t aState)
+-  {
+-    int32_t stateIndex = -1;
+-    while (aState > 0) {
+-      ++ stateIndex;
+-      aState >>= 1;
+-    }
+-    return stateIndex;  // Returns -1 if not mapped
+-  }
+ };
+ 
+ 
+ // Map array from cross platform states to ATK states
+ static const AtkStateMap gAtkStateMap[] = {                     // Cross Platform States
+   { kNone,                                    kMapOpposite },   // states::UNAVAILABLE             = 1 << 0
+   { ATK_STATE_SELECTED,                       kMapDirectly },   // states::SELECTED                = 1 << 1
+   { ATK_STATE_FOCUSED,                        kMapDirectly },   // states::FOCUSED                 = 1 << 2
+@@ -105,11 +96,15 @@ static const AtkStateMap gAtkStateMap[] 
+   { ATK_STATE_SINGLE_LINE,                    kMapDirectly },   // states::SINGLE_LINE             = 1 << 40
+   { ATK_STATE_TRANSIENT,                      kMapDirectly },   // states::TRANSIENT               = 1 << 41
+   { ATK_STATE_VERTICAL,                       kMapDirectly },   // states::VERTICAL                = 1 << 42
+   { ATK_STATE_STALE,                          kMapDirectly },   // states::STALE                   = 1 << 43
+   { ATK_STATE_ENABLED,                        kMapDirectly },   // states::ENABLED                 = 1 << 44
+   { ATK_STATE_SENSITIVE,                      kMapDirectly },   // states::SENSITIVE               = 1 << 45
+   { ATK_STATE_EXPANDABLE,                     kMapDirectly },   // states::EXPANDABLE              = 1 << 46
+   { kNone,                                    kMapDirectly },   // states::PINNED                  = 1 << 47
+-  { ATK_STATE_ACTIVE,                         kMapDirectly },   // states::CURRENT                 = 1 << 48
+-  { kNone,                                    kNoSuchState },   //                                 = 1 << 49
++  { ATK_STATE_ACTIVE,                         kMapDirectly }    // states::CURRENT                 = 1 << 48
+ };
++
++static const auto gAtkStateMapLen = std::extent<decltype(gAtkStateMap)>::value;
++
++static_assert(((uint64_t) 0x1) << (gAtkStateMapLen - 1) == mozilla::a11y::states::LAST_ENTRY,
++              "ATK states map is out of sync with internal states");
+diff --git a/accessible/base/States.h b/accessible/base/States.h
+--- a/accessible/base/States.h
++++ b/accessible/base/States.h
+@@ -278,14 +278,19 @@ namespace states {
+    */
+   const uint64_t PINNED = ((uint64_t) 0x1) << 47;
+ 
+   /**
+    * The object is the current item within a container or set of related elements.
+    */
+   const uint64_t CURRENT = ((uint64_t) 0x1) << 48;
+ 
++  /**
++   * Not a real state, used for static assertions.
++   */
++  const uint64_t LAST_ENTRY = CURRENT;
++
+ } // namespace states
+ } // namespace a11y
+ } // namespace mozilla
+ 
+ #endif
+ 
+

+ 30 - 0
mozilla-release/patches/1449530-2-61a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Alexander Surkov <surkov.alexander@gmail.com>
+# Date 1522767648 14400
+# Node ID bd15a594caa8e4b7e491180f90396c1e33b3bbbd
+# Parent  9559e00f1e98feb2b6a51c3fd5db0ae3895b3767
+Bug 1449530 - fix bustage of a11cb2c5d1f9c CLOSED TREE
+
+diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp
+--- a/accessible/atk/AccessibleWrap.cpp
++++ b/accessible/atk/AccessibleWrap.cpp
+@@ -1539,17 +1539,17 @@ MaiAtkObject::FireStateChangeEvent(uint6
+ {
+   auto state = aState;
+   int32_t stateIndex = -1;
+   while (state > 0) {
+     ++stateIndex;
+     state >>= 1;
+   }
+ 
+-  MOZ_ASSERT(stateIndex >= 0 && stateIndex < gAtkStateMapLen,
++  MOZ_ASSERT(stateIndex >= 0 && stateIndex < static_cast<int32_t>(gAtkStateMapLen),
+              "No ATK state for internal state was found");
+   if (stateIndex < 0 || stateIndex >= static_cast<int32_t>(gAtkStateMapLen)) {
+     return;
+   }
+ 
+   if (gAtkStateMap[stateIndex].atkState != kNone) {
+     MOZ_ASSERT(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange,
+                  "State changes should not fired for this state");
+

+ 143 - 0
mozilla-release/patches/857348-60a1.patch

@@ -0,0 +1,143 @@
+# HG changeset patch
+# User Alexander Surkov <surkov.alexander@gmail.com>
+# Date 1519767252 18000
+# Node ID 1db3a600ea0139e7fa9d637a3c3930155b236d4d
+# Parent  19c4eedf4d8e8c2cbd8ea83fe57352d137b762a1
+Bug 857348 - assert if defunct state is out of sync with content ref, rs=jamie
+
+diff --git a/accessible/atk/nsMaiInterfaceComponent.cpp b/accessible/atk/nsMaiInterfaceComponent.cpp
+--- a/accessible/atk/nsMaiInterfaceComponent.cpp
++++ b/accessible/atk/nsMaiInterfaceComponent.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "InterfaceInitFuncs.h"
+ 
++#include "Accessible-inl.h"
+ #include "AccessibleWrap.h"
+ #include "nsAccUtils.h"
+ #include "nsCoreUtils.h"
+ #include "nsMai.h"
+ #include "mozilla/Likely.h"
+ #include "mozilla/a11y/ProxyAccessible.h"
+ 
+ using namespace mozilla::a11y;
+diff --git a/accessible/generic/Accessible-inl.h b/accessible/generic/Accessible-inl.h
+--- a/accessible/generic/Accessible-inl.h
++++ b/accessible/generic/Accessible-inl.h
+@@ -99,16 +99,25 @@ Accessible::HasNumericValue() const
+     return false;
+ 
+   if (roleMapEntry->valueRule == eHasValueMinMaxIfFocusable)
+     return InteractiveState() & states::FOCUSABLE;
+ 
+   return true;
+ }
+ 
++inline bool
++Accessible::IsDefunct() const
++{
++  MOZ_ASSERT(mStateFlags & eIsDefunct || IsApplication() || IsDoc() ||
++             mStateFlags & eSharedNode || mContent,
++             "No content");
++  return mStateFlags & eIsDefunct;
++}
++
+ inline void
+ Accessible::ScrollTo(uint32_t aHow) const
+ {
+   if (mContent)
+     nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
+ }
+ 
+ inline bool
+diff --git a/accessible/generic/Accessible.h b/accessible/generic/Accessible.h
+--- a/accessible/generic/Accessible.h
++++ b/accessible/generic/Accessible.h
+@@ -856,17 +856,17 @@ public:
+   /**
+    * Return the localized string for the given key.
+    */
+   static void TranslateString(const nsString& aKey, nsAString& aStringOut);
+ 
+   /**
+    * Return true if the accessible is defunct.
+    */
+-  bool IsDefunct() const { return mStateFlags & eIsDefunct; }
++  bool IsDefunct() const;
+ 
+   /**
+    * Return false if the accessible is no longer in the document.
+    */
+   bool IsInDocument() const { return !(mStateFlags & eIsNotInDocument); }
+ 
+   /**
+    * Return true if the accessible should be contained by document node map.
+diff --git a/accessible/windows/msaa/XULListboxAccessibleWrap.cpp b/accessible/windows/msaa/XULListboxAccessibleWrap.cpp
+--- a/accessible/windows/msaa/XULListboxAccessibleWrap.cpp
++++ b/accessible/windows/msaa/XULListboxAccessibleWrap.cpp
+@@ -1,15 +1,17 @@
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "XULListboxAccessibleWrap.h"
+ 
++#include "Accessible-inl.h"
++
+ using namespace mozilla::a11y;
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ // XULListboxAccessibleWrap
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ NS_IMPL_ISUPPORTS_INHERITED0(XULListboxAccessibleWrap,
+                              XULListboxAccessible)
+diff --git a/accessible/windows/sdn/sdnDocAccessible.cpp b/accessible/windows/sdn/sdnDocAccessible.cpp
+--- a/accessible/windows/sdn/sdnDocAccessible.cpp
++++ b/accessible/windows/sdn/sdnDocAccessible.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "sdnDocAccessible.h"
+ 
++#include "Accessible-inl.h"
+ #include "ISimpleDOM.h"
+ 
+ #include "nsNameSpaceManager.h"
+ 
+ using namespace mozilla;
+ using namespace mozilla::a11y;
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+diff --git a/accessible/windows/uia/uiaRawElmProvider.cpp b/accessible/windows/uia/uiaRawElmProvider.cpp
+--- a/accessible/windows/uia/uiaRawElmProvider.cpp
++++ b/accessible/windows/uia/uiaRawElmProvider.cpp
+@@ -1,16 +1,17 @@
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+  * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "uiaRawElmProvider.h"
+ 
++#include "Accessible-inl.h"
+ #include "AccessibleWrap.h"
+ #include "ARIAMap.h"
+ #include "nsIPersistentProperties2.h"
+ 
+ using namespace mozilla;
+ using namespace mozilla::a11y;
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+

+ 26 - 0
mozilla-release/patches/series

@@ -7291,3 +7291,29 @@ TOP-NOBUG-blockquad0-25319.patch
 1902935-seamonkey-credits-25320.patch
 1902935-seamonkey-credits-25320.patch
 1435568-60a1.patch
 1435568-60a1.patch
 1180498-68a1.patch
 1180498-68a1.patch
+1363723-1-FIX-57a1.patch
+1363723-2-57a1.patch
+1408777-FIX-58a1.patch
+1416893-59a1.patch
+1419131-59a1.patch
+1260598-59a1.patch
+1405796-59a1.patch
+1427825-59a1.patch
+1432513-60a1.patch
+1431264-1-60a1.patch
+1431264-2-60a1.patch
+1431264-3-60a1.patch
+1433891-60a1.patch
+1402999-60a1.patch
+857348-60a1.patch
+1442196-60a1.patch
+1444003-60a1.patch
+1444633-60a1.patch
+1444851-61a1.patch
+1431256-1-61a1.patch
+1431256-2-61a1.patch
+1431256-3-61a1.patch
+1431256-4-61a1.patch
+1431256-5-61a1.patch
+1449530-1-61a1.patch
+1449530-2-61a1.patch