Backed out 6 changesets (bug 1694865) for Windows accessibility crashes. a=backout
authorSebastian Hengst <archaeopteryx@coole-files.de>
Thu, 29 Apr 2021 14:29:25 +0200
changeset 577939 d9e30da70def144c22f40e7debc5b190a31eb1f1
parent 577938 36de91ab59b93fecadebd915220833ba0de4ddaa
child 577972 abe0d75ef0ee47c22fcddb8d273c35128c446535
push id38418
push userarchaeopteryx@coole-files.de
push dateThu, 29 Apr 2021 12:29:50 +0000
treeherdermozilla-central@d9e30da70def [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1694865
milestone90.0a1
backs out53ed762843ec9fbb7c622f498c5ffa494fcd7e09
309f737d3bc3479d0fe4d82d13519f0d78205eae
461b46e1a2cbcbdfa8306a4a007972894aef0bae
acafc5835608eeda617d7e2cb9118d8b667c6287
40c7e0bcfcfd65160b8e15123bae95b84f457718
7dfb88fc34a1631546768dfd23305ba2f14eb88b
first release with
nightly win32
d9e30da70def / 90.0a1 / 20210429122950 / files
nightly win64
d9e30da70def / 90.0a1 / 20210429122950 / files
nightly linux32
nightly linux64
nightly mac
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly win32
nightly win64
Backed out 6 changesets (bug 1694865) for Windows accessibility crashes. a=backout Backed out changeset 53ed762843ec (bug 1694865) Backed out changeset 309f737d3bc3 (bug 1694865) Backed out changeset 461b46e1a2cb (bug 1694865) Backed out changeset acafc5835608 (bug 1694865) Backed out changeset 40c7e0bcfcfd (bug 1694865) Backed out changeset 7dfb88fc34a1 (bug 1694865)
accessible/generic/LocalAccessible-inl.h
accessible/windows/ia2/ia2Accessible.cpp
accessible/windows/ia2/ia2Accessible.h
accessible/windows/ia2/ia2AccessibleAction.cpp
accessible/windows/ia2/ia2AccessibleAction.h
accessible/windows/ia2/ia2AccessibleComponent.cpp
accessible/windows/ia2/ia2AccessibleComponent.h
accessible/windows/ia2/ia2AccessibleEditableText.cpp
accessible/windows/ia2/ia2AccessibleEditableText.h
accessible/windows/ia2/ia2AccessibleHyperlink.cpp
accessible/windows/ia2/ia2AccessibleHyperlink.h
accessible/windows/ia2/ia2AccessibleHypertext.cpp
accessible/windows/ia2/ia2AccessibleHypertext.h
accessible/windows/ia2/ia2AccessibleImage.cpp
accessible/windows/ia2/ia2AccessibleImage.h
accessible/windows/ia2/ia2AccessibleRelation.cpp
accessible/windows/ia2/ia2AccessibleTable.cpp
accessible/windows/ia2/ia2AccessibleTable.h
accessible/windows/ia2/ia2AccessibleTableCell.cpp
accessible/windows/ia2/ia2AccessibleTableCell.h
accessible/windows/ia2/ia2AccessibleText.cpp
accessible/windows/ia2/ia2AccessibleText.h
accessible/windows/ia2/ia2AccessibleValue.cpp
accessible/windows/ia2/ia2AccessibleValue.h
accessible/windows/msaa/AccessibleWrap.cpp
accessible/windows/msaa/AccessibleWrap.h
accessible/windows/msaa/CompatibilityUIA.cpp
accessible/windows/msaa/DocAccessibleWrap.cpp
accessible/windows/msaa/EnumVariant.cpp
accessible/windows/msaa/MsaaAccessible.cpp
accessible/windows/msaa/MsaaAccessible.h
--- a/accessible/generic/LocalAccessible-inl.h
+++ b/accessible/generic/LocalAccessible-inl.h
@@ -67,17 +67,17 @@ inline bool LocalAccessible::ARIAHasNume
 }
 
 inline bool LocalAccessible::HasNumericValue() const {
   return NativeHasNumericValue() || ARIAHasNumericValue();
 }
 
 inline bool LocalAccessible::IsDefunct() const {
   MOZ_ASSERT(mStateFlags & eIsDefunct || IsApplication() || IsDoc() ||
-                 IsProxy() || mStateFlags & eSharedNode || mContent,
+                 mStateFlags & eSharedNode || mContent,
              "No content");
   return mStateFlags & eIsDefunct;
 }
 
 inline void LocalAccessible::ScrollTo(uint32_t aHow) const {
   if (mContent) {
     RefPtr<PresShell> presShell = mDoc->PresShellPtr();
     nsCOMPtr<nsIContent> content = mContent;
--- a/accessible/windows/ia2/ia2Accessible.cpp
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -56,30 +56,26 @@ ia2Accessible::QueryInterface(REFIID iid
   if (*ppv) {
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
   return E_NOINTERFACE;
 }
 
-AccessibleWrap* ia2Accessible::LocalAcc() {
-  return static_cast<MsaaAccessible*>(this)->LocalAcc();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // IAccessible2
 
 STDMETHODIMP
 ia2Accessible::get_nRelations(long* aNRelations) {
   if (!aNRelations) return E_INVALIDARG;
   *aNRelations = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   MOZ_ASSERT(!acc->IsProxy());
 
   for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
     if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue;
 
     Relation rel = acc->RelationByType(sRelationTypePairs[idx].first);
     if (rel.Next()) (*aNRelations)++;
@@ -88,33 +84,32 @@ ia2Accessible::get_nRelations(long* aNRe
 }
 
 STDMETHODIMP
 ia2Accessible::get_relation(long aRelationIndex,
                             IAccessibleRelation** aRelation) {
   if (!aRelation || aRelationIndex < 0) return E_INVALIDARG;
   *aRelation = nullptr;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   MOZ_ASSERT(!acc->IsProxy());
 
   long relIdx = 0;
   for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
     if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue;
 
     RelationType relationType = sRelationTypePairs[idx].first;
     Relation rel = acc->RelationByType(relationType);
     RefPtr<ia2AccessibleRelation> ia2Relation =
         new ia2AccessibleRelation(relationType, &rel);
     if (ia2Relation->HasTargets()) {
       if (relIdx == aRelationIndex) {
-        MsaaAccessible* msaa = static_cast<MsaaAccessible*>(this);
-        msaa->AssociateCOMObjectForDisconnection(ia2Relation);
+        acc->AssociateCOMObjectForDisconnection(ia2Relation);
         ia2Relation.forget(aRelation);
         return S_OK;
       }
 
       relIdx++;
     }
   }
 
@@ -123,47 +118,46 @@ ia2Accessible::get_relation(long aRelati
 
 STDMETHODIMP
 ia2Accessible::get_relations(long aMaxRelations,
                              IAccessibleRelation** aRelation,
                              long* aNRelations) {
   if (!aRelation || !aNRelations || aMaxRelations <= 0) return E_INVALIDARG;
   *aNRelations = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   MOZ_ASSERT(!acc->IsProxy());
 
   for (uint32_t idx = 0;
        idx < ArrayLength(sRelationTypePairs) && *aNRelations < aMaxRelations;
        idx++) {
     if (sRelationTypePairs[idx].second == IA2_RELATION_NULL) continue;
 
     RelationType relationType = sRelationTypePairs[idx].first;
     Relation rel = acc->RelationByType(relationType);
     RefPtr<ia2AccessibleRelation> ia2Rel =
         new ia2AccessibleRelation(relationType, &rel);
     if (ia2Rel->HasTargets()) {
-      MsaaAccessible* msaa = static_cast<MsaaAccessible*>(this);
-      msaa->AssociateCOMObjectForDisconnection(ia2Rel);
+      acc->AssociateCOMObjectForDisconnection(ia2Rel);
       ia2Rel.forget(aRelation + (*aNRelations));
       (*aNRelations)++;
     }
   }
   return S_OK;
 }
 
 STDMETHODIMP
 ia2Accessible::role(long* aRole) {
   if (!aRole) return E_INVALIDARG;
   *aRole = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
 #define ROLE(_geckoRole, stringRole, atkRole, macRole, macSubrole, msaaRole, \
              ia2Role, androidClass, nameRule)                                \
   case roles::_geckoRole:                                                    \
     *aRole = ia2Role;                                                        \
     break;
 
   a11y::role geckoRole;
@@ -187,32 +181,32 @@ ia2Accessible::role(long* aRole) {
   }
 
   return S_OK;
 }
 
 // XXX Use MOZ_CAN_RUN_SCRIPT_BOUNDARY for now due to bug 1543294.
 MOZ_CAN_RUN_SCRIPT_BOUNDARY STDMETHODIMP
 ia2Accessible::scrollTo(enum IA2ScrollType aScrollType) {
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   MOZ_ASSERT(!acc->IsProxy());
   RefPtr<PresShell> presShell = acc->Document()->PresShellPtr();
   nsCOMPtr<nsIContent> content = acc->GetContent();
   nsCoreUtils::ScrollTo(presShell, content, aScrollType);
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2Accessible::scrollToPoint(enum IA2CoordinateType aCoordType, long aX,
                              long aY) {
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   uint32_t geckoCoordType =
       (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
           ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
           : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
 
   MOZ_ASSERT(!acc->IsProxy());
   acc->ScrollToPoint(geckoCoordType, aX, aY);
@@ -225,18 +219,18 @@ ia2Accessible::get_groupPosition(long* a
                                  long* aPositionInGroup) {
   if (!aGroupLevel || !aSimilarItemsInGroup || !aPositionInGroup)
     return E_INVALIDARG;
 
   *aGroupLevel = 0;
   *aSimilarItemsInGroup = 0;
   *aPositionInGroup = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   GroupPos groupPos = acc->GroupPosition();
 
   // Group information for accessibles having level only (like html headings
   // elements) isn't exposed by this method. AT should look for 'level' object
   // attribute.
   if (!groupPos.setSize && !groupPos.posInSet) return S_FALSE;
 
@@ -249,18 +243,18 @@ ia2Accessible::get_groupPosition(long* a
 
 STDMETHODIMP
 ia2Accessible::get_states(AccessibleStates* aStates) {
   if (!aStates) return E_INVALIDARG;
   *aStates = 0;
 
   // XXX: bug 344674 should come with better approach that we have here.
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) {
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) {
     *aStates = IA2_STATE_DEFUNCT;
     return S_OK;
   }
 
   uint64_t state;
   MOZ_ASSERT(!acc->IsProxy());
   state = acc->State();
 
@@ -339,40 +333,40 @@ ia2Accessible::get_localizedExtendedStat
   *aNLocalizedExtendedStates = 0;
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 ia2Accessible::get_uniqueID(long* aUniqueID) {
   if (!aUniqueID) return E_INVALIDARG;
 
-  AccessibleWrap* acc = LocalAcc();
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   *aUniqueID = MsaaAccessible::GetChildIDFor(acc);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2Accessible::get_windowHandle(HWND* aWindowHandle) {
   if (!aWindowHandle) return E_INVALIDARG;
   *aWindowHandle = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
-  *aWindowHandle = MsaaAccessible::GetHWNDFor(acc);
+  *aWindowHandle = AccessibleWrap::GetHWNDFor(acc);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2Accessible::get_indexInParent(long* aIndexInParent) {
   if (!aIndexInParent) return E_INVALIDARG;
   *aIndexInParent = -1;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   MOZ_ASSERT(!acc->IsProxy());
   *aIndexInParent = acc->IndexInParent();
 
   if (*aIndexInParent == -1) return S_FALSE;
 
   return S_OK;
 }
@@ -381,18 +375,18 @@ STDMETHODIMP
 ia2Accessible::get_locale(IA2Locale* aLocale) {
   if (!aLocale) return E_INVALIDARG;
 
   // Language codes consist of a primary code and a possibly empty series of
   // subcodes: language-code = primary-code ( "-" subcode )*
   // Two-letter primary codes are reserved for [ISO639] language abbreviations.
   // Any two-letter subcode is understood to be a [ISO3166] country code.
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsAutoString lang;
   acc->Language(lang);
 
   // If primary code consists from two letters then expose it as language.
   int32_t offset = lang.FindChar('-', 0);
   if (offset == -1) {
     if (lang.Length() == 2) {
@@ -421,18 +415,18 @@ ia2Accessible::get_locale(IA2Locale* aLo
   return S_OK;
 }
 
 STDMETHODIMP
 ia2Accessible::get_attributes(BSTR* aAttributes) {
   if (!aAttributes) return E_INVALIDARG;
   *aAttributes = nullptr;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   // The format is name:value;name:value; with \ for escaping these
   // characters ":;=,\".
   if (!acc->IsProxy()) {
     nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes();
     return ConvertToIA2Attributes(attributes, aAttributes);
   }
 
@@ -453,33 +447,33 @@ ia2Accessible::get_attribute(BSTR name, 
 STDMETHODIMP
 ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible,
                                        long* aCaretOffset) {
   if (!aAccessible || !aCaretOffset) return E_INVALIDARG;
 
   *aAccessible = nullptr;
   *aCaretOffset = -1;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   int32_t caretOffset = -1;
   LocalAccessible* accWithCaret =
       SelectionMgr()->AccessibleWithCaret(&caretOffset);
   if (!accWithCaret || acc->Document() != accWithCaret->Document())
     return S_FALSE;
 
   LocalAccessible* child = accWithCaret;
   while (!child->IsDoc() && child != acc) child = child->LocalParent();
 
   if (child != acc) return S_FALSE;
 
-  RefPtr<IAccessible2> ia2WithCaret;
-  accWithCaret->GetNativeInterface(getter_AddRefs(ia2WithCaret));
-  ia2WithCaret.forget(aAccessible);
+  *aAccessible =
+      static_cast<IAccessible2*>(static_cast<AccessibleWrap*>(accWithCaret));
+  (*aAccessible)->AddRef();
   *aCaretOffset = caretOffset;
   return S_OK;
 }
 
 STDMETHODIMP
 ia2Accessible::get_relationTargetsOfType(BSTR aType, long aMaxTargets,
                                          IUnknown*** aTargets,
                                          long* aNTargets) {
@@ -490,18 +484,18 @@ ia2Accessible::get_relationTargetsOfType
   for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
     if (wcscmp(aType, sRelationTypePairs[idx].second) == 0) {
       relationType.emplace(sRelationTypePairs[idx].first);
       break;
     }
   }
   if (!relationType) return E_INVALIDARG;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsTArray<LocalAccessible*> targets;
   MOZ_ASSERT(!acc->IsProxy());
   Relation rel = acc->RelationByType(*relationType);
   LocalAccessible* target = nullptr;
   while (
       (target = rel.Next()) &&
       (aMaxTargets == 0 || static_cast<long>(targets.Length()) < aMaxTargets)) {
@@ -509,52 +503,54 @@ ia2Accessible::get_relationTargetsOfType
   }
 
   *aNTargets = targets.Length();
   *aTargets =
       static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) * *aNTargets));
   if (!*aTargets) return E_OUTOFMEMORY;
 
   for (int32_t i = 0; i < *aNTargets; i++) {
-    RefPtr<IAccessible2> target;
-    targets[i]->GetNativeInterface(getter_AddRefs(target));
-    target.forget(&(*aTargets)[i]);
+    AccessibleWrap* target = static_cast<AccessibleWrap*>(targets[i]);
+    (*aTargets)[i] = static_cast<IAccessible2*>(target);
+    (*aTargets)[i]->AddRef();
   }
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2Accessible::get_selectionRanges(IA2Range** aRanges, long* aNRanges) {
   if (!aRanges || !aNRanges) return E_INVALIDARG;
 
   *aNRanges = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   AutoTArray<TextRange, 1> ranges;
   acc->Document()->SelectionRanges(&ranges);
   ranges.RemoveElementsBy([acc](auto& range) { return !range.Crop(acc); });
 
   *aNRanges = ranges.Length();
   *aRanges =
       static_cast<IA2Range*>(::CoTaskMemAlloc(sizeof(IA2Range) * *aNRanges));
   if (!*aRanges) return E_OUTOFMEMORY;
 
   for (uint32_t idx = 0; idx < static_cast<uint32_t>(*aNRanges); idx++) {
-    RefPtr<IAccessible2> anchor;
-    ranges[idx].StartContainer()->GetNativeInterface(getter_AddRefs(anchor));
-    anchor.forget(&(*aRanges)[idx].anchor);
+    AccessibleWrap* anchor =
+        static_cast<AccessibleWrap*>(ranges[idx].StartContainer());
+    (*aRanges)[idx].anchor = static_cast<IAccessible2*>(anchor);
+    anchor->AddRef();
 
     (*aRanges)[idx].anchorOffset = ranges[idx].StartOffset();
 
-    RefPtr<IAccessible2> active;
-    ranges[idx].EndContainer()->GetNativeInterface(getter_AddRefs(active));
-    active.forget(&(*aRanges)[idx].active);
+    AccessibleWrap* active =
+        static_cast<AccessibleWrap*>(ranges[idx].EndContainer());
+    (*aRanges)[idx].active = static_cast<IAccessible2*>(active);
+    active->AddRef();
 
     (*aRanges)[idx].activeOffset = ranges[idx].EndOffset();
   }
 
   return S_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/windows/ia2/ia2Accessible.h
+++ b/accessible/windows/ia2/ia2Accessible.h
@@ -12,17 +12,16 @@
 
 #include "Accessible2_3.h"
 
 class nsIPersistentProperties;
 
 namespace mozilla {
 namespace a11y {
 class Attribute;
-class AccessibleWrap;
 
 class ia2Accessible : public IAccessible2_3 {
  public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessible2
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRelations(
@@ -111,17 +110,14 @@ class ia2Accessible : public IAccessible
       /* [out, size_is(,*nRanges)] */ IA2Range** ranges,
       /* [out, retval] */ long* nRanges);
 
   // Helper method
   static HRESULT ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
                                         BSTR* aIA2Attributes);
   static HRESULT ConvertToIA2Attributes(nsTArray<Attribute>* aAttributes,
                                         BSTR* aIA2Attributes);
-
- private:
-  AccessibleWrap* LocalAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleAction.cpp
+++ b/accessible/windows/ia2/ia2AccessibleAction.cpp
@@ -9,68 +9,65 @@
 
 #include "AccessibleAction_i.c"
 
 #include "AccessibleWrap.h"
 #include "IUnknownImpl.h"
 
 using namespace mozilla::a11y;
 
-AccessibleWrap* ia2AccessibleAction::LocalAcc() {
-  return static_cast<MsaaAccessible*>(this)->LocalAcc();
-}
-
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv) {
   if (!ppv) return E_INVALIDARG;
 
   *ppv = nullptr;
 
-  if (IID_IAccessibleAction == iid && LocalAcc() && !LocalAcc()->IsProxy()) {
+  if (IID_IAccessibleAction == iid &&
+      !static_cast<AccessibleWrap*>(this)->IsProxy()) {
     *ppv = static_cast<IAccessibleAction*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
   return E_NOINTERFACE;
 }
 
 // IAccessibleAction
 
 STDMETHODIMP
 ia2AccessibleAction::nActions(long* aActionCount) {
   if (!aActionCount) return E_INVALIDARG;
 
   *aActionCount = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   *aActionCount = acc->ActionCount();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleAction::doAction(long aActionIndex) {
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   uint8_t index = static_cast<uint8_t>(aActionIndex);
   return acc->DoAction(index) ? S_OK : E_INVALIDARG;
 }
 
 STDMETHODIMP
 ia2AccessibleAction::get_description(long aActionIndex, BSTR* aDescription) {
   if (!aDescription) return E_INVALIDARG;
   *aDescription = nullptr;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsAutoString description;
   uint8_t index = static_cast<uint8_t>(aActionIndex);
   acc->ActionDescriptionAt(index, description);
   if (description.IsEmpty()) return S_FALSE;
 
   *aDescription = ::SysAllocStringLen(description.get(), description.Length());
   return *aDescription ? S_OK : E_OUTOFMEMORY;
@@ -82,18 +79,18 @@ ia2AccessibleAction::get_keyBinding(long
   if (!aKeyBinding) return E_INVALIDARG;
   *aKeyBinding = nullptr;
 
   if (!aNumBinding) return E_INVALIDARG;
   *aNumBinding = 0;
 
   if (aActionIndex != 0 || aNumMaxBinding < 1) return E_INVALIDARG;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   // Expose keyboard shortcut if it's not exposed via MSAA keyboard shortcut.
   KeyBinding keyBinding = acc->AccessKey();
   if (keyBinding.IsEmpty()) return S_FALSE;
 
   keyBinding = acc->KeyboardShortcut();
   if (keyBinding.IsEmpty()) return S_FALSE;
 
@@ -114,18 +111,18 @@ ia2AccessibleAction::get_keyBinding(long
 }
 
 STDMETHODIMP
 ia2AccessibleAction::get_name(long aActionIndex, BSTR* aName) {
   if (!aName) return E_INVALIDARG;
 
   *aName = nullptr;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsAutoString name;
   uint8_t index = static_cast<uint8_t>(aActionIndex);
   acc->ActionNameAt(index, name);
   if (name.IsEmpty()) return E_INVALIDARG;
 
   *aName = ::SysAllocStringLen(name.get(), name.Length());
   return *aName ? S_OK : E_OUTOFMEMORY;
--- a/accessible/windows/ia2/ia2AccessibleAction.h
+++ b/accessible/windows/ia2/ia2AccessibleAction.h
@@ -9,17 +9,16 @@
 #define _ACCESSIBLE_ACTION_H
 
 #include "nsISupports.h"
 
 #include "AccessibleAction.h"
 
 namespace mozilla {
 namespace a11y {
-class AccessibleWrap;
 
 class ia2AccessibleAction : public IAccessibleAction {
  public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessibleAction
   virtual HRESULT STDMETHODCALLTYPE nActions(
@@ -40,19 +39,16 @@ class ia2AccessibleAction : public IAcce
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_name(
       /* [in] */ long actionIndex,
       /* [retval][out] */ BSTR* name);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_localizedName(
       /* [in] */ long actionIndex,
       /* [retval][out] */ BSTR* localizedName);
-
- private:
-  AccessibleWrap* LocalAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #define FORWARD_IACCESSIBLEACTION(Class)                                       \
   virtual HRESULT STDMETHODCALLTYPE nActions(long* nActions) {                 \
     return Class::nActions(nActions);                                          \
--- a/accessible/windows/ia2/ia2AccessibleComponent.cpp
+++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp
@@ -12,20 +12,16 @@
 #include "AccessibleWrap.h"
 #include "States.h"
 #include "IUnknownImpl.h"
 
 #include "nsIFrame.h"
 
 using namespace mozilla::a11y;
 
-AccessibleWrap* ia2AccessibleComponent::LocalAcc() {
-  return static_cast<MsaaAccessible*>(this)->LocalAcc();
-}
-
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleComponent::QueryInterface(REFIID iid, void** ppv) {
   if (!ppv) return E_INVALIDARG;
 
   *ppv = nullptr;
 
@@ -42,18 +38,18 @@ ia2AccessibleComponent::QueryInterface(R
 
 STDMETHODIMP
 ia2AccessibleComponent::get_locationInParent(long* aX, long* aY) {
   if (!aX || !aY) return E_INVALIDARG;
 
   *aX = 0;
   *aY = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   // If the object is not on any screen the returned position is (0,0).
   uint64_t state = acc->State();
   if (state & states::INVISIBLE) return S_OK;
 
   nsIntRect rect = acc->Bounds();
 
   // The coordinates of the returned position are relative to this object's
@@ -74,33 +70,33 @@ ia2AccessibleComponent::get_locationInPa
 }
 
 STDMETHODIMP
 ia2AccessibleComponent::get_foreground(IA2Color* aForeground) {
   if (!aForeground) return E_INVALIDARG;
 
   *aForeground = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsIFrame* frame = acc->GetFrame();
   if (frame) *aForeground = frame->StyleText()->mColor.ToColor();
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleComponent::get_background(IA2Color* aBackground) {
   if (!aBackground) return E_INVALIDARG;
 
   *aBackground = 0;
 
-  AccessibleWrap* acc = LocalAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsIFrame* frame = acc->GetFrame();
   if (frame) {
     *aBackground = frame->StyleBackground()->BackgroundColor(frame);
   }
 
   return S_OK;
 }
--- a/accessible/windows/ia2/ia2AccessibleComponent.h
+++ b/accessible/windows/ia2/ia2AccessibleComponent.h
@@ -7,34 +7,30 @@
 
 #ifndef IA2_ACCESSIBLE_COMPONENT_H_
 #define IA2_ACCESSIBLE_COMPONENT_H_
 
 #include "AccessibleComponent.h"
 
 namespace mozilla {
 namespace a11y {
-class AccessibleWrap;
 
 class ia2AccessibleComponent : public IAccessibleComponent {
  public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessibleComponent
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_locationInParent(
       /* [out] */ long* x,
       /* [retval][out] */ long* y);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_foreground(
       /* [retval][out] */ IA2Color* foreground);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_background(
       /* [retval][out] */ IA2Color* background);
-
- private:
-  AccessibleWrap* LocalAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleEditableText.cpp
+++ b/accessible/windows/ia2/ia2AccessibleEditableText.cpp
@@ -12,94 +12,91 @@
 #include "HyperTextAccessibleWrap.h"
 #include "ProxyWrappers.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 
 using namespace mozilla::a11y;
 
-HyperTextAccessibleWrap* ia2AccessibleEditableText::TextAcc() {
-  // XXX This first static_cast is a necessary hack until we get rid of the
-  // inheritance of HyperTextAccessibleWrap.
-  auto wrap = static_cast<HyperTextAccessibleWrap*>(this);
-  AccessibleWrap* acc = static_cast<MsaaAccessible*>(wrap)->LocalAcc();
-  return static_cast<HyperTextAccessibleWrap*>(acc);
-}
-
 // IAccessibleEditableText
 
 STDMETHODIMP
 ia2AccessibleEditableText::copyText(long aStartOffset, long aEndOffset) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG;
 
   textAcc->CopyText(aStartOffset, aEndOffset);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleEditableText::deleteText(long aStartOffset, long aEndOffset) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG;
 
   textAcc->DeleteText(aStartOffset, aEndOffset);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleEditableText::insertText(long aOffset, BSTR* aText) {
   uint32_t length = ::SysStringLen(*aText);
   nsAutoString text(*aText, length);
+  MOZ_ASSERT(!HyperTextProxyFor(this));
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
 
   textAcc->InsertText(text, aOffset);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleEditableText::cutText(long aStartOffset, long aEndOffset) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG;
 
   textAcc->CutText(aStartOffset, aEndOffset);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleEditableText::pasteText(long aOffset) {
-  RefPtr<HyperTextAccessible> textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  RefPtr<HyperTextAccessible> textAcc =
+      static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
 
   textAcc->PasteText(aOffset);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleEditableText::replaceText(long aStartOffset, long aEndOffset,
                                        BSTR* aText) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) return E_INVALIDARG;
 
   textAcc->DeleteText(aStartOffset, aEndOffset);
 
   uint32_t length = ::SysStringLen(*aText);
   nsAutoString text(*aText, length);
   textAcc->InsertText(text, aStartOffset);
--- a/accessible/windows/ia2/ia2AccessibleEditableText.h
+++ b/accessible/windows/ia2/ia2AccessibleEditableText.h
@@ -9,17 +9,16 @@
 #define _ACCESSIBLE_EDITABLETEXT_H
 
 #include "nsISupports.h"
 
 #include "AccessibleEditableText.h"
 
 namespace mozilla {
 namespace a11y {
-class HyperTextAccessibleWrap;
 
 class ia2AccessibleEditableText : public IAccessibleEditableText {
  public:
   // IAccessibleEditableText
   virtual HRESULT STDMETHODCALLTYPE copyText(
       /* [in] */ long startOffset,
       /* [in] */ long endOffset);
 
@@ -43,17 +42,14 @@ class ia2AccessibleEditableText : public
       /* [in] */ long startOffset,
       /* [in] */ long endOffset,
       /* [in] */ BSTR* text);
 
   virtual HRESULT STDMETHODCALLTYPE setAttributes(
       /* [in] */ long startOffset,
       /* [in] */ long endOffset,
       /* [in] */ BSTR* attributes);
-
- private:
-  HyperTextAccessibleWrap* TextAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleHyperlink.cpp
+++ b/accessible/windows/ia2/ia2AccessibleHyperlink.cpp
@@ -9,34 +9,28 @@
 #include "AccessibleHyperlink_i.c"
 
 #include "AccessibleWrap.h"
 #include "IUnknownImpl.h"
 #include "nsIURI.h"
 
 using namespace mozilla::a11y;
 
-AccessibleWrap* ia2AccessibleHyperlink::LocalAcc() {
-  return static_cast<MsaaAccessible*>(this)->LocalAcc();
-}
-
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleHyperlink::QueryInterface(REFIID iid, void** ppv) {
   if (!ppv) return E_INVALIDARG;
 
   *ppv = nullptr;
 
   if (IID_IAccessibleHyperlink == iid) {
-    auto accWrap = LocalAcc();
-    if (!accWrap || accWrap->IsProxy() ? !accWrap->Proxy()->IsLink()
-                                       : !accWrap->IsLink()) {
+    auto accWrap = static_cast<AccessibleWrap*>(this);
+    if (accWrap->IsProxy() ? !accWrap->Proxy()->IsLink() : !accWrap->IsLink())
       return E_NOINTERFACE;
-    }
 
     *ppv = static_cast<IAccessibleHyperlink*>(this);
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
 
   return ia2AccessibleAction::QueryInterface(iid, ppv);
 }
@@ -44,52 +38,53 @@ ia2AccessibleHyperlink::QueryInterface(R
 // IAccessibleHyperlink
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_anchor(long aIndex, VARIANT* aAnchor) {
   if (!aAnchor) return E_INVALIDARG;
 
   VariantInit(aAnchor);
 
-  LocalAccessible* thisObj = LocalAcc();
-  if (!thisObj) {
-    return CO_E_OBJNOTCONNECTED;
-  }
+  LocalAccessible* thisObj = static_cast<AccessibleWrap*>(this);
   MOZ_ASSERT(!thisObj->IsProxy());
 
+  if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
   if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount()))
     return E_INVALIDARG;
 
   if (!thisObj->IsLink()) return S_FALSE;
 
   AccessibleWrap* anchor =
       static_cast<AccessibleWrap*>(thisObj->AnchorAt(aIndex));
   if (!anchor) return S_FALSE;
 
-  RefPtr<IAccessible> result;
-  anchor->GetNativeInterface(getter_AddRefs(result));
-  result.forget(&aAnchor->punkVal);
+  void* instancePtr = nullptr;
+  HRESULT result = anchor->QueryInterface(IID_IUnknown, &instancePtr);
+  if (FAILED(result)) return result;
+
+  aAnchor->punkVal = static_cast<IUnknown*>(instancePtr);
   aAnchor->vt = VT_UNKNOWN;
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT* aAnchorTarget) {
   if (!aAnchorTarget) {
     return E_INVALIDARG;
   }
 
   VariantInit(aAnchorTarget);
 
-  LocalAccessible* thisObj = LocalAcc();
-  if (!thisObj) {
+  LocalAccessible* thisObj = static_cast<AccessibleWrap*>(this);
+  nsAutoCString uriStr;
+  MOZ_ASSERT(!thisObj->IsProxy());
+  if (thisObj->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  nsAutoCString uriStr;
-  MOZ_ASSERT(!thisObj->IsProxy());
 
   if (aIndex < 0 || aIndex >= static_cast<long>(thisObj->AnchorCount())) {
     return E_INVALIDARG;
   }
 
   if (!thisObj->IsLink()) {
     return S_FALSE;
   }
@@ -114,55 +109,52 @@ ia2AccessibleHyperlink::get_anchorTarget
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_startIndex(long* aIndex) {
   if (!aIndex) return E_INVALIDARG;
 
   *aIndex = 0;
 
-  LocalAccessible* thisObj = LocalAcc();
-  if (!thisObj) {
-    return CO_E_OBJNOTCONNECTED;
-  }
-  MOZ_ASSERT(!thisObj->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  LocalAccessible* thisObj = static_cast<AccessibleWrap*>(this);
+  if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!thisObj->IsLink()) return S_FALSE;
 
   *aIndex = thisObj->StartOffset();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_endIndex(long* aIndex) {
   if (!aIndex) return E_INVALIDARG;
 
   *aIndex = 0;
 
-  LocalAccessible* thisObj = LocalAcc();
-  if (!thisObj) {
-    return CO_E_OBJNOTCONNECTED;
-  }
-  MOZ_ASSERT(!thisObj->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  LocalAccessible* thisObj = static_cast<AccessibleWrap*>(this);
+  if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!thisObj->IsLink()) return S_FALSE;
 
   *aIndex = thisObj->EndOffset();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleHyperlink::get_valid(boolean* aValid) {
   if (!aValid) return E_INVALIDARG;
 
   *aValid = false;
 
-  LocalAccessible* thisObj = LocalAcc();
-  if (!thisObj) {
-    return CO_E_OBJNOTCONNECTED;
-  }
-  MOZ_ASSERT(!thisObj->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  LocalAccessible* thisObj = static_cast<AccessibleWrap*>(this);
+  if (thisObj->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!thisObj->IsLink()) return S_FALSE;
 
   *aValid = thisObj->IsLinkValid();
   return S_OK;
 }
--- a/accessible/windows/ia2/ia2AccessibleHyperlink.h
+++ b/accessible/windows/ia2/ia2AccessibleHyperlink.h
@@ -10,17 +10,16 @@
 
 #include "nsISupports.h"
 
 #include "ia2AccessibleAction.h"
 #include "AccessibleHyperlink.h"
 
 namespace mozilla {
 namespace a11y {
-class AccessibleWrap;
 
 class ia2AccessibleHyperlink : public ia2AccessibleAction,
                                public IAccessibleHyperlink {
  public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessibleAction
@@ -37,17 +36,14 @@ class ia2AccessibleHyperlink : public ia
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_startIndex(
       /* [retval][out] */ long* index);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_endIndex(
       /* [retval][out] */ long* index);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_valid(
       /* [retval][out] */ boolean* valid);
-
- private:
-  AccessibleWrap* LocalAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleHypertext.cpp
+++ b/accessible/windows/ia2/ia2AccessibleHypertext.cpp
@@ -9,94 +9,92 @@
 
 #include "AccessibleHypertext_i.c"
 
 #include "HyperTextAccessibleWrap.h"
 #include "IUnknownImpl.h"
 
 using namespace mozilla::a11y;
 
-HyperTextAccessibleWrap* ia2AccessibleHypertext::TextAcc() {
-  // XXX This first static_cast is a necessary hack until we get rid of the
-  // inheritance of HyperTextAccessibleWrap.
-  auto wrap = static_cast<HyperTextAccessibleWrap*>(this);
-  AccessibleWrap* acc = static_cast<MsaaAccessible*>(wrap)->LocalAcc();
-  return static_cast<HyperTextAccessibleWrap*>(acc);
-}
-
 // IAccessibleHypertext
 
 STDMETHODIMP
 ia2AccessibleHypertext::get_nHyperlinks(long* aHyperlinkCount) {
   if (!aHyperlinkCount) return E_INVALIDARG;
 
   *aHyperlinkCount = 0;
 
-  HyperTextAccessibleWrap* hyperText = TextAcc();
-  if (!hyperText) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!hyperText->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessibleWrap* hyperText =
+      static_cast<HyperTextAccessibleWrap*>(this);
+  if (hyperText->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   *aHyperlinkCount = hyperText->LinkCount();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleHypertext::get_hyperlink(long aLinkIndex,
                                       IAccessibleHyperlink** aHyperlink) {
   if (!aHyperlink) return E_INVALIDARG;
 
   *aHyperlink = nullptr;
 
   AccessibleWrap* hyperLink;
-  HyperTextAccessibleWrap* hyperText = TextAcc();
-  if (!hyperText) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessibleWrap* hyperText =
+      static_cast<HyperTextAccessibleWrap*>(this);
+  if (hyperText->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!hyperText->IsProxy());
 
   hyperLink = static_cast<AccessibleWrap*>(hyperText->LinkAt(aLinkIndex));
 
   if (!hyperLink) return E_FAIL;
 
-  RefPtr<IAccessibleHyperlink> result;
-  hyperLink->GetNativeInterface(getter_AddRefs(result));
-  result.forget(aHyperlink);
+  *aHyperlink = static_cast<IAccessibleHyperlink*>(hyperLink);
+  (*aHyperlink)->AddRef();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleHypertext::get_hyperlinkIndex(long aCharIndex,
                                            long* aHyperlinkIndex) {
   if (!aHyperlinkIndex) return E_INVALIDARG;
 
   *aHyperlinkIndex = 0;
 
-  HyperTextAccessibleWrap* hyperAcc = TextAcc();
-  if (!hyperAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!hyperAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessibleWrap* hyperAcc =
+      static_cast<HyperTextAccessibleWrap*>(this);
+  if (hyperAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   *aHyperlinkIndex = hyperAcc->LinkIndexAtOffset(aCharIndex);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleHypertext::get_hyperlinks(IAccessibleHyperlink*** aHyperlinks,
                                        long* aNHyperlinks) {
   if (!aHyperlinks || !aNHyperlinks) {
     return E_INVALIDARG;
   }
 
   *aHyperlinks = nullptr;
   *aNHyperlinks = 0;
 
-  HyperTextAccessibleWrap* hyperText = TextAcc();
-  if (!hyperText) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessibleWrap* hyperText =
+      static_cast<HyperTextAccessibleWrap*>(this);
+  if (hyperText->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!hyperText->IsProxy());
 
   uint32_t count = hyperText->LinkCount();
   *aNHyperlinks = count;
 
   if (count == 0) {
     *aHyperlinks = nullptr;
     return S_FALSE;
   }
@@ -106,15 +104,14 @@ ia2AccessibleHypertext::get_hyperlinks(I
   if (!*aHyperlinks) {
     return E_OUTOFMEMORY;
   }
 
   for (uint32_t i = 0; i < count; ++i) {
     AccessibleWrap* hyperLink =
         static_cast<AccessibleWrap*>(hyperText->LinkAt(i));
     MOZ_ASSERT(hyperLink);
-    RefPtr<IAccessibleHyperlink> iaHyper;
-    hyperLink->GetNativeInterface(getter_AddRefs(iaHyper));
-    iaHyper.forget(&(*aHyperlinks)[i]);
+    (*aHyperlinks)[i] = static_cast<IAccessibleHyperlink*>(hyperLink);
+    (*aHyperlinks)[i]->AddRef();
   }
 
   return S_OK;
 }
--- a/accessible/windows/ia2/ia2AccessibleHypertext.h
+++ b/accessible/windows/ia2/ia2AccessibleHypertext.h
@@ -10,17 +10,16 @@
 
 #include "nsISupports.h"
 
 #include "ia2AccessibleText.h"
 #include "AccessibleHypertext2.h"
 
 namespace mozilla {
 namespace a11y {
-class HyperTextAccessibleWrap;
 
 class ia2AccessibleHypertext : public ia2AccessibleText,
                                public IAccessibleHypertext2 {
  public:
   // IAccessibleText
   FORWARD_IACCESSIBLETEXT(ia2AccessibleText)
 
   // IAccessibleHypertext
@@ -34,17 +33,14 @@ class ia2AccessibleHypertext : public ia
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinkIndex(
       /* [in] */ long charIndex,
       /* [retval][out] */ long* hyperlinkIndex);
 
   // IAccessibleHypertext2
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_hyperlinks(
       /* [out, size_is(,*nHyperlinks)] */ IAccessibleHyperlink*** hyperlinks,
       /* [out, retval] */ long* nHyperlinks);
-
- private:
-  HyperTextAccessibleWrap* TextAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleImage.cpp
+++ b/accessible/windows/ia2/ia2AccessibleImage.cpp
@@ -13,24 +13,16 @@
 #include "IUnknownImpl.h"
 #include "nsIAccessibleTypes.h"
 
 #include "nsString.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
-ImageAccessible* ia2AccessibleImage::ImageAcc() {
-  // XXX This first static_cast is a necessary hack until we get rid of the
-  // inheritance of ImageAccessibleWrap.
-  auto wrap = static_cast<ImageAccessibleWrap*>(this);
-  AccessibleWrap* acc = static_cast<MsaaAccessible*>(wrap)->LocalAcc();
-  return static_cast<ImageAccessible*>(acc);
-}
-
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleImage::QueryInterface(REFIID iid, void** ppv) {
   if (!ppv) return E_INVALIDARG;
 
   *ppv = nullptr;
 
@@ -46,18 +38,18 @@ ia2AccessibleImage::QueryInterface(REFII
 // IAccessibleImage
 
 STDMETHODIMP
 ia2AccessibleImage::get_description(BSTR* aDescription) {
   if (!aDescription) return E_INVALIDARG;
 
   *aDescription = nullptr;
 
-  ImageAccessible* acc = ImageAcc();
-  if (!acc) return CO_E_OBJNOTCONNECTED;
+  ImageAccessibleWrap* acc = static_cast<ImageAccessibleWrap*>(this);
+  if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsAutoString description;
   acc->Name(description);
   if (description.IsEmpty()) return S_FALSE;
 
   *aDescription = ::SysAllocStringLen(description.get(), description.Length());
   return *aDescription ? S_OK : E_OUTOFMEMORY;
 }
@@ -65,18 +57,18 @@ ia2AccessibleImage::get_description(BSTR
 STDMETHODIMP
 ia2AccessibleImage::get_imagePosition(enum IA2CoordinateType aCoordType,
                                       long* aX, long* aY) {
   if (!aX || !aY) return E_INVALIDARG;
 
   *aX = 0;
   *aY = 0;
 
-  ImageAccessible* imageAcc = ImageAcc();
-  if (!imageAcc) return CO_E_OBJNOTCONNECTED;
+  ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this);
+  if (imageAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   uint32_t geckoCoordType =
       (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
           ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
           : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
 
   nsIntPoint pos = imageAcc->Position(geckoCoordType);
   *aX = pos.x;
@@ -86,16 +78,16 @@ ia2AccessibleImage::get_imagePosition(en
 
 STDMETHODIMP
 ia2AccessibleImage::get_imageSize(long* aHeight, long* aWidth) {
   if (!aHeight || !aWidth) return E_INVALIDARG;
 
   *aHeight = 0;
   *aWidth = 0;
 
-  ImageAccessible* imageAcc = ImageAcc();
-  if (!imageAcc) return CO_E_OBJNOTCONNECTED;
+  ImageAccessibleWrap* imageAcc = static_cast<ImageAccessibleWrap*>(this);
+  if (imageAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   nsIntSize size = imageAcc->Size();
   *aHeight = size.width;
   *aWidth = size.height;
   return S_OK;
 }
--- a/accessible/windows/ia2/ia2AccessibleImage.h
+++ b/accessible/windows/ia2/ia2AccessibleImage.h
@@ -7,17 +7,16 @@
 
 #ifndef _ACCESSIBLE_IMAGE_H
 #define _ACCESSIBLE_IMAGE_H
 
 #include "AccessibleImage.h"
 
 namespace mozilla {
 namespace a11y {
-class ImageAccessible;
 
 class ia2AccessibleImage : public IAccessibleImage {
  public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessibleImage
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_description(
@@ -26,17 +25,14 @@ class ia2AccessibleImage : public IAcces
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imagePosition(
       /* [in] */ enum IA2CoordinateType coordinateType,
       /* [out] */ long* x,
       /* [retval][out] */ long* y);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_imageSize(
       /* [out] */ long* height,
       /* [retval][out] */ long* width);
-
- private:
-  ImageAccessible* ImageAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleRelation.cpp
+++ b/accessible/windows/ia2/ia2AccessibleRelation.cpp
@@ -64,19 +64,20 @@ ia2AccessibleRelation::get_nTargets(long
 }
 
 STDMETHODIMP
 ia2AccessibleRelation::get_target(long aTargetIndex, IUnknown** aTarget) {
   if (aTargetIndex < 0 || (uint32_t)aTargetIndex >= mTargets.Length() ||
       !aTarget)
     return E_INVALIDARG;
 
-  RefPtr<IAccessible> target;
-  mTargets[aTargetIndex]->GetNativeInterface(getter_AddRefs(target));
-  target.forget(aTarget);
+  AccessibleWrap* target =
+      static_cast<AccessibleWrap*>(mTargets[aTargetIndex].get());
+  *aTarget = static_cast<IAccessible*>(target);
+  (*aTarget)->AddRef();
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleRelation::get_targets(long aMaxTargets, IUnknown** aTargets,
                                    long* aNTargets) {
   if (!aNTargets || !aTargets) return E_INVALIDARG;
--- a/accessible/windows/ia2/ia2AccessibleTable.cpp
+++ b/accessible/windows/ia2/ia2AccessibleTable.cpp
@@ -54,80 +54,74 @@ ia2AccessibleTable::get_accessibleAt(lon
   return get_cellAt(aRowIdx, aColIdx, aAccessible);
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_caption(IUnknown** aAccessible) {
   if (!aAccessible) return E_INVALIDARG;
 
   *aAccessible = nullptr;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  AccessibleWrap* caption = static_cast<AccessibleWrap*>(table->Caption());
+  AccessibleWrap* caption = static_cast<AccessibleWrap*>(mTable->Caption());
   if (!caption) return S_FALSE;
 
-  RefPtr<IAccessible> result;
-  caption->GetNativeInterface(getter_AddRefs(result));
-  result.forget(aAccessible);
+  (*aAccessible = static_cast<IAccessible*>(caption))->AddRef();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx,
                                    long* aChildIdx) {
   if (!aChildIdx) return E_INVALIDARG;
 
   *aChildIdx = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
-      static_cast<uint32_t>(aRowIdx) >= table->RowCount() ||
-      static_cast<uint32_t>(aColIdx) >= table->ColCount())
+      static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
+      static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
-  *aChildIdx = table->CellIndexAt(aRowIdx, aColIdx);
+  *aChildIdx = mTable->CellIndexAt(aRowIdx, aColIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription) {
   if (!aDescription) return E_INVALIDARG;
 
   *aDescription = nullptr;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
   nsAutoString descr;
-  table->ColDescription(aColIdx, descr);
+  mTable->ColDescription(aColIdx, descr);
   if (descr.IsEmpty()) return S_FALSE;
 
   *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
   return *aDescription ? S_OK : E_OUTOFMEMORY;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx,
                                        long* aSpan) {
   if (!aSpan) return E_INVALIDARG;
 
   *aSpan = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
-      static_cast<uint32_t>(aRowIdx) >= table->RowCount() ||
-      static_cast<uint32_t>(aColIdx) >= table->ColCount())
+      static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
+      static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
-  *aSpan = table->ColExtentAt(aRowIdx, aColIdx);
+  *aSpan = mTable->ColExtentAt(aRowIdx, aColIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnHeader(IAccessibleTable** aAccessibleTable,
                                      long* aStartingRowIndex) {
   if (!aAccessibleTable || !aStartingRowIndex) return E_INVALIDARG;
 
@@ -136,119 +130,112 @@ ia2AccessibleTable::get_columnHeader(IAc
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_columnIndex(long aCellIdx, long* aColIdx) {
   if (!aColIdx) return E_INVALIDARG;
 
   *aColIdx = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   if (aCellIdx < 0) {
     return E_INVALIDARG;
   }
 
-  long colIdx = table->ColIndexAt(aCellIdx);
+  long colIdx = mTable->ColIndexAt(aCellIdx);
   if (colIdx == -1) {  // Indicates an error.
     return E_INVALIDARG;
   }
 
   *aColIdx = colIdx;
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nColumns(long* aColCount) {
   if (!aColCount) return E_INVALIDARG;
 
   *aColCount = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  *aColCount = table->ColCount();
+  *aColCount = mTable->ColCount();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nRows(long* aRowCount) {
   if (!aRowCount) return E_INVALIDARG;
 
   *aRowCount = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  *aRowCount = table->RowCount();
+  *aRowCount = mTable->RowCount();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nSelectedChildren(long* aChildCount) {
   return get_nSelectedCells(aChildCount);
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nSelectedColumns(long* aColCount) {
   if (!aColCount) return E_INVALIDARG;
 
   *aColCount = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  *aColCount = table->SelectedColCount();
+  *aColCount = mTable->SelectedColCount();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nSelectedRows(long* aRowCount) {
   if (!aRowCount) return E_INVALIDARG;
 
   *aRowCount = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  *aRowCount = table->SelectedRowCount();
+  *aRowCount = mTable->SelectedRowCount();
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription) {
   if (!aDescription) return E_INVALIDARG;
 
   *aDescription = nullptr;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
 
   nsAutoString descr;
-  table->RowDescription(aRowIdx, descr);
+  mTable->RowDescription(aRowIdx, descr);
   if (descr.IsEmpty()) return S_FALSE;
 
   *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
   return *aDescription ? S_OK : E_OUTOFMEMORY;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan) {
   if (!aSpan) return E_INVALIDARG;
 
   *aSpan = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
-      static_cast<uint32_t>(aRowIdx) >= table->RowCount() ||
-      static_cast<uint32_t>(aColIdx) >= table->ColCount())
+      static_cast<uint32_t>(aRowIdx) >= mTable->RowCount() ||
+      static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
-  *aSpan = table->RowExtentAt(aRowIdx, aColIdx);
+  *aSpan = mTable->RowExtentAt(aRowIdx, aColIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowHeader(IAccessibleTable** aAccessibleTable,
                                   long* aStartingColumnIndex) {
   if (!aAccessibleTable || !aStartingColumnIndex) return E_INVALIDARG;
 
@@ -257,44 +244,42 @@ ia2AccessibleTable::get_rowHeader(IAcces
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowIndex(long aCellIdx, long* aRowIdx) {
   if (!aRowIdx) return E_INVALIDARG;
 
   *aRowIdx = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   if (aCellIdx < 0) {
     return E_INVALIDARG;
   }
 
-  long rowIdx = table->RowIndexAt(aCellIdx);
+  long rowIdx = mTable->RowIndexAt(aCellIdx);
   if (rowIdx == -1) {  // Indicates an error.
     return E_INVALIDARG;
   }
 
   *aRowIdx = rowIdx;
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedChildren(long aMaxChildren, long** aChildren,
                                          long* aNChildren) {
   if (!aChildren || !aNChildren) return E_INVALIDARG;
 
   *aChildren = nullptr;
   *aNChildren = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   AutoTArray<uint32_t, 30> cellIndices;
-  table->SelectedCellIndices(&cellIndices);
+  mTable->SelectedCellIndices(&cellIndices);
 
   uint32_t maxCells = cellIndices.Length();
   if (maxCells == 0) return S_FALSE;
 
   *aChildren = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCells));
   *aNChildren = maxCells;
   for (uint32_t i = 0; i < maxCells; i++) (*aChildren)[i] = cellIndices[i];
 
@@ -326,104 +311,97 @@ ia2AccessibleTable::get_summary(IUnknown
   return S_FALSE;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_isColumnSelected(long aColIdx, boolean* aIsSelected) {
   if (!aIsSelected) return E_INVALIDARG;
 
   *aIsSelected = false;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
-  *aIsSelected = table->IsColSelected(aColIdx);
+  *aIsSelected = mTable->IsColSelected(aColIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected) {
   if (!aIsSelected) return E_INVALIDARG;
 
   *aIsSelected = false;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
 
-  *aIsSelected = table->IsRowSelected(aRowIdx);
+  *aIsSelected = mTable->IsRowSelected(aRowIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx,
                                    boolean* aIsSelected) {
   if (!aIsSelected) return E_INVALIDARG;
 
   *aIsSelected = false;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   if (aRowIdx < 0 || aColIdx < 0 ||
-      static_cast<uint32_t>(aColIdx) >= table->ColCount() ||
-      static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+      static_cast<uint32_t>(aColIdx) >= mTable->ColCount() ||
+      static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
 
-  *aIsSelected = table->IsCellSelected(aRowIdx, aColIdx);
+  *aIsSelected = mTable->IsCellSelected(aRowIdx, aColIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::selectRow(long aRowIdx) {
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
 
-  table->SelectRow(aRowIdx);
+  mTable->SelectRow(aRowIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::selectColumn(long aColIdx) {
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
-  table->SelectCol(aColIdx);
+  mTable->SelectCol(aColIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::unselectRow(long aRowIdx) {
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
+  if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= mTable->RowCount())
     return E_INVALIDARG;
 
-  table->UnselectRow(aRowIdx);
+  mTable->UnselectRow(aRowIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::unselectColumn(long aColIdx) {
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
+  if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= mTable->ColCount())
     return E_INVALIDARG;
 
-  table->UnselectCol(aColIdx);
+  mTable->UnselectCol(aColIdx);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_rowColumnExtentsAtIndex(long aCellIdx, long* aRowIdx,
                                                 long* aColIdx,
                                                 long* aRowExtents,
                                                 long* aColExtents,
@@ -431,34 +409,33 @@ ia2AccessibleTable::get_rowColumnExtents
   if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
     return E_INVALIDARG;
 
   *aRowIdx = 0;
   *aColIdx = 0;
   *aRowExtents = 0;
   *aColExtents = 0;
   *aIsSelected = false;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   if (aCellIdx < 0) {
     return E_INVALIDARG;
   }
 
   int32_t colIdx = 0, rowIdx = 0;
-  table->RowAndColIndicesAt(aCellIdx, &rowIdx, &colIdx);
+  mTable->RowAndColIndicesAt(aCellIdx, &rowIdx, &colIdx);
   if (rowIdx == -1 || colIdx == -1) {  // Indicates an error.
     return E_INVALIDARG;
   }
 
   *aRowIdx = rowIdx;
   *aColIdx = colIdx;
-  *aRowExtents = table->RowExtentAt(rowIdx, colIdx);
-  *aColExtents = table->ColExtentAt(rowIdx, colIdx);
-  *aIsSelected = table->IsCellSelected(rowIdx, colIdx);
+  *aRowExtents = mTable->RowExtentAt(rowIdx, colIdx);
+  *aColExtents = mTable->ColExtentAt(rowIdx, colIdx);
+  *aIsSelected = mTable->IsCellSelected(rowIdx, colIdx);
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_modelChange(IA2TableModelChange* aModelChange) {
   return E_NOTIMPL;
 }
@@ -467,80 +444,74 @@ ia2AccessibleTable::get_modelChange(IA2T
 // IAccessibleTable2
 
 STDMETHODIMP
 ia2AccessibleTable::get_cellAt(long aRowIdx, long aColIdx, IUnknown** aCell) {
   if (!aCell) return E_INVALIDARG;
 
   *aCell = nullptr;
 
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   AccessibleWrap* cell =
-      static_cast<AccessibleWrap*>(table->CellAt(aRowIdx, aColIdx));
+      static_cast<AccessibleWrap*>(mTable->CellAt(aRowIdx, aColIdx));
   if (!cell) return E_INVALIDARG;
 
-  RefPtr<IAccessible> result;
-  cell->GetNativeInterface(getter_AddRefs(result));
-  result.forget(aCell);
+  (*aCell = static_cast<IAccessible*>(cell))->AddRef();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_nSelectedCells(long* aCellCount) {
   if (!aCellCount) return E_INVALIDARG;
 
   *aCellCount = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
-  *aCellCount = table->SelectedCellCount();
+  *aCellCount = mTable->SelectedCellCount();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedCells(IUnknown*** aCells,
                                       long* aNSelectedCells) {
   if (!aCells || !aNSelectedCells) return E_INVALIDARG;
 
   *aCells = nullptr;
   *aNSelectedCells = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   AutoTArray<LocalAccessible*, 30> cells;
-  table->SelectedCells(&cells);
+  mTable->SelectedCells(&cells);
   if (cells.IsEmpty()) return S_FALSE;
 
   *aCells = static_cast<IUnknown**>(
       ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length()));
   if (!*aCells) return E_OUTOFMEMORY;
 
   for (uint32_t i = 0; i < cells.Length(); i++) {
-    RefPtr<IAccessible> cell;
-    cells[i]->GetNativeInterface(getter_AddRefs(cell));
-    cell.forget(&(*aCells)[i]);
+    (*aCells)[i] =
+        static_cast<IAccessible*>(static_cast<AccessibleWrap*>(cells[i]));
+    ((*aCells)[i])->AddRef();
   }
 
   *aNSelectedCells = cells.Length();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns) {
   if (!aColumns || !aNColumns) return E_INVALIDARG;
 
   *aColumns = nullptr;
   *aNColumns = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   AutoTArray<uint32_t, 30> colIndices;
-  table->SelectedColIndices(&colIndices);
+  mTable->SelectedColIndices(&colIndices);
 
   uint32_t maxCols = colIndices.Length();
   if (maxCols == 0) return S_FALSE;
 
   *aColumns = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCols));
   *aNColumns = maxCols;
   for (uint32_t i = 0; i < maxCols; i++) (*aColumns)[i] = colIndices[i];
 
@@ -548,21 +519,20 @@ ia2AccessibleTable::get_selectedColumns(
 }
 
 STDMETHODIMP
 ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows) {
   if (!aRows || !aNRows) return E_INVALIDARG;
 
   *aRows = nullptr;
   *aNRows = 0;
-  TableAccessible* table = TableAcc();
-  if (!table) return CO_E_OBJNOTCONNECTED;
+  if (!mTable) return CO_E_OBJNOTCONNECTED;
 
   AutoTArray<uint32_t, 30> rowIndices;
-  table->SelectedRowIndices(&rowIndices);
+  mTable->SelectedRowIndices(&rowIndices);
 
   uint32_t maxRows = rowIndices.Length();
   if (maxRows == 0) return S_FALSE;
 
   *aRows = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxRows));
   *aNRows = maxRows;
   for (uint32_t i = 0; i < maxRows; i++) (*aRows)[i] = rowIndices[i];
 
--- a/accessible/windows/ia2/ia2AccessibleTable.h
+++ b/accessible/windows/ia2/ia2AccessibleTable.h
@@ -159,17 +159,14 @@ class ia2AccessibleTable : public IAcces
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectedRows(
       /* [out, size_is(,*nRows)] */ long** selectedRows,
       /* [out, retval] */ long* nRows);
 
  protected:
   ia2AccessibleTable(TableAccessible* aTable) : mTable(aTable) {}
 
   TableAccessible* mTable;
-
- private:
-  TableAccessible* TableAcc() { return mTable; }
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleTableCell.cpp
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.cpp
@@ -40,160 +40,148 @@ ia2AccessibleTableCell::QueryInterface(R
 ////////////////////////////////////////////////////////////////////////////////
 // IAccessibleTableCell
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_table(IUnknown** aTable) {
   if (!aTable) return E_INVALIDARG;
 
   *aTable = nullptr;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
-  TableAccessible* table = tableCell->Table();
+  TableAccessible* table = mTableCell->Table();
   if (!table) return E_FAIL;
 
   AccessibleWrap* wrap = static_cast<AccessibleWrap*>(table->AsAccessible());
-  RefPtr<IAccessibleTable> result;
-  wrap->GetNativeInterface(getter_AddRefs(result));
-  result.forget(aTable);
+  *aTable = static_cast<IAccessible*>(wrap);
+  (*aTable)->AddRef();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_columnExtent(long* aSpan) {
   if (!aSpan) return E_INVALIDARG;
 
   *aSpan = 0;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
-  *aSpan = tableCell->ColExtent();
+  *aSpan = mTableCell->ColExtent();
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles,
                                               long* aNColumnHeaderCells) {
   if (!aCellAccessibles || !aNColumnHeaderCells) return E_INVALIDARG;
 
   *aCellAccessibles = nullptr;
   *aNColumnHeaderCells = 0;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
   AutoTArray<LocalAccessible*, 10> cells;
-  tableCell->ColHeaderCells(&cells);
+  mTableCell->ColHeaderCells(&cells);
 
   *aNColumnHeaderCells = cells.Length();
   *aCellAccessibles = static_cast<IUnknown**>(
       ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length()));
 
   if (!*aCellAccessibles) return E_OUTOFMEMORY;
 
   for (uint32_t i = 0; i < cells.Length(); i++) {
     AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]);
-    RefPtr<IAccessible> iaCell;
-    cell->GetNativeInterface(getter_AddRefs(iaCell));
-    iaCell.forget(&(*aCellAccessibles)[i]);
+    (*aCellAccessibles)[i] = static_cast<IAccessible*>(cell);
+    (*aCellAccessibles)[i]->AddRef();
   }
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_columnIndex(long* aColIdx) {
   if (!aColIdx) return E_INVALIDARG;
 
   *aColIdx = -1;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
-  *aColIdx = tableCell->ColIdx();
+  *aColIdx = mTableCell->ColIdx();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowExtent(long* aSpan) {
   if (!aSpan) return E_INVALIDARG;
 
   *aSpan = 0;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
-  *aSpan = tableCell->RowExtent();
+  *aSpan = mTableCell->RowExtent();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles,
                                            long* aNRowHeaderCells) {
   if (!aCellAccessibles || !aNRowHeaderCells) return E_INVALIDARG;
 
   *aCellAccessibles = nullptr;
   *aNRowHeaderCells = 0;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
   AutoTArray<LocalAccessible*, 10> cells;
-  tableCell->RowHeaderCells(&cells);
+  mTableCell->RowHeaderCells(&cells);
 
   *aNRowHeaderCells = cells.Length();
   *aCellAccessibles = static_cast<IUnknown**>(
       ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length()));
   if (!*aCellAccessibles) return E_OUTOFMEMORY;
 
   for (uint32_t i = 0; i < cells.Length(); i++) {
     AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]);
-    RefPtr<IAccessible> iaCell;
-    cell->GetNativeInterface(getter_AddRefs(iaCell));
-    iaCell.forget(&(*aCellAccessibles)[i]);
+    (*aCellAccessibles)[i] = static_cast<IAccessible*>(cell);
+    (*aCellAccessibles)[i]->AddRef();
   }
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowIndex(long* aRowIdx) {
   if (!aRowIdx) return E_INVALIDARG;
 
   *aRowIdx = -1;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
-  *aRowIdx = tableCell->RowIdx();
+  *aRowIdx = mTableCell->RowIdx();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_rowColumnExtents(long* aRowIdx, long* aColIdx,
                                              long* aRowExtents,
                                              long* aColExtents,
                                              boolean* aIsSelected) {
   if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected)
     return E_INVALIDARG;
 
   *aRowIdx = *aColIdx = *aRowExtents = *aColExtents = 0;
   *aIsSelected = false;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
-  *aRowIdx = tableCell->RowIdx();
-  *aColIdx = tableCell->ColIdx();
-  *aRowExtents = tableCell->RowExtent();
-  *aColExtents = tableCell->ColExtent();
-  *aIsSelected = tableCell->Selected();
+  *aRowIdx = mTableCell->RowIdx();
+  *aColIdx = mTableCell->ColIdx();
+  *aRowExtents = mTableCell->RowExtent();
+  *aColExtents = mTableCell->ColExtent();
+  *aIsSelected = mTableCell->Selected();
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleTableCell::get_isSelected(boolean* aIsSelected) {
   if (!aIsSelected) return E_INVALIDARG;
 
   *aIsSelected = false;
-  TableCellAccessible* tableCell = CellAcc();
-  if (!tableCell) return CO_E_OBJNOTCONNECTED;
+  if (!mTableCell) return CO_E_OBJNOTCONNECTED;
 
-  *aIsSelected = tableCell->Selected();
+  *aIsSelected = mTableCell->Selected();
   return S_OK;
 }
--- a/accessible/windows/ia2/ia2AccessibleTableCell.h
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.h
@@ -54,17 +54,14 @@ class ia2AccessibleTableCell : public IA
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_isSelected(
       /* [out, retval] */ boolean* isSelected);
 
  protected:
   ia2AccessibleTableCell(TableCellAccessible* aTableCell)
       : mTableCell(aTableCell) {}
 
   TableCellAccessible* mTableCell;
-
- private:
-  TableCellAccessible* CellAcc() { return mTableCell; }
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/ia2/ia2AccessibleText.cpp
+++ b/accessible/windows/ia2/ia2AccessibleText.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=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 "ia2Accessible.h"
 #include "ia2AccessibleText.h"
 
 #include "AccessibleText_i.c"
 
 #include "HyperTextAccessibleWrap.h"
 #include "HyperTextAccessible-inl.h"
 #include "ProxyWrappers.h"
 #include "mozilla/ClearOnShutdown.h"
@@ -18,76 +17,69 @@
 using namespace mozilla::a11y;
 
 StaticRefPtr<HyperTextAccessibleWrap> ia2AccessibleText::sLastTextChangeAcc;
 StaticAutoPtr<nsString> ia2AccessibleText::sLastTextChangeString;
 uint32_t ia2AccessibleText::sLastTextChangeStart = 0;
 uint32_t ia2AccessibleText::sLastTextChangeEnd = 0;
 bool ia2AccessibleText::sLastTextChangeWasInsert = false;
 
-HyperTextAccessibleWrap* ia2AccessibleText::TextAcc() {
-  // XXX This first static_cast is a necessary hack until we get rid of the
-  // inheritance of HyperTextAccessibleWrap.
-  auto wrap = static_cast<HyperTextAccessibleWrap*>(this);
-  AccessibleWrap* acc = static_cast<MsaaAccessible*>(wrap)->LocalAcc();
-  return static_cast<HyperTextAccessibleWrap*>(acc);
-}
-
 // IAccessibleText
 
 STDMETHODIMP
 ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   return textAcc->AddToSelection(aStartOffset, aEndOffset) ? S_OK
                                                            : E_INVALIDARG;
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_attributes(long aOffset, long* aStartOffset,
                                   long* aEndOffset, BSTR* aTextAttributes) {
   if (!aStartOffset || !aEndOffset || !aTextAttributes) return E_INVALIDARG;
 
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aTextAttributes = nullptr;
 
   int32_t startOffset = 0, endOffset = 0;
   HRESULT hr;
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!textAcc->IsProxy());
 
   nsCOMPtr<nsIPersistentProperties> attributes =
       textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset);
 
-  hr = ia2Accessible::ConvertToIA2Attributes(attributes, aTextAttributes);
+  hr = AccessibleWrap::ConvertToIA2Attributes(attributes, aTextAttributes);
   if (FAILED(hr)) return hr;
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_caretOffset(long* aOffset) {
   if (!aOffset) return E_INVALIDARG;
 
   *aOffset = -1;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!textAcc->IsProxy());
 
   *aOffset = textAcc->CaretOffset();
 
   return *aOffset != -1 ? S_OK : S_FALSE;
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_characterExtents(long aOffset,
@@ -97,40 +89,40 @@ ia2AccessibleText::get_characterExtents(
   if (!aX || !aY || !aWidth || !aHeight) return E_INVALIDARG;
   *aX = *aY = *aWidth = *aHeight = 0;
 
   uint32_t geckoCoordType =
       (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
           ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
           : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
   nsIntRect rect;
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   rect = textAcc->CharBounds(aOffset, geckoCoordType);
 
   // Can't use GetRect() because of long vs. int32_t mismatch
   *aX = rect.X();
   *aY = rect.Y();
   *aWidth = rect.Width();
   *aHeight = rect.Height();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_nSelections(long* aNSelections) {
   if (!aNSelections) return E_INVALIDARG;
   *aNSelections = 0;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!textAcc->IsProxy());
 
   *aNSelections = textAcc->SelectionCount();
 
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_offsetAtPoint(long aX, long aY,
@@ -139,39 +131,39 @@ ia2AccessibleText::get_offsetAtPoint(lon
   if (!aOffset) return E_INVALIDARG;
   *aOffset = 0;
 
   uint32_t geckoCoordType =
       (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
           ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
           : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!textAcc->IsProxy());
 
   *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType);
 
   return *aOffset == -1 ? S_FALSE : S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_selection(long aSelectionIndex, long* aStartOffset,
                                  long* aEndOffset) {
   if (!aStartOffset || !aEndOffset) return E_INVALIDARG;
   *aStartOffset = *aEndOffset = 0;
 
   int32_t startOffset = 0, endOffset = 0;
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!textAcc->IsProxy());
 
   if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) {
     return E_INVALIDARG;
   }
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
   return S_OK;
@@ -179,21 +171,21 @@ ia2AccessibleText::get_selection(long aS
 
 STDMETHODIMP
 ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText) {
   if (!aText) return E_INVALIDARG;
 
   *aText = nullptr;
 
   nsAutoString text;
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) {
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  MOZ_ASSERT(!textAcc->IsProxy());
 
   if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) {
     return E_INVALIDARG;
   }
 
   textAcc->TextSubstring(aStartOffset, aEndOffset, text);
 
   if (text.IsEmpty()) return S_FALSE;
@@ -207,18 +199,18 @@ ia2AccessibleText::get_textBeforeOffset(
                                         enum IA2TextBoundaryType aBoundaryType,
                                         long* aStartOffset, long* aEndOffset,
                                         BSTR* aText) {
   if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG;
 
   *aStartOffset = *aEndOffset = 0;
   *aText = nullptr;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
 
   nsAutoString text;
   int32_t startOffset = 0, endOffset = 0;
 
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
@@ -247,18 +239,18 @@ ia2AccessibleText::get_textAfterOffset(l
                                        long* aStartOffset, long* aEndOffset,
                                        BSTR* aText) {
   if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG;
 
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aText = nullptr;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
 
   nsAutoString text;
   int32_t startOffset = 0, endOffset = 0;
 
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
@@ -285,18 +277,18 @@ ia2AccessibleText::get_textAtOffset(long
                                     enum IA2TextBoundaryType aBoundaryType,
                                     long* aStartOffset, long* aEndOffset,
                                     BSTR* aText) {
   if (!aStartOffset || !aEndOffset || !aText) return E_INVALIDARG;
 
   *aStartOffset = *aEndOffset = 0;
   *aText = nullptr;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
 
   nsAutoString text;
   int32_t startOffset = 0, endOffset = 0;
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
     endOffset = textAcc->CharacterCount();
@@ -314,86 +306,92 @@ ia2AccessibleText::get_textAtOffset(long
   if (text.IsEmpty()) return S_FALSE;
 
   *aText = ::SysAllocStringLen(text.get(), text.Length());
   return *aText ? S_OK : E_OUTOFMEMORY;
 }
 
 STDMETHODIMP
 ia2AccessibleText::removeSelection(long aSelectionIndex) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   return textAcc->RemoveFromSelection(aSelectionIndex) ? S_OK : E_INVALIDARG;
 }
 
 STDMETHODIMP
 ia2AccessibleText::setCaretOffset(long aOffset) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidOffset(aOffset)) return E_INVALIDARG;
 
   textAcc->SetCaretOffset(aOffset);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset,
                                 long aEndOffset) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset,
                                        aEndOffset)
              ? S_OK
              : E_INVALIDARG;
 }
 
 STDMETHODIMP
 ia2AccessibleText::get_nCharacters(long* aNCharacters) {
   if (!aNCharacters) return E_INVALIDARG;
   *aNCharacters = 0;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   *aNCharacters = textAcc->CharacterCount();
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex,
                                      enum IA2ScrollType aScrollType) {
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG;
 
   textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType);
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex,
                                           enum IA2CoordinateType aCoordType,
                                           long aX, long aY) {
   uint32_t geckoCoordType =
       (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE)
           ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
           : nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
 
-  HyperTextAccessible* textAcc = TextAcc();
-  if (!textAcc) return CO_E_OBJNOTCONNECTED;
-  MOZ_ASSERT(!textAcc->IsProxy());
+  MOZ_ASSERT(!HyperTextProxyFor(this));
+
+  HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
+  if (textAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
 
   if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) return E_INVALIDARG;
 
   textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex, geckoCoordType, aX,
                                   aY);
   return S_OK;
 }
 
@@ -413,17 +411,17 @@ HRESULT
 ia2AccessibleText::GetModifiedText(bool aGetInsertedText,
                                    IA2TextSegment* aText) {
   if (!aText) return E_INVALIDARG;
 
   if (!sLastTextChangeAcc) return S_OK;
 
   if (aGetInsertedText != sLastTextChangeWasInsert) return S_OK;
 
-  if (sLastTextChangeAcc != TextAcc()) return S_OK;
+  if (sLastTextChangeAcc != this) return S_OK;
 
   aText->start = sLastTextChangeStart;
   aText->end = sLastTextChangeEnd;
 
   if (sLastTextChangeString->IsEmpty()) return S_FALSE;
 
   aText->text = ::SysAllocStringLen(sLastTextChangeString->get(),
                                     sLastTextChangeString->Length());
--- a/accessible/windows/ia2/ia2AccessibleText.h
+++ b/accessible/windows/ia2/ia2AccessibleText.h
@@ -121,17 +121,16 @@ class ia2AccessibleText : public IAccess
   static bool sLastTextChangeWasInsert;
   static uint32_t sLastTextChangeStart;
   static uint32_t sLastTextChangeEnd;
 
  private:
   HRESULT GetModifiedText(bool aGetInsertedText, IA2TextSegment* aNewText);
   AccessibleTextBoundary GetGeckoTextBoundary(
       enum IA2TextBoundaryType coordinateType);
-  HyperTextAccessibleWrap* TextAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #define FORWARD_IACCESSIBLETEXT(Class)                                         \
   virtual HRESULT STDMETHODCALLTYPE addSelection(long startOffset,             \
                                                  long endOffset) {             \
--- a/accessible/windows/ia2/ia2AccessibleValue.cpp
+++ b/accessible/windows/ia2/ia2AccessibleValue.cpp
@@ -12,33 +12,29 @@
 #include "AccessibleWrap.h"
 #include "LocalAccessible-inl.h"
 #include "IUnknownImpl.h"
 
 #include "mozilla/FloatingPoint.h"
 
 using namespace mozilla::a11y;
 
-AccessibleWrap* ia2AccessibleValue::LocalAcc() {
-  return static_cast<MsaaAccessible*>(this)->LocalAcc();
-}
-
 // IUnknown
 
 STDMETHODIMP
 ia2AccessibleValue::QueryInterface(REFIID iid, void** ppv) {
   if (!ppv) return E_INVALIDARG;
 
   *ppv = nullptr;
 
   if (IID_IAccessibleValue == iid) {
-    AccessibleWrap* valueAcc = LocalAcc();
-    if (valueAcc && valueAcc->HasNumericValue()) {
-      RefPtr<IAccessibleValue> result = this;
-      result.forget(ppv);
+    AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+    if (valueAcc->HasNumericValue()) {
+      *ppv = static_cast<IAccessibleValue*>(this);
+      valueAcc->AddRef();
       return S_OK;
     }
 
     return E_NOINTERFACE;
   }
 
   return E_NOINTERFACE;
 }
@@ -46,79 +42,78 @@ ia2AccessibleValue::QueryInterface(REFII
 // IAccessibleValue
 
 STDMETHODIMP
 ia2AccessibleValue::get_currentValue(VARIANT* aCurrentValue) {
   if (!aCurrentValue) return E_INVALIDARG;
 
   VariantInit(aCurrentValue);
 
-  AccessibleWrap* valueAcc = LocalAcc();
-  if (!valueAcc) {
+  AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+  double currentValue;
+  MOZ_ASSERT(!valueAcc->IsProxy());
+  if (valueAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  double currentValue;
-  MOZ_ASSERT(!valueAcc->IsProxy());
 
   currentValue = valueAcc->CurValue();
 
   if (IsNaN(currentValue)) return S_FALSE;
 
   aCurrentValue->vt = VT_R8;
   aCurrentValue->dblVal = currentValue;
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleValue::setCurrentValue(VARIANT aValue) {
   if (aValue.vt != VT_R8) return E_INVALIDARG;
 
-  AccessibleWrap* valueAcc = LocalAcc();
-  if (!valueAcc) {
-    return CO_E_OBJNOTCONNECTED;
-  }
+  AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
   MOZ_ASSERT(!valueAcc->IsProxy());
 
+  if (valueAcc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
   return valueAcc->SetCurValue(aValue.dblVal) ? S_OK : E_FAIL;
 }
 
 STDMETHODIMP
 ia2AccessibleValue::get_maximumValue(VARIANT* aMaximumValue) {
   if (!aMaximumValue) return E_INVALIDARG;
 
   VariantInit(aMaximumValue);
 
-  AccessibleWrap* valueAcc = LocalAcc();
-  if (!valueAcc) {
+  AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+  double maximumValue;
+  MOZ_ASSERT(!valueAcc->IsProxy());
+  if (valueAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  double maximumValue;
-  MOZ_ASSERT(!valueAcc->IsProxy());
 
   maximumValue = valueAcc->MaxValue();
 
   if (IsNaN(maximumValue)) return S_FALSE;
 
   aMaximumValue->vt = VT_R8;
   aMaximumValue->dblVal = maximumValue;
   return S_OK;
 }
 
 STDMETHODIMP
 ia2AccessibleValue::get_minimumValue(VARIANT* aMinimumValue) {
   if (!aMinimumValue) return E_INVALIDARG;
 
   VariantInit(aMinimumValue);
 
-  AccessibleWrap* valueAcc = LocalAcc();
-  if (!valueAcc) {
+  AccessibleWrap* valueAcc = static_cast<AccessibleWrap*>(this);
+  double minimumValue;
+  MOZ_ASSERT(!valueAcc->IsProxy());
+  if (valueAcc->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
-  double minimumValue;
-  MOZ_ASSERT(!valueAcc->IsProxy());
 
   minimumValue = valueAcc->MinValue();
 
   if (IsNaN(minimumValue)) return S_FALSE;
 
   aMinimumValue->vt = VT_R8;
   aMinimumValue->dblVal = minimumValue;
   return S_OK;
--- a/accessible/windows/ia2/ia2AccessibleValue.h
+++ b/accessible/windows/ia2/ia2AccessibleValue.h
@@ -7,17 +7,16 @@
 
 #ifndef _ACCESSIBLE_VALUE_H
 #define _ACCESSIBLE_VALUE_H
 
 #include "AccessibleValue.h"
 
 namespace mozilla {
 namespace a11y {
-class AccessibleWrap;
 
 class ia2AccessibleValue : public IAccessibleValue {
  public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessibleValue
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_currentValue(
@@ -26,17 +25,14 @@ class ia2AccessibleValue : public IAcces
   virtual HRESULT STDMETHODCALLTYPE setCurrentValue(
       /* [in] */ VARIANT value);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_maximumValue(
       /* [retval][out] */ VARIANT* maximumValue);
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_minimumValue(
       /* [retval][out] */ VARIANT* minimumValue);
-
- private:
-  AccessibleWrap* LocalAcc();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -1,47 +1,86 @@
 /* -*- 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 "AccessibleWrap.h"
+#include "LocalAccessible-inl.h"
 
+#include "Compatibility.h"
+#include "DocAccessible-inl.h"
 #include "mozilla/a11y/DocAccessibleParent.h"
-#include "AccEvent.h"
 #include "EnumVariant.h"
 #include "GeckoCustom.h"
 #include "nsAccUtils.h"
+#include "nsCoreUtils.h"
 #include "nsIAccessibleEvent.h"
-#include "nsIWidget.h"
 #include "nsWindowsHelpers.h"
+#include "nsWinUtils.h"
 #include "mozilla/a11y/RemoteAccessible.h"
 #include "ProxyWrappers.h"
 #include "ServiceProvider.h"
+#include "Relation.h"
+#include "Role.h"
+#include "RootAccessible.h"
 #include "sdnAccessible.h"
+#include "States.h"
+
+#ifdef A11Y_LOG
+#  include "Logging.h"
+#endif
 
+#include "nsIFrame.h"
+#include "nsIScrollableFrame.h"
+#include "mozilla/PresShell.h"
+#include "mozilla/dom/NodeInfo.h"
+#include "mozilla/dom/BrowserParent.h"
+#include "nsNameSpaceManager.h"
+#include "nsTextFormatter.h"
+#include "nsView.h"
+#include "nsViewManager.h"
+#include "nsArrayUtils.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/ReverseIterator.h"
 #include "mozilla/mscom/AsyncInvoker.h"
 
+#include "oleacc.h"
+
 using namespace mozilla;
 using namespace mozilla::a11y;
 
+const uint32_t USE_ROLE_STRING = 0;
+
 /* For documentation of the accessibility architecture,
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
  */
 
+//#define DEBUG_LEAKS
+
+#ifdef DEBUG_LEAKS
+static gAccessibles = 0;
+#endif
+
 StaticAutoPtr<nsTArray<AccessibleWrap::HandlerControllerData>>
     AccessibleWrap::sHandlerControllers;
 
+static const VARIANT kVarChildIdSelf = {{{VT_I4}}};
+
+static const int32_t kIEnumVariantDisconnected = -1;
+
 ////////////////////////////////////////////////////////////////////////////////
 // AccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc)
     : LocalAccessible(aContent, aDoc) {}
 
+ITypeInfo* AccessibleWrap::gTypeInfo = nullptr;
+
 NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, LocalAccessible)
 
 void AccessibleWrap::Shutdown() {
   MsaaShutdown();
   LocalAccessible::Shutdown();
 }
 
 //-----------------------------------------------------
@@ -107,16 +146,841 @@ AccessibleWrap::QueryInterface(REFIID ii
   }
 
   if (nullptr == *ppv) return E_NOINTERFACE;
 
   (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
   return S_OK;
 }
 
+//-----------------------------------------------------
+// IAccessible methods
+//-----------------------------------------------------
+
+STDMETHODIMP
+AccessibleWrap::get_accParent(IDispatch __RPC_FAR* __RPC_FAR* ppdispParent) {
+  if (!ppdispParent) return E_INVALIDARG;
+
+  *ppdispParent = nullptr;
+
+  if (IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
+  LocalAccessible* xpParentAcc = LocalParent();
+  if (!xpParentAcc) return S_FALSE;
+
+  *ppdispParent = NativeAccessible(xpParentAcc);
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accChildCount(long __RPC_FAR* pcountChildren) {
+  if (!pcountChildren) return E_INVALIDARG;
+
+  *pcountChildren = 0;
+
+  if (IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
+  if (nsAccUtils::MustPrune(this)) return S_OK;
+
+  *pcountChildren = ChildCount();
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accChild(
+    /* [in] */ VARIANT varChild,
+    /* [retval][out] */ IDispatch __RPC_FAR* __RPC_FAR* ppdispChild) {
+  if (!ppdispChild) return E_INVALIDARG;
+
+  *ppdispChild = nullptr;
+  if (IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
+  // IAccessible::accChild is used to return this accessible or child accessible
+  // at the given index or to get an accessible by child ID in the case of
+  // document accessible.
+  // The getting an accessible by child ID is used by
+  // AccessibleObjectFromEvent() called by AT when AT handles our MSAA event.
+  bool isDefunct = false;
+  RefPtr<IAccessible> child = GetIAccessibleFor(varChild, &isDefunct);
+  if (!child) {
+    return E_INVALIDARG;
+  }
+
+  if (isDefunct) {
+    return CO_E_OBJNOTCONNECTED;
+  }
+
+  child.forget(ppdispChild);
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accName(
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ BSTR __RPC_FAR* pszName) {
+  if (!pszName || varChild.vt != VT_I4) return E_INVALIDARG;
+
+  *pszName = nullptr;
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->get_accName(kVarChildIdSelf, pszName);
+  }
+
+  nsAutoString name;
+  Name(name);
+
+  // The name was not provided, e.g. no alt attribute for an image. A screen
+  // reader may choose to invent its own accessible name, e.g. from an image src
+  // attribute. Refer to eNoNameOnPurpose return value.
+  if (name.IsVoid()) return S_FALSE;
+
+  *pszName = ::SysAllocStringLen(name.get(), name.Length());
+  if (!*pszName) return E_OUTOFMEMORY;
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accValue(
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ BSTR __RPC_FAR* pszValue) {
+  if (!pszValue) return E_INVALIDARG;
+
+  *pszValue = nullptr;
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->get_accValue(kVarChildIdSelf, pszValue);
+  }
+
+  nsAutoString value;
+  Value(value);
+
+  // See bug 438784: need to expose URL on doc's value attribute. For this,
+  // reverting part of fix for bug 425693 to make this MSAA method behave
+  // IAccessible2-style.
+  if (value.IsEmpty()) return S_FALSE;
+
+  *pszValue = ::SysAllocStringLen(value.get(), value.Length());
+  if (!*pszValue) return E_OUTOFMEMORY;
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accDescription(VARIANT varChild,
+                                   BSTR __RPC_FAR* pszDescription) {
+  if (!pszDescription) return E_INVALIDARG;
+
+  *pszDescription = nullptr;
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->get_accDescription(kVarChildIdSelf, pszDescription);
+  }
+
+  nsAutoString description;
+  Description(description);
+
+  *pszDescription =
+      ::SysAllocStringLen(description.get(), description.Length());
+  return *pszDescription ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accRole(
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ VARIANT __RPC_FAR* pvarRole) {
+  if (!pvarRole) return E_INVALIDARG;
+
+  VariantInit(pvarRole);
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->get_accRole(kVarChildIdSelf, pvarRole);
+  }
+
+  a11y::role geckoRole;
+#ifdef DEBUG
+  NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(this),
+               "Does not support Text when it should");
+#endif
+
+  geckoRole = Role();
+
+  uint32_t msaaRole = 0;
+
+#define ROLE(_geckoRole, stringRole, atkRole, macRole, macSubrole, _msaaRole, \
+             ia2Role, androidClass, nameRule)                                 \
+  case roles::_geckoRole:                                                     \
+    msaaRole = _msaaRole;                                                     \
+    break;
+
+  switch (geckoRole) {
+#include "RoleMap.h"
+    default:
+      MOZ_CRASH("Unknown role.");
+  }
+
+#undef ROLE
+
+  // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
+  // the MSAA role a ROLE_OUTLINEITEM for consistency and compatibility. We need
+  // this because ARIA has a role of "row" for both grid and treegrid
+  if (geckoRole == roles::ROW) {
+    LocalAccessible* xpParent = LocalParent();
+    if (xpParent && xpParent->Role() == roles::TREE_TABLE)
+      msaaRole = ROLE_SYSTEM_OUTLINEITEM;
+  }
+
+  // -- Try enumerated role
+  if (msaaRole != USE_ROLE_STRING) {
+    pvarRole->vt = VT_I4;
+    pvarRole->lVal = msaaRole;  // Normal enumerated role
+    return S_OK;
+  }
+
+  // -- Try BSTR role
+  // Could not map to known enumerated MSAA role like ROLE_BUTTON
+  // Use BSTR role to expose role attribute or tag name + namespace
+  nsIContent* content = GetContent();
+  if (!content) return E_FAIL;
+
+  if (content->IsElement()) {
+    nsAutoString roleString;
+    // Try the role attribute.
+    content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::role,
+                                  roleString);
+
+    if (roleString.IsEmpty()) {
+      // No role attribute (or it is an empty string).
+      // Use the tag name.
+      dom::Document* document = content->GetUncomposedDoc();
+      if (!document) return E_FAIL;
+
+      dom::NodeInfo* nodeInfo = content->NodeInfo();
+      nodeInfo->GetName(roleString);
+
+      // Only append name space if different from that of current document.
+      if (!nodeInfo->NamespaceEquals(document->GetDefaultNamespaceID())) {
+        nsAutoString nameSpaceURI;
+        nodeInfo->GetNamespaceURI(nameSpaceURI);
+        roleString += u", "_ns + nameSpaceURI;
+      }
+    }
+
+    if (!roleString.IsEmpty()) {
+      pvarRole->vt = VT_BSTR;
+      pvarRole->bstrVal = ::SysAllocString(roleString.get());
+      return S_OK;
+    }
+  }
+
+  return E_FAIL;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accState(
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ VARIANT __RPC_FAR* pvarState) {
+  if (!pvarState) return E_INVALIDARG;
+
+  VariantInit(pvarState);
+  pvarState->vt = VT_I4;
+  pvarState->lVal = 0;
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->get_accState(kVarChildIdSelf, pvarState);
+  }
+
+  // MSAA only has 31 states and the lowest 31 bits of our state bit mask
+  // are the same states as MSAA.
+  // Note: we map the following Gecko states to different MSAA states:
+  //   REQUIRED -> ALERT_LOW
+  //   ALERT -> ALERT_MEDIUM
+  //   INVALID -> ALERT_HIGH
+  //   CHECKABLE -> MARQUEED
+
+  uint64_t state = State();
+
+  uint32_t msaaState = 0;
+  nsAccUtils::To32States(state, &msaaState, nullptr);
+  pvarState->lVal = msaaState;
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accHelp(
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ BSTR __RPC_FAR* pszHelp) {
+  if (!pszHelp) return E_INVALIDARG;
+
+  *pszHelp = nullptr;
+  return S_FALSE;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accHelpTopic(
+    /* [out] */ BSTR __RPC_FAR* pszHelpFile,
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ long __RPC_FAR* pidTopic) {
+  if (!pszHelpFile || !pidTopic) return E_INVALIDARG;
+
+  *pszHelpFile = nullptr;
+  *pidTopic = 0;
+  return S_FALSE;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accKeyboardShortcut(
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ BSTR __RPC_FAR* pszKeyboardShortcut) {
+  if (!pszKeyboardShortcut) return E_INVALIDARG;
+  *pszKeyboardShortcut = nullptr;
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->get_accKeyboardShortcut(kVarChildIdSelf,
+                                               pszKeyboardShortcut);
+  }
+
+  KeyBinding keyBinding = AccessKey();
+  if (keyBinding.IsEmpty()) keyBinding = KeyboardShortcut();
+
+  nsAutoString shortcut;
+  keyBinding.ToString(shortcut);
+
+  *pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(), shortcut.Length());
+  return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accFocus(
+    /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) {
+  if (!pvarChild) return E_INVALIDARG;
+
+  VariantInit(pvarChild);
+
+  // clang-format off
+  // VT_EMPTY:    None. This object does not have the keyboard focus itself
+  //              and does not contain a child that has the keyboard focus.
+  // VT_I4:       lVal is CHILDID_SELF. The object itself has the keyboard focus.
+  // VT_I4:       lVal contains the child ID of the child element with the keyboard focus.
+  // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
+  //              for the child object with the keyboard focus.
+  // clang-format on
+  if (IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
+  // Return the current IAccessible child that has focus
+  LocalAccessible* focusedAccessible = FocusedChild();
+
+  if (focusedAccessible == this) {
+    pvarChild->vt = VT_I4;
+    pvarChild->lVal = CHILDID_SELF;
+  } else if (focusedAccessible) {
+    pvarChild->vt = VT_DISPATCH;
+    pvarChild->pdispVal = NativeAccessible(focusedAccessible);
+  } else {
+    pvarChild->vt = VT_EMPTY;  // No focus or focus is not a child
+  }
+
+  return S_OK;
+}
+
+/**
+ * This helper class implements IEnumVARIANT for a nsTArray containing
+ * accessible objects.
+ */
+class AccessibleEnumerator final : public IEnumVARIANT {
+ public:
+  explicit AccessibleEnumerator(const nsTArray<LocalAccessible*>& aArray)
+      : mArray(aArray.Clone()), mCurIndex(0) {}
+  AccessibleEnumerator(const AccessibleEnumerator& toCopy)
+      : mArray(toCopy.mArray.Clone()), mCurIndex(toCopy.mCurIndex) {}
+  ~AccessibleEnumerator() {}
+
+  // IUnknown
+  DECL_IUNKNOWN
+
+  // IEnumVARIANT
+  STDMETHODIMP Next(unsigned long celt, VARIANT FAR* rgvar,
+                    unsigned long FAR* pceltFetched);
+  STDMETHODIMP Skip(unsigned long celt);
+  STDMETHODIMP Reset() {
+    mCurIndex = 0;
+    return S_OK;
+  }
+  STDMETHODIMP Clone(IEnumVARIANT FAR* FAR* ppenum);
+
+ private:
+  nsTArray<LocalAccessible*> mArray;
+  uint32_t mCurIndex;
+};
+
+STDMETHODIMP
+AccessibleEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
+  if (iid == IID_IEnumVARIANT) {
+    *ppvObject = static_cast<IEnumVARIANT*>(this);
+    AddRef();
+    return S_OK;
+  }
+  if (iid == IID_IUnknown) {
+    *ppvObject = static_cast<IUnknown*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  *ppvObject = nullptr;
+  return E_NOINTERFACE;
+}
+
+STDMETHODIMP
+AccessibleEnumerator::Next(unsigned long celt, VARIANT FAR* rgvar,
+                           unsigned long FAR* pceltFetched) {
+  uint32_t length = mArray.Length();
+  HRESULT hr = S_OK;
+
+  // Can't get more elements than there are...
+  if (celt > length - mCurIndex) {
+    hr = S_FALSE;
+    celt = length - mCurIndex;
+  }
+
+  // Copy the elements of the array into rgvar.
+  for (uint32_t i = 0; i < celt; ++i, ++mCurIndex) {
+    rgvar[i].vt = VT_DISPATCH;
+    rgvar[i].pdispVal = AccessibleWrap::NativeAccessible(mArray[mCurIndex]);
+  }
+
+  if (pceltFetched) *pceltFetched = celt;
+
+  return hr;
+}
+
+STDMETHODIMP
+AccessibleEnumerator::Clone(IEnumVARIANT FAR* FAR* ppenum) {
+  *ppenum = new AccessibleEnumerator(*this);
+  NS_ADDREF(*ppenum);
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleEnumerator::Skip(unsigned long celt) {
+  uint32_t length = mArray.Length();
+  // Check if we can skip the requested number of elements
+  if (celt > length - mCurIndex) {
+    mCurIndex = length;
+    return S_FALSE;
+  }
+  mCurIndex += celt;
+  return S_OK;
+}
+
+/**
+ * This method is called when a client wants to know which children of a node
+ *  are selected. Note that this method can only find selected children for
+ *  accessible object which implement SelectAccessible.
+ *
+ * The VARIANT return value arguement is expected to either contain a single
+ * IAccessible or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT
+ * regardless of the number of children selected, unless there are none selected
+ * in which case we return an empty VARIANT.
+ *
+ * We get the selected options from the select's accessible object and wrap
+ *  those in an AccessibleEnumerator which we then put in the return VARIANT.
+ *
+ * returns a VT_EMPTY VARIANT if:
+ *  - there are no selected children for this object
+ *  - the object is not the type that can have children selected
+ */
+STDMETHODIMP
+AccessibleWrap::get_accSelection(VARIANT __RPC_FAR* pvarChildren) {
+  if (!pvarChildren) return E_INVALIDARG;
+
+  VariantInit(pvarChildren);
+  pvarChildren->vt = VT_EMPTY;
+
+  if (IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
+  if (!IsSelect()) {
+    return S_OK;
+  }
+
+  AutoTArray<LocalAccessible*, 10> selectedItems;
+  SelectedItems(&selectedItems);
+  uint32_t count = selectedItems.Length();
+  if (count == 1) {
+    pvarChildren->vt = VT_DISPATCH;
+    pvarChildren->pdispVal = NativeAccessible(selectedItems[0]);
+  } else if (count > 1) {
+    RefPtr<AccessibleEnumerator> pEnum =
+        new AccessibleEnumerator(selectedItems);
+    AssociateCOMObjectForDisconnection(pEnum);
+    pvarChildren->vt =
+        VT_UNKNOWN;  // this must be VT_UNKNOWN for an IEnumVARIANT
+    NS_ADDREF(pvarChildren->punkVal = pEnum);
+  }
+  // If count == 0, vt is already VT_EMPTY, so there's nothing else to do.
+
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::get_accDefaultAction(
+    /* [optional][in] */ VARIANT varChild,
+    /* [retval][out] */ BSTR __RPC_FAR* pszDefaultAction) {
+  if (!pszDefaultAction) return E_INVALIDARG;
+
+  *pszDefaultAction = nullptr;
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->get_accDefaultAction(kVarChildIdSelf, pszDefaultAction);
+  }
+
+  nsAutoString defaultAction;
+  ActionNameAt(0, defaultAction);
+
+  *pszDefaultAction =
+      ::SysAllocStringLen(defaultAction.get(), defaultAction.Length());
+  return *pszDefaultAction ? S_OK : E_OUTOFMEMORY;
+}
+
+STDMETHODIMP
+AccessibleWrap::accSelect(
+    /* [in] */ long flagsSelect,
+    /* [optional][in] */ VARIANT varChild) {
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->accSelect(flagsSelect, kVarChildIdSelf);
+  }
+
+  if (flagsSelect & SELFLAG_TAKEFOCUS) {
+    if (XRE_IsContentProcess()) {
+      // In this case we might have been invoked while the IPC MessageChannel is
+      // waiting on a sync reply. We cannot dispatch additional IPC while that
+      // is happening, so we dispatch TakeFocus from the main thread to
+      // guarantee that we are outside any IPC.
+      nsCOMPtr<nsIRunnable> runnable = mozilla::NewRunnableMethod(
+          "LocalAccessible::TakeFocus", this, &LocalAccessible::TakeFocus);
+      NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
+      return S_OK;
+    }
+    TakeFocus();
+    return S_OK;
+  }
+
+  if (flagsSelect & SELFLAG_TAKESELECTION) {
+    TakeSelection();
+    return S_OK;
+  }
+
+  if (flagsSelect & SELFLAG_ADDSELECTION) {
+    SetSelected(true);
+    return S_OK;
+  }
+
+  if (flagsSelect & SELFLAG_REMOVESELECTION) {
+    SetSelected(false);
+    return S_OK;
+  }
+
+  return E_FAIL;
+}
+
+STDMETHODIMP
+AccessibleWrap::accLocation(
+    /* [out] */ long __RPC_FAR* pxLeft,
+    /* [out] */ long __RPC_FAR* pyTop,
+    /* [out] */ long __RPC_FAR* pcxWidth,
+    /* [out] */ long __RPC_FAR* pcyHeight,
+    /* [optional][in] */ VARIANT varChild) {
+  if (!pxLeft || !pyTop || !pcxWidth || !pcyHeight) return E_INVALIDARG;
+
+  *pxLeft = 0;
+  *pyTop = 0;
+  *pcxWidth = 0;
+  *pcyHeight = 0;
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
+                                   kVarChildIdSelf);
+  }
+
+  if (IsDefunct()) {
+    return CO_E_OBJNOTCONNECTED;
+  }
+
+  nsIntRect rect = Bounds();
+
+  *pxLeft = rect.X();
+  *pyTop = rect.Y();
+  *pcxWidth = rect.Width();
+  *pcyHeight = rect.Height();
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::accNavigate(
+    /* [in] */ long navDir,
+    /* [optional][in] */ VARIANT varStart,
+    /* [retval][out] */ VARIANT __RPC_FAR* pvarEndUpAt) {
+  if (!pvarEndUpAt) return E_INVALIDARG;
+
+  VariantInit(pvarEndUpAt);
+
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varStart, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->accNavigate(navDir, kVarChildIdSelf, pvarEndUpAt);
+  }
+
+  LocalAccessible* navAccessible = nullptr;
+  Maybe<RelationType> xpRelation;
+
+#define RELATIONTYPE(geckoType, stringType, atkType, msaaType, ia2Type) \
+  case msaaType:                                                        \
+    xpRelation.emplace(RelationType::geckoType);                        \
+    break;
+
+  switch (navDir) {
+    case NAVDIR_FIRSTCHILD:
+      if (IsProxy()) {
+        if (!nsAccUtils::MustPrune(Proxy())) {
+          navAccessible = WrapperFor(Proxy()->RemoteFirstChild());
+        }
+      } else {
+        if (!nsAccUtils::MustPrune(this)) navAccessible = LocalFirstChild();
+      }
+      break;
+    case NAVDIR_LASTCHILD:
+      if (IsProxy()) {
+        if (!nsAccUtils::MustPrune(Proxy())) {
+          navAccessible = WrapperFor(Proxy()->RemoteLastChild());
+        }
+      } else {
+        if (!nsAccUtils::MustPrune(this)) navAccessible = LocalLastChild();
+      }
+      break;
+    case NAVDIR_NEXT:
+      navAccessible = IsProxy() ? WrapperFor(Proxy()->RemoteNextSibling())
+                                : LocalNextSibling();
+      break;
+    case NAVDIR_PREVIOUS:
+      navAccessible = IsProxy() ? WrapperFor(Proxy()->RemotePrevSibling())
+                                : LocalPrevSibling();
+      break;
+    case NAVDIR_DOWN:
+    case NAVDIR_LEFT:
+    case NAVDIR_RIGHT:
+    case NAVDIR_UP:
+      return E_NOTIMPL;
+
+      // MSAA relationship extensions to accNavigate
+#include "RelationTypeMap.h"
+
+    default:
+      return E_INVALIDARG;
+  }
+
+#undef RELATIONTYPE
+
+  pvarEndUpAt->vt = VT_EMPTY;
+
+  if (xpRelation) {
+    Relation rel = RelationByType(*xpRelation);
+    navAccessible = rel.Next();
+  }
+
+  if (!navAccessible) return E_FAIL;
+
+  pvarEndUpAt->pdispVal = NativeAccessible(navAccessible);
+  pvarEndUpAt->vt = VT_DISPATCH;
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::accHitTest(
+    /* [in] */ long xLeft,
+    /* [in] */ long yTop,
+    /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) {
+  if (!pvarChild) return E_INVALIDARG;
+
+  VariantInit(pvarChild);
+
+  if (IsDefunct()) return CO_E_OBJNOTCONNECTED;
+
+  LocalAccessible* accessible = LocalChildAtPoint(
+      xLeft, yTop, Accessible::EWhichChildAtPoint::DirectChild);
+
+  // if we got a child
+  if (accessible) {
+    // if the child is us
+    if (accessible == this) {
+      pvarChild->vt = VT_I4;
+      pvarChild->lVal = CHILDID_SELF;
+    } else {  // its not create a LocalAccessible for it.
+      pvarChild->vt = VT_DISPATCH;
+      pvarChild->pdispVal = NativeAccessible(accessible);
+    }
+  } else {
+    // no child at that point
+    pvarChild->vt = VT_EMPTY;
+    return S_FALSE;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::accDoDefaultAction(
+    /* [optional][in] */ VARIANT varChild) {
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->accDoDefaultAction(kVarChildIdSelf);
+  }
+
+  return DoAction(0) ? S_OK : E_INVALIDARG;
+}
+
+STDMETHODIMP
+AccessibleWrap::put_accName(
+    /* [optional][in] */ VARIANT varChild,
+    /* [in] */ BSTR szName) {
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP
+AccessibleWrap::put_accValue(
+    /* [optional][in] */ VARIANT varChild,
+    /* [in] */ BSTR szValue) {
+  RefPtr<IAccessible> accessible;
+  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (accessible) {
+    return accessible->put_accValue(kVarChildIdSelf, szValue);
+  }
+
+  HyperTextAccessible* ht = AsHyperText();
+  if (!ht) {
+    return E_NOTIMPL;
+  }
+
+  uint32_t length = ::SysStringLen(szValue);
+  nsAutoString text(szValue, length);
+  ht->ReplaceText(text);
+  return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IDispatch
+
+STDMETHODIMP
+AccessibleWrap::GetTypeInfoCount(UINT* pctinfo) {
+  if (!pctinfo) return E_INVALIDARG;
+
+  *pctinfo = 1;
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) {
+  if (!ppTInfo) return E_INVALIDARG;
+
+  *ppTInfo = nullptr;
+
+  if (iTInfo != 0) return DISP_E_BADINDEX;
+
+  ITypeInfo* typeInfo = GetTI(lcid);
+  if (!typeInfo) return E_FAIL;
+
+  typeInfo->AddRef();
+  *ppTInfo = typeInfo;
+
+  return S_OK;
+}
+
+STDMETHODIMP
+AccessibleWrap::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
+                              LCID lcid, DISPID* rgDispId) {
+  ITypeInfo* typeInfo = GetTI(lcid);
+  if (!typeInfo) return E_FAIL;
+
+  HRESULT hr = DispGetIDsOfNames(typeInfo, rgszNames, cNames, rgDispId);
+  return hr;
+}
+
+STDMETHODIMP
+AccessibleWrap::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
+                       DISPPARAMS* pDispParams, VARIANT* pVarResult,
+                       EXCEPINFO* pExcepInfo, UINT* puArgErr) {
+  ITypeInfo* typeInfo = GetTI(lcid);
+  if (!typeInfo) return E_FAIL;
+
+  return typeInfo->Invoke(static_cast<IAccessible*>(this), dispIdMember, wFlags,
+                          pDispParams, pVarResult, pExcepInfo, puArgErr);
+}
+
 void AccessibleWrap::GetNativeInterface(void** aOutAccessible) {
   *aOutAccessible = static_cast<IAccessible*>(this);
   NS_ADDREF_THIS();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // LocalAccessible
 
@@ -141,21 +1005,46 @@ nsresult AccessibleWrap::HandleAccEvent(
     UpdateSystemCaretFor(accessible);
   }
 
   MsaaAccessible::FireWinEvent(accessible, eventType);
 
   return NS_OK;
 }
 
+DocRemoteAccessibleWrap* AccessibleWrap::DocProxyWrapper() const {
+  MOZ_ASSERT(IsProxy());
+
+  RemoteAccessible* proxy = Proxy();
+  if (!proxy) {
+    return nullptr;
+  }
+
+  AccessibleWrap* acc = WrapperFor(proxy->Document());
+  MOZ_ASSERT(acc->IsDoc());
+
+  return static_cast<DocRemoteAccessibleWrap*>(acc);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // AccessibleWrap
 
 //------- Helper methods ---------
 
+IDispatch* AccessibleWrap::NativeAccessible(LocalAccessible* aAccessible) {
+  if (!aAccessible) {
+    NS_WARNING("Not passing in an aAccessible");
+    return nullptr;
+  }
+
+  IAccessible* msaaAccessible = nullptr;
+  aAccessible->GetNativeInterface(reinterpret_cast<void**>(&msaaAccessible));
+  return static_cast<IDispatch*>(msaaAccessible);
+}
+
 bool AccessibleWrap::IsRootForHWND() {
   if (IsRoot()) {
     return true;
   }
   HWND thisHwnd = MsaaAccessible::GetHWNDFor(this);
   AccessibleWrap* parent = static_cast<AccessibleWrap*>(LocalParent());
   MOZ_ASSERT(parent);
   HWND parentHwnd = MsaaAccessible::GetHWNDFor(parent);
@@ -208,16 +1097,31 @@ void AccessibleWrap::UpdateSystemCaretFo
     ::ShowCaret(aCaretWnd);
     RECT windowRect;
     ::GetWindowRect(aCaretWnd, &windowRect);
     ::SetCaretPos(aCaretRect.X() - windowRect.left,
                   aCaretRect.Y() - windowRect.top);
   }
 }
 
+ITypeInfo* AccessibleWrap::GetTI(LCID lcid) {
+  if (gTypeInfo) return gTypeInfo;
+
+  ITypeLib* typeLib = nullptr;
+  HRESULT hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, lcid, &typeLib);
+  if (FAILED(hr)) return nullptr;
+
+  hr = typeLib->GetTypeInfoOfGuid(IID_IAccessible, &gTypeInfo);
+  typeLib->Release();
+
+  if (FAILED(hr)) return nullptr;
+
+  return gTypeInfo;
+}
+
 /* static */
 void AccessibleWrap::SetHandlerControl(DWORD aPid,
                                        RefPtr<IHandlerControl> aCtrl) {
   MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
 
   if (!sHandlerControllers) {
     sHandlerControllers = new nsTArray<HandlerControllerData>();
     ClearOnShutdown(&sHandlerControllers);
--- a/accessible/windows/msaa/AccessibleWrap.h
+++ b/accessible/windows/msaa/AccessibleWrap.h
@@ -34,16 +34,124 @@ class AccessibleWrap : public LocalAcces
   AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
  public:  // IUnknown methods - see iunknown.h for documentation
   STDMETHODIMP QueryInterface(REFIID, void**) override;
 
+  // Return the registered OLE class ID of this object's CfDataObj.
+  CLSID GetClassID() const;
+
+ public:  // COM interface IAccessible
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent(
+      /* [retval][out] */ IDispatch __RPC_FAR* __RPC_FAR* ppdispParent)
+      override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChildCount(
+      /* [retval][out] */ long __RPC_FAR* pcountChildren) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild(
+      /* [in] */ VARIANT varChild,
+      /* [retval][out] */ IDispatch __RPC_FAR* __RPC_FAR* ppdispChild) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accName(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR* pszName) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR* pszValue) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDescription(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR* pszDescription) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accRole(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ VARIANT __RPC_FAR* pvarRole) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accState(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ VARIANT __RPC_FAR* pvarState) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelp(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR* pszHelp) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelpTopic(
+      /* [out] */ BSTR __RPC_FAR* pszHelpFile,
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ long __RPC_FAR* pidTopic) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR* pszKeyboardShortcut) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accFocus(
+      /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accSelection(
+      /* [retval][out] */ VARIANT __RPC_FAR* pvarChildren) override;
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDefaultAction(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR* pszDefaultAction) override;
+
+  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accSelect(
+      /* [in] */ long flagsSelect,
+      /* [optional][in] */ VARIANT varChild) override;
+
+  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accLocation(
+      /* [out] */ long __RPC_FAR* pxLeft,
+      /* [out] */ long __RPC_FAR* pyTop,
+      /* [out] */ long __RPC_FAR* pcxWidth,
+      /* [out] */ long __RPC_FAR* pcyHeight,
+      /* [optional][in] */ VARIANT varChild) override;
+
+  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accNavigate(
+      /* [in] */ long navDir,
+      /* [optional][in] */ VARIANT varStart,
+      /* [retval][out] */ VARIANT __RPC_FAR* pvarEndUpAt) override;
+
+  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accHitTest(
+      /* [in] */ long xLeft,
+      /* [in] */ long yTop,
+      /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) override;
+
+  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accDoDefaultAction(
+      /* [optional][in] */ VARIANT varChild) override;
+
+  virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accName(
+      /* [optional][in] */ VARIANT varChild,
+      /* [in] */ BSTR szName) override;
+
+  virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accValue(
+      /* [optional][in] */ VARIANT varChild,
+      /* [in] */ BSTR szValue) override;
+
+  // IDispatch (support of scripting languages like VB)
+  virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override;
+
+  virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
+                                                ITypeInfo** ppTInfo) override;
+
+  virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
+                                                  LPOLESTR* rgszNames,
+                                                  UINT cNames, LCID lcid,
+                                                  DISPID* rgDispId) override;
+
+  virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
+                                           LCID lcid, WORD wFlags,
+                                           DISPPARAMS* pDispParams,
+                                           VARIANT* pVarResult,
+                                           EXCEPINFO* pExcepInfo,
+                                           UINT* puArgErr) override;
+
   // LocalAccessible
   virtual nsresult HandleAccEvent(AccEvent* aEvent) override;
   virtual void Shutdown() override;
 
   // Helper methods
   /**
    * System caret support: update the Windows caret position.
    * The system caret works more universally than the MSAA caret
@@ -62,26 +170,68 @@ class AccessibleWrap : public LocalAcces
  public:
   /**
    * Determine whether this is the root accessible for its HWND.
    */
   bool IsRootForHWND();
 
   virtual void GetNativeInterface(void** aOutAccessible) override;
 
+  static IDispatch* NativeAccessible(LocalAccessible* aAccessible);
+
   static void SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl);
 
   static void InvalidateHandlers();
 
   bool DispatchTextChangeToHandler(bool aIsInsert, const nsString& aText,
                                    int32_t aStart, uint32_t aLen);
 
  protected:
   virtual ~AccessibleWrap() = default;
 
+  /**
+   * Return the wrapper for the document's proxy.
+   */
+  DocRemoteAccessibleWrap* DocProxyWrapper() const;
+
+  /**
+   * Creates ITypeInfo for LIBID_Accessibility if it's needed and returns it.
+   */
+  static ITypeInfo* GetTI(LCID lcid);
+
+  static ITypeInfo* gTypeInfo;
+
+  enum navRelations {
+    NAVRELATION_CONTROLLED_BY = 0x1000,
+    NAVRELATION_CONTROLLER_FOR = 0x1001,
+    NAVRELATION_LABEL_FOR = 0x1002,
+    NAVRELATION_LABELLED_BY = 0x1003,
+    NAVRELATION_MEMBER_OF = 0x1004,
+    NAVRELATION_NODE_CHILD_OF = 0x1005,
+    NAVRELATION_FLOWS_TO = 0x1006,
+    NAVRELATION_FLOWS_FROM = 0x1007,
+    NAVRELATION_SUBWINDOW_OF = 0x1008,
+    NAVRELATION_EMBEDS = 0x1009,
+    NAVRELATION_EMBEDDED_BY = 0x100a,
+    NAVRELATION_POPUP_FOR = 0x100b,
+    NAVRELATION_PARENT_WINDOW_OF = 0x100c,
+    NAVRELATION_DEFAULT_BUTTON = 0x100d,
+    NAVRELATION_DESCRIBED_BY = 0x100e,
+    NAVRELATION_DESCRIPTION_FOR = 0x100f,
+    NAVRELATION_NODE_PARENT_OF = 0x1010,
+    NAVRELATION_CONTAINING_DOCUMENT = 0x1011,
+    NAVRELATION_CONTAINING_TAB_PANE = 0x1012,
+    NAVRELATION_CONTAINING_WINDOW = 0x1013,
+    NAVRELATION_CONTAINING_APPLICATION = 0x1014,
+    NAVRELATION_DETAILS = 0x1015,
+    NAVRELATION_DETAILS_FOR = 0x1016,
+    NAVRELATION_ERROR = 0x1017,
+    NAVRELATION_ERROR_FOR = 0x1018
+  };
+
   struct HandlerControllerData final {
     HandlerControllerData(DWORD aPid, RefPtr<IHandlerControl>&& aCtrl)
         : mPid(aPid), mCtrl(std::move(aCtrl)) {
       mIsProxy = mozilla::mscom::IsProxy(mCtrl);
     }
 
     HandlerControllerData(HandlerControllerData&& aOther)
         : mPid(aOther.mPid),
--- a/accessible/windows/msaa/CompatibilityUIA.cpp
+++ b/accessible/windows/msaa/CompatibilityUIA.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Compatibility.h"
 
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/WindowsVersion.h"
-#include "nspr/prenv.h"
 
 #include "nsTHashMap.h"
 #include "nsTHashSet.h"
 #include "nsPrintfCString.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "nsUnicharUtils.h"
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -4,17 +4,16 @@
  * 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 "DocAccessibleWrap.h"
 
 #include "Compatibility.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/dom/BrowserChild.h"
-#include "mozilla/dom/Document.h"
 #include "DocAccessibleChild.h"
 #include "nsWinUtils.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "sdnDocAccessible.h"
 #include "Statistics.h"
 
 #include "nsIDocShell.h"
--- a/accessible/windows/msaa/EnumVariant.cpp
+++ b/accessible/windows/msaa/EnumVariant.cpp
@@ -26,17 +26,17 @@ ChildrenEnumVariant::Next(ULONG aCount, 
 
   if (mAnchorAcc->IsDefunct() || mAnchorAcc->LocalChildAt(mCurIndex) != mCurAcc)
     return CO_E_OBJNOTCONNECTED;
 
   ULONG countFetched = 0;
   while (mCurAcc && countFetched < aCount) {
     VariantInit(aItems + countFetched);
 
-    IDispatch* accNative = MsaaAccessible::NativeAccessible(mCurAcc);
+    IDispatch* accNative = AccessibleWrap::NativeAccessible(mCurAcc);
 
     ++mCurIndex;
     mCurAcc = mAnchorAcc->LocalChildAt(mCurIndex);
 
     // Don't output the accessible and count it as having been fetched unless
     // it is non-null
     MOZ_ASSERT(accNative);
     if (!accNative) {
--- a/accessible/windows/msaa/MsaaAccessible.cpp
+++ b/accessible/windows/msaa/MsaaAccessible.cpp
@@ -1,51 +1,38 @@
 /* -*- 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 "MsaaAccessible.h"
-#include "mozilla/a11y/AccessibleWrap.h"
-#include "mozilla/a11y/DocAccessibleParent.h"
 #include "mozilla/dom/BrowserBridgeParent.h"
 #include "mozilla/dom/BrowserParent.h"
 #include "mozilla/mscom/Interceptor.h"
 #include "nsEventMap.h"
-#include "nsViewManager.h"
 #include "nsWinUtils.h"
-#include "Relation.h"
 #include "sdnAccessible.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
-const uint32_t USE_ROLE_STRING = 0;
-static const VARIANT kVarChildIdSelf = {{{VT_I4}}};
-
 MsaaIdGenerator MsaaAccessible::sIDGen;
-ITypeInfo* MsaaAccessible::gTypeInfo = nullptr;
 
 MsaaAccessible::MsaaAccessible() : mID(kNoID) {}
 
 MsaaAccessible::~MsaaAccessible() {
   if (mID != kNoID) {
     sIDGen.ReleaseID(WrapNotNull(this));
   }
 }
 
 void MsaaAccessible::MsaaShutdown() {
   if (mID != kNoID) {
-    // Don't use LocalAcc() here because it requires that the Accessible is
-    // not defunct. When shutting down, the Accessible might already be
-    // marked defunct. It's safe for us to call LocalAccessible::Document() here
-    // regardless.
-    auto localAcc = static_cast<AccessibleWrap*>(this);
-    auto doc = static_cast<DocAccessibleWrap*>(localAcc->Document());
+    auto doc = static_cast<DocAccessibleWrap*>(LocalAcc()->Document());
     // Accessibles can be shut down twice in some cases. When this happens,
     // doc will be null.
     if (doc) {
       doc->RemoveID(mID);
     }
   }
 
   if (XRE_IsContentProcess()) {
@@ -246,18 +233,17 @@ void MsaaAccessible::FireWinEvent(LocalA
     AccessibleWrap::InvalidateHandlers();
   }
 
   // Fire MSAA event for client area window.
   ::NotifyWinEvent(winEvent, hwnd, OBJID_CLIENT, childID);
 }
 
 AccessibleWrap* MsaaAccessible::LocalAcc() {
-  auto acc = static_cast<AccessibleWrap*>(this);
-  return acc->IsDefunct() ? nullptr : acc;
+  return static_cast<AccessibleWrap*>(this);
 }
 
 /**
  * This function is a helper for implementing IAccessible methods that accept
  * a Child ID as a parameter. If the child ID is CHILDID_SELF, the function
  * returns S_OK but a null *aOutInterface. Otherwise, *aOutInterface points
  * to the resolved IAccessible.
  *
@@ -284,17 +270,17 @@ MsaaAccessible::ResolveChild(const VARIA
                              IAccessible** aOutInterface) {
   MOZ_ASSERT(aOutInterface);
   *aOutInterface = nullptr;
 
   if (aVarChild.vt != VT_I4) {
     return E_INVALIDARG;
   }
 
-  if (!LocalAcc()) {
+  if (LocalAcc()->IsDefunct()) {
     return CO_E_OBJNOTCONNECTED;
   }
 
   if (aVarChild.lVal == CHILDID_SELF) {
     return S_OK;
   }
 
   bool isDefunct = false;
@@ -376,22 +362,21 @@ already_AddRefed<IAccessible> MsaaAccess
   VARIANT varChild = aVarChild;
 
   MOZ_ASSERT(aIsDefunct);
   *aIsDefunct = false;
 
   RefPtr<IAccessible> result;
 
   AccessibleWrap* localAcc = LocalAcc();
-  if (!localAcc) {
-    *aIsDefunct = true;
-    return nullptr;
-  }
-
   if (varChild.lVal == CHILDID_SELF) {
+    *aIsDefunct = localAcc->IsDefunct();
+    if (*aIsDefunct) {
+      return nullptr;
+    }
     localAcc->GetNativeInterface(getter_AddRefs(result));
     if (result) {
       return result.forget();
     }
     // If we're not a proxy, there's nothing more we can do to attempt to
     // resolve the IAccessible, so we just fail.
     if (!localAcc->IsProxy()) {
       return nullptr;
@@ -586,869 +571,8 @@ already_AddRefed<IAccessible> MsaaAccess
     // QI can fail on rare occasions if the LocalAccessible dies after we
     // fetched disp but before we QI.
     NS_WARNING_ASSERTION(SUCCEEDED(hr), "QI failed on remote IDispatch");
     return result.forget();
   }
 
   return nullptr;
 }
-
-IDispatch* MsaaAccessible::NativeAccessible(LocalAccessible* aAccessible) {
-  if (!aAccessible) {
-    NS_WARNING("Not passing in an aAccessible");
-    return nullptr;
-  }
-
-  IAccessible* msaaAccessible = nullptr;
-  aAccessible->GetNativeInterface(reinterpret_cast<void**>(&msaaAccessible));
-  return static_cast<IDispatch*>(msaaAccessible);
-}
-
-ITypeInfo* MsaaAccessible::GetTI(LCID lcid) {
-  if (gTypeInfo) return gTypeInfo;
-
-  ITypeLib* typeLib = nullptr;
-  HRESULT hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, lcid, &typeLib);
-  if (FAILED(hr)) return nullptr;
-
-  hr = typeLib->GetTypeInfoOfGuid(IID_IAccessible, &gTypeInfo);
-  typeLib->Release();
-
-  if (FAILED(hr)) return nullptr;
-
-  return gTypeInfo;
-}
-
-// IAccessible methods
-
-STDMETHODIMP
-MsaaAccessible::get_accParent(IDispatch __RPC_FAR* __RPC_FAR* ppdispParent) {
-  if (!ppdispParent) return E_INVALIDARG;
-
-  *ppdispParent = nullptr;
-
-  LocalAccessible* localAcc = LocalAcc();
-  if (!localAcc) return CO_E_OBJNOTCONNECTED;
-
-  LocalAccessible* xpParentAcc = localAcc->LocalParent();
-  if (!xpParentAcc) return S_FALSE;
-
-  *ppdispParent = NativeAccessible(xpParentAcc);
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accChildCount(long __RPC_FAR* pcountChildren) {
-  if (!pcountChildren) return E_INVALIDARG;
-
-  *pcountChildren = 0;
-
-  LocalAccessible* localAcc = LocalAcc();
-  if (!localAcc) return CO_E_OBJNOTCONNECTED;
-
-  if (nsAccUtils::MustPrune(localAcc)) return S_OK;
-
-  *pcountChildren = localAcc->ChildCount();
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accChild(
-    /* [in] */ VARIANT varChild,
-    /* [retval][out] */ IDispatch __RPC_FAR* __RPC_FAR* ppdispChild) {
-  if (!ppdispChild) return E_INVALIDARG;
-
-  *ppdispChild = nullptr;
-  if (!LocalAcc()) return CO_E_OBJNOTCONNECTED;
-
-  // IAccessible::accChild is used to return this accessible or child accessible
-  // at the given index or to get an accessible by child ID in the case of
-  // document accessible.
-  // The getting an accessible by child ID is used by
-  // AccessibleObjectFromEvent() called by AT when AT handles our MSAA event.
-  bool isDefunct = false;
-  RefPtr<IAccessible> child = GetIAccessibleFor(varChild, &isDefunct);
-  if (!child) {
-    return E_INVALIDARG;
-  }
-
-  if (isDefunct) {
-    return CO_E_OBJNOTCONNECTED;
-  }
-
-  child.forget(ppdispChild);
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accName(
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ BSTR __RPC_FAR* pszName) {
-  if (!pszName || varChild.vt != VT_I4) return E_INVALIDARG;
-
-  *pszName = nullptr;
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->get_accName(kVarChildIdSelf, pszName);
-  }
-
-  nsAutoString name;
-  LocalAcc()->Name(name);
-
-  // The name was not provided, e.g. no alt attribute for an image. A screen
-  // reader may choose to invent its own accessible name, e.g. from an image src
-  // attribute. Refer to eNoNameOnPurpose return value.
-  if (name.IsVoid()) return S_FALSE;
-
-  *pszName = ::SysAllocStringLen(name.get(), name.Length());
-  if (!*pszName) return E_OUTOFMEMORY;
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accValue(
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ BSTR __RPC_FAR* pszValue) {
-  if (!pszValue) return E_INVALIDARG;
-
-  *pszValue = nullptr;
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->get_accValue(kVarChildIdSelf, pszValue);
-  }
-
-  nsAutoString value;
-  LocalAcc()->Value(value);
-
-  // See bug 438784: need to expose URL on doc's value attribute. For this,
-  // reverting part of fix for bug 425693 to make this MSAA method behave
-  // IAccessible2-style.
-  if (value.IsEmpty()) return S_FALSE;
-
-  *pszValue = ::SysAllocStringLen(value.get(), value.Length());
-  if (!*pszValue) return E_OUTOFMEMORY;
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accDescription(VARIANT varChild,
-                                   BSTR __RPC_FAR* pszDescription) {
-  if (!pszDescription) return E_INVALIDARG;
-
-  *pszDescription = nullptr;
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->get_accDescription(kVarChildIdSelf, pszDescription);
-  }
-
-  nsAutoString description;
-  LocalAcc()->Description(description);
-
-  *pszDescription =
-      ::SysAllocStringLen(description.get(), description.Length());
-  return *pszDescription ? S_OK : E_OUTOFMEMORY;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accRole(
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ VARIANT __RPC_FAR* pvarRole) {
-  if (!pvarRole) return E_INVALIDARG;
-
-  VariantInit(pvarRole);
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->get_accRole(kVarChildIdSelf, pvarRole);
-  }
-
-  a11y::role geckoRole;
-  LocalAccessible* localAcc = LocalAcc();
-#ifdef DEBUG
-  NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(localAcc),
-               "Does not support Text when it should");
-#endif
-  geckoRole = localAcc->Role();
-
-  uint32_t msaaRole = 0;
-
-#define ROLE(_geckoRole, stringRole, atkRole, macRole, macSubrole, _msaaRole, \
-             ia2Role, androidClass, nameRule)                                 \
-  case roles::_geckoRole:                                                     \
-    msaaRole = _msaaRole;                                                     \
-    break;
-
-  switch (geckoRole) {
-#include "RoleMap.h"
-    default:
-      MOZ_CRASH("Unknown role.");
-  }
-
-#undef ROLE
-
-  // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
-  // the MSAA role a ROLE_OUTLINEITEM for consistency and compatibility. We need
-  // this because ARIA has a role of "row" for both grid and treegrid
-  if (geckoRole == roles::ROW) {
-    LocalAccessible* xpParent = localAcc->LocalParent();
-    if (xpParent && xpParent->Role() == roles::TREE_TABLE)
-      msaaRole = ROLE_SYSTEM_OUTLINEITEM;
-  }
-
-  // -- Try enumerated role
-  if (msaaRole != USE_ROLE_STRING) {
-    pvarRole->vt = VT_I4;
-    pvarRole->lVal = msaaRole;  // Normal enumerated role
-    return S_OK;
-  }
-
-  // -- Try BSTR role
-  // Could not map to known enumerated MSAA role like ROLE_BUTTON
-  // Use BSTR role to expose role attribute or tag name + namespace
-  nsIContent* content = localAcc->GetContent();
-  if (!content) return E_FAIL;
-
-  if (content->IsElement()) {
-    nsAutoString roleString;
-    // Try the role attribute.
-    content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::role,
-                                  roleString);
-
-    if (roleString.IsEmpty()) {
-      // No role attribute (or it is an empty string).
-      // Use the tag name.
-      dom::Document* document = content->GetUncomposedDoc();
-      if (!document) return E_FAIL;
-
-      dom::NodeInfo* nodeInfo = content->NodeInfo();
-      nodeInfo->GetName(roleString);
-
-      // Only append name space if different from that of current document.
-      if (!nodeInfo->NamespaceEquals(document->GetDefaultNamespaceID())) {
-        nsAutoString nameSpaceURI;
-        nodeInfo->GetNamespaceURI(nameSpaceURI);
-        roleString += u", "_ns + nameSpaceURI;
-      }
-    }
-
-    if (!roleString.IsEmpty()) {
-      pvarRole->vt = VT_BSTR;
-      pvarRole->bstrVal = ::SysAllocString(roleString.get());
-      return S_OK;
-    }
-  }
-
-  return E_FAIL;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accState(
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ VARIANT __RPC_FAR* pvarState) {
-  if (!pvarState) return E_INVALIDARG;
-
-  VariantInit(pvarState);
-  pvarState->vt = VT_I4;
-  pvarState->lVal = 0;
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->get_accState(kVarChildIdSelf, pvarState);
-  }
-
-  // MSAA only has 31 states and the lowest 31 bits of our state bit mask
-  // are the same states as MSAA.
-  // Note: we map the following Gecko states to different MSAA states:
-  //   REQUIRED -> ALERT_LOW
-  //   ALERT -> ALERT_MEDIUM
-  //   INVALID -> ALERT_HIGH
-  //   CHECKABLE -> MARQUEED
-
-  uint64_t state = LocalAcc()->State();
-
-  uint32_t msaaState = 0;
-  nsAccUtils::To32States(state, &msaaState, nullptr);
-  pvarState->lVal = msaaState;
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accHelp(
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ BSTR __RPC_FAR* pszHelp) {
-  if (!pszHelp) return E_INVALIDARG;
-
-  *pszHelp = nullptr;
-  return S_FALSE;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accHelpTopic(
-    /* [out] */ BSTR __RPC_FAR* pszHelpFile,
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ long __RPC_FAR* pidTopic) {
-  if (!pszHelpFile || !pidTopic) return E_INVALIDARG;
-
-  *pszHelpFile = nullptr;
-  *pidTopic = 0;
-  return S_FALSE;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accKeyboardShortcut(
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ BSTR __RPC_FAR* pszKeyboardShortcut) {
-  if (!pszKeyboardShortcut) return E_INVALIDARG;
-  *pszKeyboardShortcut = nullptr;
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->get_accKeyboardShortcut(kVarChildIdSelf,
-                                               pszKeyboardShortcut);
-  }
-
-  LocalAccessible* localAcc = LocalAcc();
-  KeyBinding keyBinding = localAcc->AccessKey();
-  if (keyBinding.IsEmpty()) keyBinding = localAcc->KeyboardShortcut();
-
-  nsAutoString shortcut;
-  keyBinding.ToString(shortcut);
-
-  *pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(), shortcut.Length());
-  return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accFocus(
-    /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) {
-  if (!pvarChild) return E_INVALIDARG;
-
-  VariantInit(pvarChild);
-
-  // clang-format off
-  // VT_EMPTY:    None. This object does not have the keyboard focus itself
-  //              and does not contain a child that has the keyboard focus.
-  // VT_I4:       lVal is CHILDID_SELF. The object itself has the keyboard focus.
-  // VT_I4:       lVal contains the child ID of the child element with the keyboard focus.
-  // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
-  //              for the child object with the keyboard focus.
-  // clang-format on
-  LocalAccessible* localAcc = LocalAcc();
-  if (!localAcc) return CO_E_OBJNOTCONNECTED;
-
-  // Return the current IAccessible child that has focus
-  LocalAccessible* focusedAccessible = localAcc->FocusedChild();
-
-  if (focusedAccessible == localAcc) {
-    pvarChild->vt = VT_I4;
-    pvarChild->lVal = CHILDID_SELF;
-  } else if (focusedAccessible) {
-    pvarChild->vt = VT_DISPATCH;
-    pvarChild->pdispVal = NativeAccessible(focusedAccessible);
-  } else {
-    pvarChild->vt = VT_EMPTY;  // No focus or focus is not a child
-  }
-
-  return S_OK;
-}
-
-/**
- * This helper class implements IEnumVARIANT for a nsTArray containing
- * accessible objects.
- */
-class AccessibleEnumerator final : public IEnumVARIANT {
- public:
-  explicit AccessibleEnumerator(const nsTArray<LocalAccessible*>& aArray)
-      : mArray(aArray.Clone()), mCurIndex(0) {}
-  AccessibleEnumerator(const AccessibleEnumerator& toCopy)
-      : mArray(toCopy.mArray.Clone()), mCurIndex(toCopy.mCurIndex) {}
-  ~AccessibleEnumerator() {}
-
-  // IUnknown
-  DECL_IUNKNOWN
-
-  // IEnumVARIANT
-  STDMETHODIMP Next(unsigned long celt, VARIANT FAR* rgvar,
-                    unsigned long FAR* pceltFetched);
-  STDMETHODIMP Skip(unsigned long celt);
-  STDMETHODIMP Reset() {
-    mCurIndex = 0;
-    return S_OK;
-  }
-  STDMETHODIMP Clone(IEnumVARIANT FAR* FAR* ppenum);
-
- private:
-  nsTArray<LocalAccessible*> mArray;
-  uint32_t mCurIndex;
-};
-
-STDMETHODIMP
-AccessibleEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
-  if (iid == IID_IEnumVARIANT) {
-    *ppvObject = static_cast<IEnumVARIANT*>(this);
-    AddRef();
-    return S_OK;
-  }
-  if (iid == IID_IUnknown) {
-    *ppvObject = static_cast<IUnknown*>(this);
-    AddRef();
-    return S_OK;
-  }
-
-  *ppvObject = nullptr;
-  return E_NOINTERFACE;
-}
-
-STDMETHODIMP
-AccessibleEnumerator::Next(unsigned long celt, VARIANT FAR* rgvar,
-                           unsigned long FAR* pceltFetched) {
-  uint32_t length = mArray.Length();
-  HRESULT hr = S_OK;
-
-  // Can't get more elements than there are...
-  if (celt > length - mCurIndex) {
-    hr = S_FALSE;
-    celt = length - mCurIndex;
-  }
-
-  // Copy the elements of the array into rgvar.
-  for (uint32_t i = 0; i < celt; ++i, ++mCurIndex) {
-    rgvar[i].vt = VT_DISPATCH;
-    rgvar[i].pdispVal = MsaaAccessible::NativeAccessible(mArray[mCurIndex]);
-  }
-
-  if (pceltFetched) *pceltFetched = celt;
-
-  return hr;
-}
-
-STDMETHODIMP
-AccessibleEnumerator::Clone(IEnumVARIANT FAR* FAR* ppenum) {
-  *ppenum = new AccessibleEnumerator(*this);
-  NS_ADDREF(*ppenum);
-  return S_OK;
-}
-
-STDMETHODIMP
-AccessibleEnumerator::Skip(unsigned long celt) {
-  uint32_t length = mArray.Length();
-  // Check if we can skip the requested number of elements
-  if (celt > length - mCurIndex) {
-    mCurIndex = length;
-    return S_FALSE;
-  }
-  mCurIndex += celt;
-  return S_OK;
-}
-
-/**
- * This method is called when a client wants to know which children of a node
- *  are selected. Note that this method can only find selected children for
- *  accessible object which implement SelectAccessible.
- *
- * The VARIANT return value arguement is expected to either contain a single
- * IAccessible or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT
- * regardless of the number of children selected, unless there are none selected
- * in which case we return an empty VARIANT.
- *
- * We get the selected options from the select's accessible object and wrap
- *  those in an AccessibleEnumerator which we then put in the return VARIANT.
- *
- * returns a VT_EMPTY VARIANT if:
- *  - there are no selected children for this object
- *  - the object is not the type that can have children selected
- */
-STDMETHODIMP
-MsaaAccessible::get_accSelection(VARIANT __RPC_FAR* pvarChildren) {
-  if (!pvarChildren) return E_INVALIDARG;
-
-  VariantInit(pvarChildren);
-  pvarChildren->vt = VT_EMPTY;
-
-  LocalAccessible* localAcc = LocalAcc();
-  if (!localAcc) return CO_E_OBJNOTCONNECTED;
-
-  if (!localAcc->IsSelect()) {
-    return S_OK;
-  }
-
-  AutoTArray<LocalAccessible*, 10> selectedItems;
-  localAcc->SelectedItems(&selectedItems);
-  uint32_t count = selectedItems.Length();
-  if (count == 1) {
-    pvarChildren->vt = VT_DISPATCH;
-    pvarChildren->pdispVal = NativeAccessible(selectedItems[0]);
-  } else if (count > 1) {
-    RefPtr<AccessibleEnumerator> pEnum =
-        new AccessibleEnumerator(selectedItems);
-    AssociateCOMObjectForDisconnection(pEnum);
-    pvarChildren->vt =
-        VT_UNKNOWN;  // this must be VT_UNKNOWN for an IEnumVARIANT
-    NS_ADDREF(pvarChildren->punkVal = pEnum);
-  }
-  // If count == 0, vt is already VT_EMPTY, so there's nothing else to do.
-
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::get_accDefaultAction(
-    /* [optional][in] */ VARIANT varChild,
-    /* [retval][out] */ BSTR __RPC_FAR* pszDefaultAction) {
-  if (!pszDefaultAction) return E_INVALIDARG;
-
-  *pszDefaultAction = nullptr;
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->get_accDefaultAction(kVarChildIdSelf, pszDefaultAction);
-  }
-
-  nsAutoString defaultAction;
-  LocalAcc()->ActionNameAt(0, defaultAction);
-
-  *pszDefaultAction =
-      ::SysAllocStringLen(defaultAction.get(), defaultAction.Length());
-  return *pszDefaultAction ? S_OK : E_OUTOFMEMORY;
-}
-
-STDMETHODIMP
-MsaaAccessible::accSelect(
-    /* [in] */ long flagsSelect,
-    /* [optional][in] */ VARIANT varChild) {
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->accSelect(flagsSelect, kVarChildIdSelf);
-  }
-
-  LocalAccessible* localAcc = LocalAcc();
-  if (flagsSelect & SELFLAG_TAKEFOCUS) {
-    if (XRE_IsContentProcess()) {
-      // In this case we might have been invoked while the IPC MessageChannel is
-      // waiting on a sync reply. We cannot dispatch additional IPC while that
-      // is happening, so we dispatch TakeFocus from the main thread to
-      // guarantee that we are outside any IPC.
-      nsCOMPtr<nsIRunnable> runnable = mozilla::NewRunnableMethod(
-          "LocalAccessible::TakeFocus", localAcc, &LocalAccessible::TakeFocus);
-      NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
-      return S_OK;
-    }
-    localAcc->TakeFocus();
-    return S_OK;
-  }
-
-  if (flagsSelect & SELFLAG_TAKESELECTION) {
-    localAcc->TakeSelection();
-    return S_OK;
-  }
-
-  if (flagsSelect & SELFLAG_ADDSELECTION) {
-    localAcc->SetSelected(true);
-    return S_OK;
-  }
-
-  if (flagsSelect & SELFLAG_REMOVESELECTION) {
-    localAcc->SetSelected(false);
-    return S_OK;
-  }
-
-  return E_FAIL;
-}
-
-STDMETHODIMP
-MsaaAccessible::accLocation(
-    /* [out] */ long __RPC_FAR* pxLeft,
-    /* [out] */ long __RPC_FAR* pyTop,
-    /* [out] */ long __RPC_FAR* pcxWidth,
-    /* [out] */ long __RPC_FAR* pcyHeight,
-    /* [optional][in] */ VARIANT varChild) {
-  if (!pxLeft || !pyTop || !pcxWidth || !pcyHeight) return E_INVALIDARG;
-
-  *pxLeft = 0;
-  *pyTop = 0;
-  *pcxWidth = 0;
-  *pcyHeight = 0;
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
-                                   kVarChildIdSelf);
-  }
-
-  LocalAccessible* localAcc = LocalAcc();
-  if (!localAcc) {
-    return CO_E_OBJNOTCONNECTED;
-  }
-
-  nsIntRect rect = localAcc->Bounds();
-
-  *pxLeft = rect.X();
-  *pyTop = rect.Y();
-  *pcxWidth = rect.Width();
-  *pcyHeight = rect.Height();
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::accNavigate(
-    /* [in] */ long navDir,
-    /* [optional][in] */ VARIANT varStart,
-    /* [retval][out] */ VARIANT __RPC_FAR* pvarEndUpAt) {
-  if (!pvarEndUpAt) return E_INVALIDARG;
-
-  VariantInit(pvarEndUpAt);
-
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varStart, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->accNavigate(navDir, kVarChildIdSelf, pvarEndUpAt);
-  }
-
-  LocalAccessible* localAcc = LocalAcc();
-  LocalAccessible* navAccessible = nullptr;
-  Maybe<RelationType> xpRelation;
-
-#define RELATIONTYPE(geckoType, stringType, atkType, msaaType, ia2Type) \
-  case msaaType:                                                        \
-    xpRelation.emplace(RelationType::geckoType);                        \
-    break;
-
-  switch (navDir) {
-    case NAVDIR_FIRSTCHILD:
-      if (localAcc->IsProxy()) {
-        if (!nsAccUtils::MustPrune(localAcc->Proxy())) {
-          navAccessible = WrapperFor(localAcc->Proxy()->RemoteFirstChild());
-        }
-      } else {
-        if (!nsAccUtils::MustPrune(localAcc))
-          navAccessible = localAcc->LocalFirstChild();
-      }
-      break;
-    case NAVDIR_LASTCHILD:
-      if (localAcc->IsProxy()) {
-        if (!nsAccUtils::MustPrune(localAcc->Proxy())) {
-          navAccessible = WrapperFor(localAcc->Proxy()->RemoteLastChild());
-        }
-      } else {
-        if (!nsAccUtils::MustPrune(localAcc))
-          navAccessible = localAcc->LocalLastChild();
-      }
-      break;
-    case NAVDIR_NEXT:
-      navAccessible = localAcc->IsProxy()
-                          ? WrapperFor(localAcc->Proxy()->RemoteNextSibling())
-                          : localAcc->LocalNextSibling();
-      break;
-    case NAVDIR_PREVIOUS:
-      navAccessible = localAcc->IsProxy()
-                          ? WrapperFor(localAcc->Proxy()->RemotePrevSibling())
-                          : localAcc->LocalPrevSibling();
-      break;
-    case NAVDIR_DOWN:
-    case NAVDIR_LEFT:
-    case NAVDIR_RIGHT:
-    case NAVDIR_UP:
-      return E_NOTIMPL;
-
-      // MSAA relationship extensions to accNavigate
-#include "RelationTypeMap.h"
-
-    default:
-      return E_INVALIDARG;
-  }
-
-#undef RELATIONTYPE
-
-  pvarEndUpAt->vt = VT_EMPTY;
-
-  if (xpRelation) {
-    Relation rel = localAcc->RelationByType(*xpRelation);
-    navAccessible = rel.Next();
-  }
-
-  if (!navAccessible) return E_FAIL;
-
-  pvarEndUpAt->pdispVal = NativeAccessible(navAccessible);
-  pvarEndUpAt->vt = VT_DISPATCH;
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::accHitTest(
-    /* [in] */ long xLeft,
-    /* [in] */ long yTop,
-    /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) {
-  if (!pvarChild) return E_INVALIDARG;
-
-  VariantInit(pvarChild);
-
-  LocalAccessible* localAcc = LocalAcc();
-  if (!localAcc) return CO_E_OBJNOTCONNECTED;
-
-  LocalAccessible* accessible = localAcc->LocalChildAtPoint(
-      xLeft, yTop, Accessible::EWhichChildAtPoint::DirectChild);
-
-  // if we got a child
-  if (accessible) {
-    // if the child is us
-    if (accessible == localAcc) {
-      pvarChild->vt = VT_I4;
-      pvarChild->lVal = CHILDID_SELF;
-    } else {  // its not create a LocalAccessible for it.
-      pvarChild->vt = VT_DISPATCH;
-      pvarChild->pdispVal = NativeAccessible(accessible);
-    }
-  } else {
-    // no child at that point
-    pvarChild->vt = VT_EMPTY;
-    return S_FALSE;
-  }
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::accDoDefaultAction(
-    /* [optional][in] */ VARIANT varChild) {
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->accDoDefaultAction(kVarChildIdSelf);
-  }
-
-  return LocalAcc()->DoAction(0) ? S_OK : E_INVALIDARG;
-}
-
-STDMETHODIMP
-MsaaAccessible::put_accName(
-    /* [optional][in] */ VARIANT varChild,
-    /* [in] */ BSTR szName) {
-  return E_NOTIMPL;
-}
-
-STDMETHODIMP
-MsaaAccessible::put_accValue(
-    /* [optional][in] */ VARIANT varChild,
-    /* [in] */ BSTR szValue) {
-  RefPtr<IAccessible> accessible;
-  HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
-  if (FAILED(hr)) {
-    return hr;
-  }
-
-  if (accessible) {
-    return accessible->put_accValue(kVarChildIdSelf, szValue);
-  }
-
-  HyperTextAccessible* ht = LocalAcc()->AsHyperText();
-  if (!ht) {
-    return E_NOTIMPL;
-  }
-
-  uint32_t length = ::SysStringLen(szValue);
-  nsAutoString text(szValue, length);
-  ht->ReplaceText(text);
-  return S_OK;
-}
-
-// IDispatch methods
-
-STDMETHODIMP
-MsaaAccessible::GetTypeInfoCount(UINT* pctinfo) {
-  if (!pctinfo) return E_INVALIDARG;
-
-  *pctinfo = 1;
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) {
-  if (!ppTInfo) return E_INVALIDARG;
-
-  *ppTInfo = nullptr;
-
-  if (iTInfo != 0) return DISP_E_BADINDEX;
-
-  ITypeInfo* typeInfo = GetTI(lcid);
-  if (!typeInfo) return E_FAIL;
-
-  typeInfo->AddRef();
-  *ppTInfo = typeInfo;
-
-  return S_OK;
-}
-
-STDMETHODIMP
-MsaaAccessible::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
-                              LCID lcid, DISPID* rgDispId) {
-  ITypeInfo* typeInfo = GetTI(lcid);
-  if (!typeInfo) return E_FAIL;
-
-  HRESULT hr = DispGetIDsOfNames(typeInfo, rgszNames, cNames, rgDispId);
-  return hr;
-}
-
-STDMETHODIMP
-MsaaAccessible::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
-                       DISPPARAMS* pDispParams, VARIANT* pVarResult,
-                       EXCEPINFO* pExcepInfo, UINT* puArgErr) {
-  ITypeInfo* typeInfo = GetTI(lcid);
-  if (!typeInfo) return E_FAIL;
-
-  return typeInfo->Invoke(static_cast<IAccessible*>(this), dispIdMember, wFlags,
-                          pDispParams, pVarResult, pExcepInfo, puArgErr);
-}
--- a/accessible/windows/msaa/MsaaAccessible.h
+++ b/accessible/windows/msaa/MsaaAccessible.h
@@ -59,151 +59,33 @@ class MsaaAccessible : public ia2Accessi
     // collection is disabled there.
     if (XRE_IsContentProcess()) {
       mAssociatedCOMObjectsForDisconnection.AppendElement(aObject);
     }
   }
 
   void MsaaShutdown();
 
-  static IDispatch* NativeAccessible(LocalAccessible* aAccessible);
-
-  // IAccessible
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent(
-      /* [retval][out] */ IDispatch __RPC_FAR* __RPC_FAR* ppdispParent)
-      override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChildCount(
-      /* [retval][out] */ long __RPC_FAR* pcountChildren) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild(
-      /* [in] */ VARIANT varChild,
-      /* [retval][out] */ IDispatch __RPC_FAR* __RPC_FAR* ppdispChild) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accName(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR* pszName) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR* pszValue) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDescription(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR* pszDescription) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accRole(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ VARIANT __RPC_FAR* pvarRole) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accState(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ VARIANT __RPC_FAR* pvarState) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelp(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR* pszHelp) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelpTopic(
-      /* [out] */ BSTR __RPC_FAR* pszHelpFile,
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ long __RPC_FAR* pidTopic) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR* pszKeyboardShortcut) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accFocus(
-      /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accSelection(
-      /* [retval][out] */ VARIANT __RPC_FAR* pvarChildren) override;
-  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDefaultAction(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR* pszDefaultAction) override;
-  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accSelect(
-      /* [in] */ long flagsSelect,
-      /* [optional][in] */ VARIANT varChild) override;
-  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accLocation(
-      /* [out] */ long __RPC_FAR* pxLeft,
-      /* [out] */ long __RPC_FAR* pyTop,
-      /* [out] */ long __RPC_FAR* pcxWidth,
-      /* [out] */ long __RPC_FAR* pcyHeight,
-      /* [optional][in] */ VARIANT varChild) override;
-  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accNavigate(
-      /* [in] */ long navDir,
-      /* [optional][in] */ VARIANT varStart,
-      /* [retval][out] */ VARIANT __RPC_FAR* pvarEndUpAt) override;
-  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accHitTest(
-      /* [in] */ long xLeft,
-      /* [in] */ long yTop,
-      /* [retval][out] */ VARIANT __RPC_FAR* pvarChild) override;
-  virtual /* [id] */ HRESULT STDMETHODCALLTYPE accDoDefaultAction(
-      /* [optional][in] */ VARIANT varChild) override;
-  virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accName(
-      /* [optional][in] */ VARIANT varChild,
-      /* [in] */ BSTR szName) override;
-  virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accValue(
-      /* [optional][in] */ VARIANT varChild,
-      /* [in] */ BSTR szValue) override;
-
-  // IDispatch (support of scripting languages like VB)
-  virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override;
-  virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
-                                                ITypeInfo** ppTInfo) override;
-  virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
-                                                  LPOLESTR* rgszNames,
-                                                  UINT cNames, LCID lcid,
-                                                  DISPID* rgDispId) override;
-  virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
-                                           LCID lcid, WORD wFlags,
-                                           DISPPARAMS* pDispParams,
-                                           VARIANT* pVarResult,
-                                           EXCEPINFO* pExcepInfo,
-                                           UINT* puArgErr) override;
-
  protected:
   virtual ~MsaaAccessible();
 
   uint32_t mID;
   static MsaaIdGenerator sIDGen;
 
   HRESULT
   ResolveChild(const VARIANT& aVarChild, IAccessible** aOutInterface);
 
-  enum navRelations {
-    NAVRELATION_CONTROLLED_BY = 0x1000,
-    NAVRELATION_CONTROLLER_FOR = 0x1001,
-    NAVRELATION_LABEL_FOR = 0x1002,
-    NAVRELATION_LABELLED_BY = 0x1003,
-    NAVRELATION_MEMBER_OF = 0x1004,
-    NAVRELATION_NODE_CHILD_OF = 0x1005,
-    NAVRELATION_FLOWS_TO = 0x1006,
-    NAVRELATION_FLOWS_FROM = 0x1007,
-    NAVRELATION_SUBWINDOW_OF = 0x1008,
-    NAVRELATION_EMBEDS = 0x1009,
-    NAVRELATION_EMBEDDED_BY = 0x100a,
-    NAVRELATION_POPUP_FOR = 0x100b,
-    NAVRELATION_PARENT_WINDOW_OF = 0x100c,
-    NAVRELATION_DEFAULT_BUTTON = 0x100d,
-    NAVRELATION_DESCRIBED_BY = 0x100e,
-    NAVRELATION_DESCRIPTION_FOR = 0x100f,
-    NAVRELATION_NODE_PARENT_OF = 0x1010,
-    NAVRELATION_CONTAINING_DOCUMENT = 0x1011,
-    NAVRELATION_CONTAINING_TAB_PANE = 0x1012,
-    NAVRELATION_CONTAINING_WINDOW = 0x1013,
-    NAVRELATION_CONTAINING_APPLICATION = 0x1014,
-    NAVRELATION_DETAILS = 0x1015,
-    NAVRELATION_DETAILS_FOR = 0x1016,
-    NAVRELATION_ERROR = 0x1017,
-    NAVRELATION_ERROR_FOR = 0x1018
-  };
-
  private:
   /**
    * Find a remote accessible by the given child ID.
    */
   [[nodiscard]] already_AddRefed<IAccessible> GetRemoteIAccessibleFor(
       const VARIANT& aVarChild);
 
   nsTArray<RefPtr<IUnknown>> mAssociatedCOMObjectsForDisconnection;
-
-  /**
-   * Creates ITypeInfo for LIBID_Accessibility if it's needed and returns it.
-   */
-  static ITypeInfo* GetTI(LCID lcid);
-  static ITypeInfo* gTypeInfo;
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #ifdef XP_WIN
 // Undo the windows.h damage
 #  undef GetMessage