Bug 1297549: Part 1 - Use chrome-generated MSAA IDs in content; r=tbsaunde
authorAaron Klotz <aklotz@mozilla.com>
Mon, 19 Sep 2016 13:58:15 -0600
changeset 314457 10611fcdd32e0592397302afae63f842359394cb
parent 314456 d29c970e4d7d1a4f5dccaff860c6eaec60f05856
child 314458 345334eff0212ecb78a29a65c62b1e95d0279f3a
push id20574
push usercbook@mozilla.com
push dateTue, 20 Sep 2016 10:05:16 +0000
treeherderfx-team@14705f779a46 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs1297549
milestone51.0a1
Bug 1297549: Part 1 - Use chrome-generated MSAA IDs in content; r=tbsaunde MozReview-Commit-ID: 7YIx7f6KEOs
accessible/ipc/DocAccessibleChildBase.cpp
accessible/ipc/DocAccessibleChildBase.h
accessible/ipc/DocAccessibleParent.cpp
accessible/ipc/DocAccessibleParent.h
accessible/ipc/win/DocAccessibleChild.cpp
accessible/ipc/win/PDocAccessible.ipdl
accessible/windows/msaa/AccessibleWrap.cpp
accessible/windows/msaa/AccessibleWrap.h
accessible/windows/msaa/DocAccessibleWrap.cpp
accessible/windows/msaa/DocAccessibleWrap.h
--- a/accessible/ipc/DocAccessibleChildBase.cpp
+++ b/accessible/ipc/DocAccessibleChildBase.cpp
@@ -77,23 +77,61 @@ DocAccessibleChildBase::SerializeTree(Ac
   aTree.AppendElement(AccessibleData(id, role, childCount, interfaces));
 #endif
 
   for (uint32_t i = 0; i < childCount; i++) {
     SerializeTree(aRoot->GetChildAt(i), aTree);
   }
 }
 
+#if defined(XP_WIN)
+/* static */ void
+DocAccessibleChildBase::SetMsaaIds(Accessible* aRoot,
+                                   uint32_t& aMsaaIdIndex,
+                                   const nsTArray<MsaaMapping>& aNewMsaaIds)
+{
+  const MsaaMapping& mapping = aNewMsaaIds[aMsaaIdIndex];
+#if defined(DEBUG)
+  uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
+  MOZ_ASSERT(mapping.ID() == id);
+#endif // defined(DEBUG)
+  static_cast<AccessibleWrap*>(aRoot)->SetID(mapping.MsaaID());
+  ++aMsaaIdIndex;
+  if (aRoot->IsOuterDoc()) {
+    // This needs to match the tree traversal in SerializeTree
+    return;
+  }
+  for (uint32_t i = 0, n = aRoot->ChildCount(); i < n; ++i) {
+    SetMsaaIds(aRoot->GetChildAt(i), aMsaaIdIndex, aNewMsaaIds);
+  }
+}
+#endif // defined(XP_WIN)
+
 void
 DocAccessibleChildBase::ShowEvent(AccShowEvent* aShowEvent)
 {
   Accessible* parent = aShowEvent->Parent();
   uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID());
   uint32_t idxInParent = aShowEvent->InsertionIndex();
   nsTArray<AccessibleData> shownTree;
   ShowEventData data(parentID, idxInParent, shownTree);
   SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
+#if defined(XP_WIN)
+  nsTArray<MsaaMapping> newMsaaIds;
+  SendShowEventInfo(data, &newMsaaIds);
+  // newMsaaIds could be empty if something went wrong in SendShowEvent()
+  if (!newMsaaIds.IsEmpty()) {
+    uint32_t index = 0;
+    SetMsaaIds(aShowEvent->GetAccessible(), index, newMsaaIds);
+  }
+  // NB: On Windows, SendShowEvent attaches the subtree and generates new IDs,
+  //     but does *NOT* fire the native event. We need to do that after
+  //     we've called SetMsaaIds.
+  SendEvent(reinterpret_cast<uint64_t>(aShowEvent->GetAccessible()->UniqueID()),
+            nsIAccessibleEvent::EVENT_SHOW);
+#else
   SendShowEvent(data, aShowEvent->IsFromUserInput());
+#endif // defined(XP_WIN)
 }
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/DocAccessibleChildBase.h
+++ b/accessible/ipc/DocAccessibleChildBase.h
@@ -55,16 +55,20 @@ public:
 
     mDoc->SetIPCDoc(nullptr);
     mDoc = nullptr;
   }
 
 protected:
   static uint32_t InterfacesFor(Accessible* aAcc);
   static void SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree);
+#if defined(XP_WIN)
+  static void SetMsaaIds(Accessible* aRoot, uint32_t& aMsaaIdIndex,
+                         const nsTArray<MsaaMapping>& aNewMsaaIds);
+#endif
 
   DocAccessible*  mDoc;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_DocAccessibleChildBase_h
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -11,18 +11,23 @@
 #include "xpcAccEvents.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 
 namespace mozilla {
 namespace a11y {
 
 bool
+#if defined(XP_WIN)
+DocAccessibleParent::RecvShowEventInfo(const ShowEventData& aData,
+                                       nsTArray<MsaaMapping>* aNewMsaaIds)
+#else
 DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
                                    const bool& aFromUser)
+#endif // defined(XP_WIN)
 {
   if (mShutdown)
     return true;
 
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
 
   if (aData.NewTree().IsEmpty()) {
     NS_ERROR("no children being added");
@@ -39,17 +44,23 @@ DocAccessibleParent::RecvShowEvent(const
   }
 
   uint32_t newChildIdx = aData.Idx();
   if (newChildIdx > parent->ChildrenCount()) {
     NS_ERROR("invalid index to add child at");
     return true;
   }
 
+#if defined(XP_WIN)
+  aNewMsaaIds->SetCapacity(aData.NewTree().Length());
+  uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx,
+                                 aNewMsaaIds);
+#else
   uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
+#endif
   MOZ_ASSERT(consumed == aData.NewTree().Length());
 
   // XXX This shouldn't happen, but if we failed to add children then the below
   // is pointless and can crash.
   if (!consumed) {
     return true;
   }
 
@@ -57,38 +68,46 @@ DocAccessibleParent::RecvShowEvent(const
   for (uint32_t i = 0; i < consumed; i++) {
     uint64_t id = aData.NewTree()[i].ID();
     MOZ_ASSERT(mAccessibles.GetEntry(id));
   }
 #endif
 
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
 
+  // NB: On Windows we dispatch the native event via a subsequent call to
+  // RecvEvent().
+#if !defined(XP_WIN)
   ProxyAccessible* target = parent->ChildAt(newChildIdx);
   ProxyShowHideEvent(target, parent, true, aFromUser);
 
   if (!nsCoreUtils::AccEventObserversExist()) {
     return true;
   }
 
   uint32_t type = nsIAccessibleEvent::EVENT_SHOW;
   xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   nsIDOMNode* node = nullptr;
   RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node,
                                               aFromUser);
   nsCoreUtils::DispatchAccEvent(Move(event));
+#endif
 
   return true;
 }
 
 uint32_t
 DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
                                 const nsTArray<a11y::AccessibleData>& aNewTree,
-                                uint32_t aIdx, uint32_t aIdxInParent)
+                                uint32_t aIdx, uint32_t aIdxInParent
+#if defined(XP_WIN)
+                                , nsTArray<MsaaMapping>* aNewMsaaIds
+#endif
+                                )
 {
   if (aNewTree.Length() <= aIdx) {
     NS_ERROR("bad index in serialized tree!");
     return 0;
   }
 
   const AccessibleData& newChild = aNewTree[aIdx];
   if (newChild.Role() > roles::LAST_ROLE) {
@@ -119,20 +138,32 @@ DocAccessibleParent::AddSubtree(ProxyAcc
     new ProxyAccessible(newChild.ID(), aParent, this, role,
                         newChild.Interfaces());
 #endif
 
   aParent->AddChildAt(aIdxInParent, newProxy);
   mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
   ProxyCreated(newProxy, newChild.Interfaces());
 
+#if defined(XP_WIN)
+  Accessible* idForAcc = WrapperFor(newProxy);
+  MOZ_ASSERT(idForAcc);
+  uint32_t newMsaaId = AccessibleWrap::GetChildIDFor(idForAcc);
+  MOZ_ASSERT(newMsaaId);
+  aNewMsaaIds->AppendElement(MsaaMapping(newChild.ID(), newMsaaId));
+#endif // defined(XP_WIN)
+
   uint32_t accessibles = 1;
   uint32_t kids = newChild.ChildrenCount();
   for (uint32_t i = 0; i < kids; i++) {
-    uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i);
+    uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i
+#if defined(XP_WIN)
+                                   , aNewMsaaIds
+#endif
+                                  );
     if (!consumed)
       return 0;
 
     accessibles += consumed;
   }
 
   MOZ_ASSERT(newProxy->ChildrenCount() == kids);
 
@@ -471,26 +502,29 @@ DocAccessibleParent::GetXPCAccessible(Pr
 /**
  * @param aCOMProxy COM Proxy to the document in the content process.
  * @param aParentCOMProxy COM Proxy to the OuterDocAccessible that is
  *        the parent of the document. The content process will use this
  *        proxy when traversing up across the content/chrome boundary.
  */
 bool
 DocAccessibleParent::RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
-                                  IAccessibleHolder* aParentCOMProxy)
+                                  IAccessibleHolder* aParentCOMProxy,
+                                  uint32_t* aMsaaID)
 {
   RefPtr<IAccessible> ptr(aCOMProxy.Get());
   SetCOMInterface(ptr);
 
   Accessible* outerDoc = OuterDocOfRemoteBrowser();
   IAccessible* rawNative = nullptr;
   if (outerDoc) {
     outerDoc->GetNativeInterface((void**) &rawNative);
   }
 
   aParentCOMProxy->Set(IAccessibleHolder::COMPtrType(rawNative));
+  Accessible* wrapper = WrapperFor(this);
+  *aMsaaID = AccessibleWrap::GetChildIDFor(wrapper);
   return true;
 }
 #endif // defined(XP_WIN)
 
 } // a11y
 } // mozilla
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -45,18 +45,23 @@ public:
 
   /*
    * Called when a message from a document in a child process notifies the main
    * process it is firing an event.
    */
   virtual bool RecvEvent(const uint64_t& aID, const uint32_t& aType)
     override;
 
+#if defined(XP_WIN)
+  virtual bool RecvShowEventInfo(const ShowEventData& aData,
+                                 nsTArray<MsaaMapping>* aNewMsaaIds) override;
+#else
   virtual bool RecvShowEvent(const ShowEventData& aData, const bool& aFromUser)
     override;
+#endif // defined(XP_WIN)
   virtual bool RecvHideEvent(const uint64_t& aRootID, const bool& aFromUser)
     override;
   virtual bool RecvStateChangeEvent(const uint64_t& aID,
                                     const uint64_t& aState,
                                     const bool& aEnabled) override final;
 
   virtual bool RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
     override final;
@@ -139,17 +144,18 @@ public:
     { return const_cast<DocAccessibleParent*>(this)->GetAccessible(aID); }
 
   size_t ChildDocCount() const { return mChildDocs.Length(); }
   const DocAccessibleParent* ChildDocAt(size_t aIdx) const
     { return mChildDocs[aIdx]; }
 
 #if defined(XP_WIN)
   virtual bool RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
-                            IAccessibleHolder* aParentCOMProxy) override;
+                            IAccessibleHolder* aParentCOMProxy,
+                            uint32_t* aMsaaID) override;
 #endif
 
 private:
 
   class ProxyEntry : public PLDHashEntryHdr
   {
   public:
     explicit ProxyEntry(const void*) : mProxy(nullptr) {}
@@ -169,17 +175,21 @@ private:
 
     enum { ALLOW_MEMMOVE = true };
 
     ProxyAccessible* mProxy;
   };
 
   uint32_t AddSubtree(ProxyAccessible* aParent,
                       const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
-                      uint32_t aIdxInParent);
+                      uint32_t aIdxInParent
+#if defined(XP_WIN)
+                      , nsTArray<MsaaMapping>* aNewMsaaIds
+#endif // defined(XP_WIN)
+                      );
   MOZ_MUST_USE bool CheckDocTree() const;
   xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
 
   nsTArray<DocAccessibleParent*> mChildDocs;
   DocAccessibleParent* mParentDoc;
 
   /*
    * Conceptually this is a map from IDs to proxies, but we store the ID in the
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -29,15 +29,17 @@ DocAccessibleChild::~DocAccessibleChild(
 {
   MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
 }
 
 void
 DocAccessibleChild::SendCOMProxy(const IAccessibleHolder& aProxy)
 {
   IAccessibleHolder parentProxy;
-  PDocAccessibleChild::SendCOMProxy(aProxy, &parentProxy);
+  uint32_t msaaID = AccessibleWrap::kNoID;
+  PDocAccessibleChild::SendCOMProxy(aProxy, &parentProxy, &msaaID);
   mParentProxy.reset(parentProxy.Release());
+  mDoc->SetID(msaaID);
 }
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/win/PDocAccessible.ipdl
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -22,16 +22,22 @@ struct AccessibleData
 
 struct ShowEventData
 {
   uint64_t ID;
   uint32_t Idx;
   AccessibleData[] NewTree;
 };
 
+struct MsaaMapping
+{
+  uint64_t ID;
+  uint32_t MsaaID;
+};
+
 struct Attribute
 {
   nsCString Name;
   nsString Value;
 };
 
 sync protocol PDocAccessible
 {
@@ -40,17 +46,17 @@ sync protocol PDocAccessible
 parent:
   async Shutdown();
 
   /*
    * Notify the parent process the document in the child process is firing an
    * event.
    */
   async Event(uint64_t aID, uint32_t type);
-  async ShowEvent(ShowEventData data, bool aFromuser);
+  sync ShowEventInfo(ShowEventData data) returns (MsaaMapping[] aNewMsaaIds);
   async HideEvent(uint64_t aRootID, bool aFromUser);
   async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
   async CaretMoveEvent(uint64_t aID, int32_t aOffset);
   async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
                         bool aIsInsert, bool aFromUser);
   async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);
   async RoleChangedEvent(uint32_t aRole);
 
@@ -58,16 +64,16 @@ parent:
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
   // For now we'll add the command to send the proxy here. This might move to
   // PDocAccessible constructor in PBrowser.
   sync COMProxy(IAccessibleHolder aDocCOMProxy)
-    returns(IAccessibleHolder aParentCOMProxy);
+    returns(IAccessibleHolder aParentCOMProxy, uint32_t aMsaaID);
 
 child:
   async __delete__();
 };
 
 }
 }
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -4,16 +4,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/. */
 
 #include "AccessibleWrap.h"
 #include "Accessible-inl.h"
 
 #include "Compatibility.h"
 #include "DocAccessible-inl.h"
+#include "mozilla/a11y/DocAccessibleChild.h"
 #include "mozilla/a11y/DocAccessibleParent.h"
 #include "EnumVariant.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsIAccessibleEvent.h"
 #include "nsWinUtils.h"
 #include "mozilla/a11y/ProxyAccessible.h"
 #include "ProxyWrappers.h"
@@ -64,46 +65,42 @@ IDSet AccessibleWrap::sIDGen;
 
 static const int32_t kIEnumVariantDisconnected = -1;
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
   Accessible(aContent, aDoc)
-#ifdef _WIN64
   , mID(kNoID)
-#endif
 {
 }
 
 AccessibleWrap::~AccessibleWrap()
 {
 #ifdef _WIN64
-  if (mID != kNoID)
+  if (mID != kNoID && XRE_IsParentProcess())
     sIDGen.ReleaseID(mID);
 #endif
 }
 
 ITypeInfo* AccessibleWrap::gTypeInfo = nullptr;
 
 NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, Accessible)
 
 void
 AccessibleWrap::Shutdown()
 {
-#ifdef _WIN64
   if (mID != kNoID) {
     auto doc = static_cast<DocAccessibleWrap*>(mDoc);
     MOZ_ASSERT(doc);
     if (doc) {
       doc->RemoveID(mID);
     }
   }
-#endif
 
   Accessible::Shutdown();
 }
 
 //-----------------------------------------------------
 // IUnknown interface methods - see iunknown.h for documentation
 //-----------------------------------------------------
 
@@ -1143,18 +1140,31 @@ AccessibleWrap::Invoke(DISPID dispIdMemb
 void
 AccessibleWrap::GetNativeInterface(void** aOutAccessible)
 {
   *aOutAccessible = static_cast<IAccessible*>(this);
   NS_ADDREF_THIS();
 }
 
 void
+AccessibleWrap::SetID(uint32_t aID)
+{
+  MOZ_ASSERT(XRE_IsContentProcess());
+  mID = aID;
+  DocAccessibleWrap* doc = static_cast<DocAccessibleWrap*>(Document());
+  DebugOnly<AccessibleWrap*> checkAcc = nullptr;
+  MOZ_ASSERT(!(checkAcc = doc->GetAccessibleByID(aID)) ||
+             checkAcc->GetExistingID() == aID);
+  doc->AddID(aID, this);
+}
+
+void
 AccessibleWrap::FireWinEvent(Accessible* aTarget, uint32_t aEventType)
 {
+  MOZ_ASSERT(XRE_IsParentProcess());
   static_assert(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY,
                 "MSAA event map skewed");
 
   NS_ASSERTION(aEventType > 0 && aEventType < ArrayLength(gWinEventMap), "invalid event type");
 
   uint32_t winEvent = gWinEventMap[aEventType];
   if (!winEvent)
     return;
@@ -1241,16 +1251,23 @@ AccessibleWrap::GetChildIDFor(Accessible
   // A child ID of the window is required, when we use NotifyWinEvent,
   // so that the 3rd party application can call back and get the IAccessible
   // the event occurred on.
 
   if (!aAccessible) {
     return 0;
   }
 
+  // Content should use mID which has been generated by the chrome process.
+  if (XRE_IsContentProcess() && !aAccessible->IsApplication()) {
+    const uint32_t id = static_cast<AccessibleWrap*>(aAccessible)->mID;
+    MOZ_ASSERT(id != kNoID);
+    return id;
+  }
+
 #ifdef _WIN64
   if (!aAccessible->Document() && !aAccessible->IsProxy())
     return 0;
 
   uint32_t* id = & static_cast<AccessibleWrap*>(aAccessible)->mID;
   if (*id != kNoID)
     return *id;
 
@@ -1340,34 +1357,32 @@ AccessibleWrap::NativeAccessible(Accessi
     return nullptr;
   }
 
   IAccessible* msaaAccessible = nullptr;
   aAccessible->GetNativeInterface(reinterpret_cast<void**>(&msaaAccessible));
   return static_cast<IDispatch*>(msaaAccessible);
 }
 
-#ifdef _WIN64
 static Accessible*
 GetAccessibleInSubtree(DocAccessible* aDoc, uint32_t aID)
 {
   Accessible* child = static_cast<DocAccessibleWrap*>(aDoc)->GetAccessibleByID(aID);
   if (child)
     return child;
 
   uint32_t childDocCount = aDoc->ChildDocumentCount();
   for (uint32_t i = 0; i < childDocCount; i++) {
     child = GetAccessibleInSubtree(aDoc->GetChildDocumentAt(i), aID);
     if (child)
       return child;
   }
 
     return nullptr;
   }
-#endif
 
 static AccessibleWrap*
 GetProxiedAccessibleInSubtree(const DocAccessibleParent* aDoc, uint32_t aID)
 {
   auto wrapper = static_cast<DocProxyAccessibleWrap*>(WrapperFor(aDoc));
   AccessibleWrap* child = wrapper->GetAccessibleByID(aID);
   if (child) {
     return child;
@@ -1421,17 +1436,19 @@ AccessibleWrap::GetXPAccessibleFor(const
   if (!IsProxy()) {
     void* uniqueID = reinterpret_cast<void*>(intptr_t(-aVarChild.lVal));
 
     DocAccessible* document = Document();
     Accessible* child =
 #ifdef _WIN64
       GetAccessibleInSubtree(document, static_cast<uint32_t>(aVarChild.lVal));
 #else
-      document->GetAccessibleByUniqueIDInSubtree(uniqueID);
+      XRE_IsContentProcess() ?
+        GetAccessibleInSubtree(document, static_cast<uint32_t>(aVarChild.lVal)) :
+        document->GetAccessibleByUniqueIDInSubtree(uniqueID);
 #endif
 
     // If it is a document then just return an accessible.
     if (child && IsDoc())
       return child;
 
     // Otherwise check whether the accessible is a child (this path works for
     // ARIA documents and popups).
--- a/accessible/windows/msaa/AccessibleWrap.h
+++ b/accessible/windows/msaa/AccessibleWrap.h
@@ -174,27 +174,25 @@ public: // construction, destruction
    * Find an accessible by the given child ID in cached documents.
    */
   Accessible* GetXPAccessibleFor(const VARIANT& aVarChild);
 
   virtual void GetNativeInterface(void **aOutAccessible) override;
 
   static IDispatch* NativeAccessible(Accessible* aAccessible);
 
-#ifdef _WIN64
   uint32_t GetExistingID() const { return mID; }
   static const uint32_t kNoID = 0;
-#endif
+  // This is only valid to call in content
+  void SetID(uint32_t aID);
 
 protected:
   virtual ~AccessibleWrap();
 
-#ifdef _WIN64
   uint32_t mID;
-#endif
 
   /**
    * Return the wrapper for the document's proxy.
    */
   DocProxyAccessibleWrap* DocProxyWrapper() const;
 
   /**
    * Creates ITypeInfo for LIBID_Accessibility if it's needed and returns it.
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -43,25 +43,20 @@ IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWr
     return S_OK;
   }
 IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(HyperTextAccessibleWrap)
 
 STDMETHODIMP
 DocAccessibleWrap::get_accParent(
       /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
 {
-  HRESULT hr = DocAccessible::get_accParent(ppdispParent);
-  if (*ppdispParent) {
-    return hr;
-  }
-
   // We might be a top-level document in a content process.
   DocAccessibleChild* ipcDoc = IPCDoc();
   if (!ipcDoc) {
-    return S_FALSE;
+    return DocAccessible::get_accParent(ppdispParent);
   }
   IAccessible* dispParent = ipcDoc->GetParentIAccessible();
   if (!dispParent) {
     return S_FALSE;
   }
 
   dispParent->AddRef();
   *ppdispParent = static_cast<IDispatch*>(dispParent);
--- a/accessible/windows/msaa/DocAccessibleWrap.h
+++ b/accessible/windows/msaa/DocAccessibleWrap.h
@@ -35,35 +35,31 @@ public:
   virtual void Shutdown();
 
   // DocAccessible
   virtual void* GetNativeWindow() const;
 
   /**
    * Manage the mapping from id to Accessible.
    */
-#ifdef _WIN64
   void AddID(uint32_t aID, AccessibleWrap* aAcc)
     { mIDToAccessibleMap.Put(aID, aAcc); }
   void RemoveID(uint32_t aID) { mIDToAccessibleMap.Remove(aID); }
   AccessibleWrap* GetAccessibleByID(uint32_t aID) const
     { return mIDToAccessibleMap.Get(aID); }
-#endif
 
 protected:
   // DocAccessible
   virtual void DoInitialUpdate();
 
 protected:
   void* mHWND;
 
   /*
    * This provides a mapping from 32 bit id to accessible objects.
    */
-#ifdef _WIN64
   nsDataHashtable<nsUint32HashKey, AccessibleWrap*> mIDToAccessibleMap;
-#endif
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif