summaryrefslogtreecommitdiffstats
path: root/accessible/windows/msaa/MsaaDocAccessible.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/windows/msaa/MsaaDocAccessible.cpp')
-rw-r--r--accessible/windows/msaa/MsaaDocAccessible.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/accessible/windows/msaa/MsaaDocAccessible.cpp b/accessible/windows/msaa/MsaaDocAccessible.cpp
new file mode 100644
index 0000000000..451e26e35c
--- /dev/null
+++ b/accessible/windows/msaa/MsaaDocAccessible.cpp
@@ -0,0 +1,156 @@
+/* -*- 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 "MsaaDocAccessible.h"
+
+#include "MsaaDocAccessible.h"
+#include "DocAccessibleChild.h"
+#include "mozilla/a11y/DocAccessibleParent.h"
+#include "nsAccessibilityService.h"
+#include "nsAccUtils.h"
+#include "nsWinUtils.h"
+#include "Statistics.h"
+#include "sdnDocAccessible.h"
+#include "Role.h"
+#include "ISimpleDOM.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+DocAccessible* MsaaDocAccessible::DocAcc() {
+ return static_cast<DocAccessible*>(LocalAcc());
+}
+
+/* static */
+MsaaDocAccessible* MsaaDocAccessible::GetFrom(DocAccessible* aDoc) {
+ return static_cast<MsaaDocAccessible*>(MsaaAccessible::GetFrom(aDoc));
+}
+
+/* static */
+MsaaDocAccessible* MsaaDocAccessible::GetFrom(DocAccessibleParent* aDoc) {
+ return static_cast<MsaaDocAccessible*>(
+ reinterpret_cast<MsaaAccessible*>(aDoc->GetWrapper()));
+}
+
+/* static */
+MsaaDocAccessible* MsaaDocAccessible::GetFromOwned(Accessible* aAcc) {
+ if (RemoteAccessible* remoteAcc = aAcc->AsRemote()) {
+ DocAccessibleParent* doc = remoteAcc->Document();
+ if (!doc) {
+ return nullptr;
+ }
+ return MsaaDocAccessible::GetFrom(doc);
+ }
+ DocAccessible* doc = aAcc->AsLocal()->Document();
+ if (!doc) {
+ return nullptr;
+ }
+ return MsaaDocAccessible::GetFrom(doc);
+}
+
+// IUnknown
+IMPL_IUNKNOWN_QUERY_HEAD(MsaaDocAccessible)
+if (aIID == IID_ISimpleDOMDocument && LocalAcc()) {
+ statistics::ISimpleDOMUsed();
+ *aInstancePtr = static_cast<ISimpleDOMDocument*>(new sdnDocAccessible(this));
+ static_cast<IUnknown*>(*aInstancePtr)->AddRef();
+ return S_OK;
+}
+IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(ia2AccessibleHypertext)
+
+STDMETHODIMP
+MsaaDocAccessible::get_accParent(
+ /* [retval][out] */ IDispatch __RPC_FAR* __RPC_FAR* ppdispParent) {
+ if (!mAcc) {
+ return CO_E_OBJNOTCONNECTED;
+ }
+
+ if (mAcc->IsRemote()) {
+ DocAccessibleParent* remoteDoc = mAcc->AsRemote()->AsDoc();
+ if (nsWinUtils::IsWindowEmulationStarted() && remoteDoc->IsTopLevel()) {
+ // Window emulation is enabled and this is a top level document. Return
+ // window system accessible object.
+ HWND hwnd = remoteDoc->GetEmulatedWindowHandle();
+ MOZ_ASSERT(hwnd);
+ if (hwnd &&
+ SUCCEEDED(::AccessibleObjectFromWindow(
+ hwnd, OBJID_WINDOW, IID_IAccessible, (void**)ppdispParent))) {
+ return S_OK;
+ }
+ }
+ return MsaaAccessible::get_accParent(ppdispParent);
+ }
+
+ DocAccessible* docAcc = DocAcc();
+ MOZ_ASSERT(docAcc);
+
+ // Return window system accessible object for root document accessibles, as
+ // well as tab document accessibles if window emulation is enabled.
+ MOZ_ASSERT(XRE_IsParentProcess());
+ if ((!docAcc->ParentDocument() ||
+ (nsWinUtils::IsWindowEmulationStarted() &&
+ nsCoreUtils::IsTopLevelContentDocInProcess(docAcc->DocumentNode())))) {
+ HWND hwnd = static_cast<HWND>(docAcc->GetNativeWindow());
+ if (hwnd && !docAcc->ParentDocument()) {
+ nsIFrame* frame = docAcc->GetFrame();
+ if (frame) {
+ nsIWidget* widget = frame->GetNearestWidget();
+ if (widget->GetWindowType() == widget::WindowType::Child &&
+ !widget->GetParent()) {
+ // Bug 1427304: Windows opened with popup=yes (such as the WebRTC
+ // sharing indicator) get two HWNDs. The root widget is associated
+ // with the inner HWND, but the outer HWND still answers to
+ // WM_GETOBJECT queries. This means that getting the parent of the
+ // oleacc window accessible for the inner HWND returns this
+ // root accessible. Thus, to avoid a loop, we must never return the
+ // oleacc window accessible for the inner HWND. Instead, we use the
+ // outer HWND here.
+ HWND parentHwnd = ::GetParent(hwnd);
+ if (parentHwnd) {
+ MOZ_ASSERT(::GetWindowLongW(parentHwnd, GWL_STYLE) & WS_POPUP,
+ "Parent HWND should be a popup!");
+ hwnd = parentHwnd;
+ }
+ }
+ }
+ }
+ if (hwnd &&
+ SUCCEEDED(::AccessibleObjectFromWindow(
+ hwnd, OBJID_WINDOW, IID_IAccessible, (void**)ppdispParent))) {
+ return S_OK;
+ }
+ }
+
+ return MsaaAccessible::get_accParent(ppdispParent);
+}
+
+STDMETHODIMP
+MsaaDocAccessible::get_accValue(VARIANT aVarChild, BSTR __RPC_FAR* aValue) {
+ if (!aValue) return E_INVALIDARG;
+ *aValue = nullptr;
+
+ // For backwards-compat, we still support old MSAA hack to provide URL in
+ // accValue Check for real value first
+ HRESULT hr = MsaaAccessible::get_accValue(aVarChild, aValue);
+ if (FAILED(hr) || *aValue || aVarChild.lVal != CHILDID_SELF) return hr;
+
+ // MsaaAccessible::get_accValue should have failed (and thus we should have
+ // returned early) if the Accessible is dead.
+ MOZ_ASSERT(mAcc);
+ // If document is being used to create a widget, don't use the URL hack
+ roles::Role role = mAcc->Role();
+ if (role != roles::DOCUMENT && role != roles::APPLICATION &&
+ role != roles::DIALOG && role != roles::ALERT &&
+ role != roles::NON_NATIVE_DOCUMENT)
+ return hr;
+
+ nsAutoString url;
+ nsAccUtils::DocumentURL(mAcc, url);
+ if (url.IsEmpty()) return S_FALSE;
+
+ *aValue = ::SysAllocStringLen(url.get(), url.Length());
+ return *aValue ? S_OK : E_OUTOFMEMORY;
+}