зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 6 changesets (bug 1821963) for build bustages. CLOSED TREE
Backed out changeset a92c62e304f0 (bug 1821963) Backed out changeset da6cba0b0dd4 (bug 1821963) Backed out changeset 4ed7ca0eb04a (bug 1821963) Backed out changeset f2fba0ef15d9 (bug 1821963) Backed out changeset 706e46fc2688 (bug 1821963) Backed out changeset 6de2b9548dc6 (bug 1821963)
This commit is contained in:
Родитель
92a0d9b020
Коммит
ed1139f199
|
@ -58,6 +58,11 @@ bool ShouldA11yBeEnabled();
|
|||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/*
|
||||
* Do we have AccessibleHandler.dll registered.
|
||||
*/
|
||||
bool IsHandlerRegistered();
|
||||
|
||||
/*
|
||||
* Name of platform service that instantiated accessibility
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
import "objidl.idl";
|
||||
import "oaidl.idl";
|
||||
|
||||
[object, uuid(7510360f-cdae-4de9-88c8-d167eda62afc)]
|
||||
interface IGeckoCustom : IUnknown
|
||||
{
|
||||
[propget] HRESULT ID([out, retval] unsigned __int64* aID);
|
||||
[propget] HRESULT anchorCount([out, retval] long* aCount);
|
||||
[propget] HRESULT boundsInCSSPixels([out] __int32* aX,
|
||||
[out] __int32* aY,
|
||||
[out] __int32* aWidth,
|
||||
[out, retval] __int32* aHeight);
|
||||
[propget] HRESULT DOMNodeID([out, retval] BSTR* aID);
|
||||
[propget] HRESULT minimumIncrement([out, retval] double* aIncrement);
|
||||
[propget] HRESULT mozState([out, retval] unsigned __int64* aState);
|
||||
}
|
||||
|
||||
|
||||
[
|
||||
uuid(55769d85-f830-4d76-9e39-3670914a28f7),
|
||||
helpstring("private custom gecko interfaces")
|
||||
]
|
||||
library IGeckoCustom
|
||||
{
|
||||
interface IGeckoCustom;
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
GeneratedFile(
|
||||
"IGeckoCustom.h",
|
||||
"IGeckoCustom_p.c",
|
||||
"IGeckoCustom_i.c",
|
||||
"IGeckoCustom_dlldata.c",
|
||||
"IGeckoCustom.tlb",
|
||||
inputs=["IGeckoCustom.idl"],
|
||||
script="/build/midl.py",
|
||||
entry_point="midl",
|
||||
flags=["-dlldata", OBJDIR + "/IGeckoCustom_dlldata.c"],
|
||||
)
|
||||
|
||||
SOURCES += [
|
||||
"!IGeckoCustom_dlldata.c",
|
||||
"!IGeckoCustom_i.c",
|
||||
"!IGeckoCustom_p.c",
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
"!IGeckoCustom.h",
|
||||
"!IGeckoCustom_i.c",
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
# Suppress warnings from the MIDL generated code.
|
||||
if CONFIG["CC_TYPE"] == "clang-cl":
|
||||
CFLAGS += [
|
||||
"-Wno-extern-initializer",
|
||||
"-Wno-incompatible-pointer-types",
|
||||
"-Wno-missing-braces",
|
||||
"-Wno-unused-const-variable",
|
||||
]
|
|
@ -0,0 +1,11 @@
|
|||
;+# 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/.
|
||||
|
||||
LIBRARY IA2Marshal.dll
|
||||
EXPORTS DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
||||
GetProxyDllInfo PRIVATE
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="IA2Marshal" version="1.0.0.0" />
|
||||
<file name="IA2Marshal.dll">
|
||||
<comInterfaceProxyStub
|
||||
iid="{E89F726E-C4F4-4c19-BB19-B647D7FA8478}"
|
||||
proxyStubClsid32="{E89F726E-C4F4-4c19-BB19-B647D7FA8478}"
|
||||
name="IAccessible2"
|
||||
tlbid="{CE3F726E-D1D3-44FE-B995-FF1DB3B48B2B}"
|
||||
/>
|
||||
</file>
|
||||
</assembly>
|
|
@ -0,0 +1,5 @@
|
|||
/* 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/. */
|
||||
|
||||
1 typelib IA2Typelib.tlb
|
|
@ -0,0 +1,61 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
typedef struct _MozRemotableHandle
|
||||
{
|
||||
long fContext;
|
||||
long hRemote;
|
||||
} MozRemotableHandle;
|
||||
|
||||
typedef [unique] MozRemotableHandle * mozHWND;
|
||||
typedef [unique] MozRemotableHandle * mozHMENU;
|
||||
typedef [unique] MozRemotableHandle * mozHACCEL;
|
||||
typedef [unique] MozRemotableHandle * mozHBRUSH;
|
||||
typedef [unique] MozRemotableHandle * mozHFONT;
|
||||
typedef [unique] MozRemotableHandle * mozHDC;
|
||||
typedef [unique] MozRemotableHandle * mozHICON;
|
||||
typedef [unique] MozRemotableHandle * mozHRGN;
|
||||
typedef [unique] MozRemotableHandle * mozHMONITOR;
|
||||
|
||||
cpp_quote("#if 0")
|
||||
typedef [wire_marshal(mozHWND)] void* HWND;
|
||||
typedef [wire_marshal(mozHMENU)] void* HMENU;
|
||||
typedef [wire_marshal(mozHACCEL)] void* HACCEL;
|
||||
typedef [wire_marshal(mozHBRUSH)] void* HBRUSH;
|
||||
typedef [wire_marshal(mozHFONT)] void* HFONT;
|
||||
typedef [wire_marshal(mozHDC)] void* HDC;
|
||||
typedef [wire_marshal(mozHICON)] void* HICON;
|
||||
typedef [wire_marshal(mozHRGN)] void* HRGN;
|
||||
typedef [wire_marshal(mozHMONITOR)] void* HMONITOR;
|
||||
cpp_quote("#endif // 0")
|
||||
|
||||
import "Accessible2.idl";
|
||||
import "Accessible2_2.idl";
|
||||
import "Accessible2_3.idl";
|
||||
import "AccessibleAction.idl";
|
||||
import "AccessibleApplication.idl";
|
||||
import "AccessibleComponent.idl";
|
||||
import "AccessibleDocument.idl";
|
||||
import "AccessibleEditableText.idl";
|
||||
import "AccessibleEventId.idl";
|
||||
import "AccessibleHyperlink.idl";
|
||||
import "AccessibleHypertext.idl";
|
||||
import "AccessibleHypertext2.idl";
|
||||
import "AccessibleImage.idl";
|
||||
import "AccessibleRelation.idl";
|
||||
import "AccessibleRole.idl";
|
||||
import "AccessibleStates.idl";
|
||||
import "AccessibleTable.idl";
|
||||
import "AccessibleTable2.idl";
|
||||
import "AccessibleTableCell.idl";
|
||||
import "AccessibleText.idl";
|
||||
import "AccessibleText2.idl";
|
||||
import "AccessibleValue.idl";
|
||||
import "IA2CommonTypes.idl";
|
||||
|
||||
// We are explicitly using #include instead of import so that the imported
|
||||
// IDL is treated as part of this IDL file.
|
||||
#include "IA2TypeLibrary.idl"
|
|
@ -4,6 +4,20 @@
|
|||
# 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/.
|
||||
|
||||
GeckoSharedLibrary("IA2Marshal", linkage=None)
|
||||
|
||||
DEFINES["REGISTER_PROXY_DLL"] = True
|
||||
|
||||
DEFFILE = "IA2Marshal.def"
|
||||
|
||||
OS_LIBS += [
|
||||
"uuid",
|
||||
"kernel32",
|
||||
"rpcrt4",
|
||||
"ole32",
|
||||
"oleaut32",
|
||||
]
|
||||
|
||||
midl_enums = [
|
||||
"AccessibleEventId",
|
||||
"AccessibleRole",
|
||||
|
@ -76,3 +90,42 @@ for iface in midl_interfaces:
|
|||
SOURCES["!%s" % p].flags += [
|
||||
"-DUserMarshalRoutines=UserMarshalRoutines__%s" % p[:-2]
|
||||
]
|
||||
|
||||
# Warning: the build system doesn't know about the dependency of IA2Marshal.rc on
|
||||
# IA2Typelib.tlb. We rely on the IA2Typelib.h output forcing the command to run
|
||||
# during export, before rc files are treated during compile.
|
||||
GeneratedFile(
|
||||
"IA2Typelib.h",
|
||||
"IA2Typelib_i.c",
|
||||
"IA2Typelib.tlb",
|
||||
inputs=["IA2Typelib.idl"],
|
||||
script="/build/midl.py",
|
||||
entry_point="midl",
|
||||
flags=[
|
||||
"-app_config",
|
||||
"-I",
|
||||
TOPSRCDIR + "/other-licenses/ia2",
|
||||
"-D",
|
||||
"_MIDL_DECLARE_WIREM_HANDLE",
|
||||
],
|
||||
)
|
||||
|
||||
GeneratedFile(
|
||||
"dlldata.c",
|
||||
inputs=["!" + iface + "_dlldata.c" for iface in midl_interfaces],
|
||||
script="/build/midl.py",
|
||||
entry_point="merge_dlldata",
|
||||
)
|
||||
|
||||
SOURCES += ["!dlldata.c"]
|
||||
|
||||
RCINCLUDE = "IA2Marshal.rc"
|
||||
|
||||
# Suppress warnings from the MIDL generated code.
|
||||
if CONFIG["CC_TYPE"] == "clang-cl":
|
||||
CFLAGS += [
|
||||
"-Wno-extern-initializer",
|
||||
"-Wno-incompatible-pointer-types",
|
||||
"-Wno-missing-braces",
|
||||
"-Wno-unused-const-variable",
|
||||
]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows" and CONFIG["COMPILE_ENVIRONMENT"]:
|
||||
DIRS += ["msaa", "ia2"]
|
||||
DIRS += ["gecko", "msaa", "ia2"]
|
||||
|
||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
||||
XPIDL_SOURCES += ["nsIAccessibleMacInterface.idl"]
|
||||
|
|
|
@ -164,6 +164,43 @@ typedef uint32_t role;
|
|||
* define types used by PDocAccessible differently depending on platform.
|
||||
*/
|
||||
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
|
||||
// So that we don't include a bunch of other Windows junk.
|
||||
# if !defined(COM_NO_WINDOWS_H)
|
||||
# define COM_NO_WINDOWS_H
|
||||
# endif // !defined(COM_NO_WINDOWS_H)
|
||||
|
||||
// COM headers pull in MSXML which conflicts with our own XMLDocument class.
|
||||
// This define excludes those conflicting definitions.
|
||||
# if !defined(__XMLDocument_FWD_DEFINED__)
|
||||
# define __XMLDocument_FWD_DEFINED__
|
||||
# endif // !defined(__XMLDocument_FWD_DEFINED__)
|
||||
|
||||
# include <combaseapi.h>
|
||||
|
||||
# include "mozilla/a11y/COMPtrTypes.h"
|
||||
|
||||
// This define in rpcndr.h messes up our code, so we must undefine it after
|
||||
// COMPtrTypes.h has been included.
|
||||
# if defined(small)
|
||||
# undef small
|
||||
# endif // defined(small)
|
||||
|
||||
#else
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
typedef uint32_t IAccessibleHolder;
|
||||
typedef uint32_t IDispatchHolder;
|
||||
typedef uint32_t IHandlerControlHolder;
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
|
||||
#if defined(MOZ_WIDGET_COCOA)
|
||||
# if defined(ACCESSIBILITY)
|
||||
# include "mozilla/a11y/PlatformExtTypes.h"
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- 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 "mozilla/a11y/COMPtrTypes.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/a11y/LocalAccessible.h"
|
||||
#include "mozilla/a11y/HandlerProvider.h"
|
||||
#include "mozilla/a11y/Platform.h"
|
||||
#include "mozilla/mscom/MainThreadHandoff.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using mozilla::mscom::MainThreadHandoff;
|
||||
using mozilla::mscom::ProxyUniquePtr;
|
||||
using mozilla::mscom::STAUniquePtr;
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
IAccessibleHolder CreateHolderFromAccessible(
|
||||
NotNull<LocalAccessible*> aAccToWrap) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
STAUniquePtr<IAccessible> iaToProxy;
|
||||
aAccToWrap->GetNativeInterface(mscom::getter_AddRefs(iaToProxy));
|
||||
MOZ_DIAGNOSTIC_ASSERT(iaToProxy);
|
||||
if (!iaToProxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const bool useHandler =
|
||||
Preferences::GetBool("accessibility.handler.enabled", false) &&
|
||||
IsHandlerRegistered();
|
||||
|
||||
RefPtr<HandlerProvider> payload;
|
||||
if (useHandler) {
|
||||
payload = new HandlerProvider(IID_IAccessible,
|
||||
mscom::ToInterceptorTargetPtr(iaToProxy));
|
||||
}
|
||||
|
||||
ProxyUniquePtr<IAccessible> intercepted;
|
||||
HRESULT hr = MainThreadHandoff::WrapInterface(
|
||||
std::move(iaToProxy), payload,
|
||||
(IAccessible**)mscom::getter_AddRefs(intercepted));
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return IAccessibleHolder(std::move(intercepted));
|
||||
}
|
||||
|
||||
IHandlerControlHolder CreateHolderFromHandlerControl(
|
||||
mscom::ProxyUniquePtr<IHandlerControl> aHandlerControl) {
|
||||
MOZ_ASSERT(aHandlerControl);
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!aHandlerControl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return IHandlerControlHolder(std::move(aHandlerControl));
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_a11y_COMPtrTypes_h
|
||||
#define mozilla_a11y_COMPtrTypes_h
|
||||
|
||||
#include "mozilla/a11y/AccessibleHandler.h"
|
||||
#include "mozilla/mscom/ActCtxResource.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/mscom/ActivationContext.h"
|
||||
#include "mozilla/mscom/COMPtrHolder.h"
|
||||
#include "mozilla/NotNull.h"
|
||||
|
||||
#include <oleacc.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class MOZ_RAII IAccessibleEnvironment : public mscom::ProxyStream::Environment {
|
||||
public:
|
||||
IAccessibleEnvironment() = default;
|
||||
|
||||
bool Push() override {
|
||||
mActCtxRgn = GetActCtx();
|
||||
return !!mActCtxRgn;
|
||||
}
|
||||
|
||||
bool Pop() override { return mActCtxRgn.Deactivate(); }
|
||||
|
||||
private:
|
||||
static const mscom::ActivationContext& GetActCtx() {
|
||||
static const mscom::ActivationContext sActCtx(
|
||||
mscom::ActCtxResource::GetAccessibilityResource());
|
||||
MOZ_DIAGNOSTIC_ASSERT(sActCtx);
|
||||
return sActCtx;
|
||||
}
|
||||
|
||||
private:
|
||||
mscom::ActivationContextRegion mActCtxRgn;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
||||
namespace mscom {
|
||||
namespace detail {
|
||||
|
||||
template <>
|
||||
struct EnvironmentSelector<IAccessible> {
|
||||
typedef a11y::IAccessibleEnvironment Type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mscom
|
||||
|
||||
namespace a11y {
|
||||
|
||||
typedef mozilla::mscom::COMPtrHolder<IAccessible, IID_IAccessible>
|
||||
IAccessibleHolder;
|
||||
typedef mozilla::mscom::COMPtrHolder<IDispatch, IID_IDispatch> IDispatchHolder;
|
||||
|
||||
class LocalAccessible;
|
||||
|
||||
IAccessibleHolder CreateHolderFromAccessible(
|
||||
NotNull<LocalAccessible*> aAccToWrap);
|
||||
|
||||
typedef mozilla::mscom::COMPtrHolder<IHandlerControl, IID_IHandlerControl>
|
||||
IHandlerControlHolder;
|
||||
|
||||
IHandlerControlHolder CreateHolderFromHandlerControl(
|
||||
mscom::ProxyUniquePtr<IHandlerControl> aHandlerControl);
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_COMPtrTypes_h
|
|
@ -7,13 +7,22 @@
|
|||
#include "DocAccessibleChild.h"
|
||||
|
||||
#include "LocalAccessible-inl.h"
|
||||
#include "mozilla/a11y/PlatformChild.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
static StaticAutoPtr<PlatformChild> sPlatformChild;
|
||||
|
||||
DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager)
|
||||
: DocAccessibleChildBase(aDoc) {
|
||||
MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
|
||||
if (!sPlatformChild) {
|
||||
sPlatformChild = new PlatformChild();
|
||||
ClearOnShutdown(&sPlatformChild, ShutdownPhase::XPCOMShutdown);
|
||||
}
|
||||
|
||||
SetManager(aManager);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,968 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/a11y/HandlerProvider.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "Accessible2_3.h"
|
||||
#include "AccessibleApplication.h"
|
||||
#include "AccessibleDocument.h"
|
||||
#include "AccessibleEditableText.h"
|
||||
#include "AccessibleImage.h"
|
||||
#include "AccessibleRelation.h"
|
||||
#include "AccessibleTable.h"
|
||||
#include "AccessibleTable2.h"
|
||||
#include "AccessibleTableCell.h"
|
||||
#include "HandlerData.h"
|
||||
#include "HandlerData_i.c"
|
||||
#include "ISimpleDOM.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/a11y/AccessibleWrap.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/mscom/AgileReference.h"
|
||||
#include "mozilla/mscom/FastMarshaler.h"
|
||||
#include "mozilla/mscom/Interceptor.h"
|
||||
#include "mozilla/mscom/MainThreadHandoff.h"
|
||||
#include "mozilla/mscom/MainThreadInvoker.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/StructStream.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "uiautomation.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
HandlerProvider::HandlerProvider(REFIID aIid,
|
||||
mscom::InterceptorTargetPtr<IUnknown> aTarget)
|
||||
: mRefCnt(0),
|
||||
mMutex("mozilla::a11y::HandlerProvider::mMutex"),
|
||||
mTargetUnkIid(aIid),
|
||||
mTargetUnk(std::move(aTarget)),
|
||||
mPayloadMutex("mozilla::a11y::HandlerProvider::mPayloadMutex") {}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::QueryInterface(REFIID riid, void** ppv) {
|
||||
if (!ppv) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (riid == IID_IUnknown || riid == IID_IGeckoBackChannel) {
|
||||
RefPtr<IUnknown> punk(static_cast<IGeckoBackChannel*>(this));
|
||||
punk.forget(ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (riid == IID_IMarshal) {
|
||||
if (!mFastMarshalUnk) {
|
||||
HRESULT hr =
|
||||
mscom::FastMarshaler::Create(static_cast<IGeckoBackChannel*>(this),
|
||||
getter_AddRefs(mFastMarshalUnk));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
return mFastMarshalUnk->QueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
HandlerProvider::AddRef() { return ++mRefCnt; }
|
||||
|
||||
ULONG
|
||||
HandlerProvider::Release() {
|
||||
ULONG result = --mRefCnt;
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::GetHandler(NotNull<CLSID*> aHandlerClsid) {
|
||||
if (!IsTargetInterfaceCacheable()) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
*aHandlerClsid = CLSID_AccessibleHandler;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void HandlerProvider::GetAndSerializePayload(
|
||||
const MutexAutoLock&, NotNull<mscom::IInterceptor*> aInterceptor) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (mSerializer) {
|
||||
return;
|
||||
}
|
||||
|
||||
IA2PayloadPtr payload;
|
||||
{ // Scope for lock
|
||||
MutexAutoLock lock(mPayloadMutex);
|
||||
if (mPayload) {
|
||||
// The payload was already built by prebuildPayload() called during a
|
||||
// bulk fetch operation.
|
||||
payload = std::move(mPayload);
|
||||
}
|
||||
}
|
||||
|
||||
if (!payload) {
|
||||
// We don't have a pre-built payload, so build it now.
|
||||
payload.reset(new IA2Payload());
|
||||
if (!mscom::InvokeOnMainThread(
|
||||
"HandlerProvider::BuildInitialIA2Data", this,
|
||||
&HandlerProvider::BuildInitialIA2Data,
|
||||
std::forward<NotNull<mscom::IInterceptor*>>(aInterceptor),
|
||||
std::forward<StaticIA2Data*>(&payload->mStaticData),
|
||||
std::forward<DynamicIA2Data*>(&payload->mDynamicData)) ||
|
||||
!payload->mDynamicData.mUniqueId) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// But we set mGeckoBackChannel on the current thread which resides in the
|
||||
// MTA. This is important to ensure that COM always invokes
|
||||
// IGeckoBackChannel methods in an MTA background thread.
|
||||
RefPtr<IGeckoBackChannel> payloadRef(this);
|
||||
// AddRef/Release pair for this reference is handled by payloadRef
|
||||
payload->mGeckoBackChannel = this;
|
||||
|
||||
mSerializer = MakeUnique<mscom::StructToStream>(*payload, &IA2Payload_Encode);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::GetHandlerPayloadSize(
|
||||
NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
NotNull<DWORD*> aOutPayloadSize) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!IsTargetInterfaceCacheable()) {
|
||||
// No handler, so no payload for this instance.
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
GetAndSerializePayload(lock, aInterceptor);
|
||||
|
||||
if (!mSerializer || !(*mSerializer)) {
|
||||
// Failed payload serialization is non-fatal
|
||||
*aOutPayloadSize = mscom::StructToStream::GetEmptySize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*aOutPayloadSize = mSerializer->GetSize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void HandlerProvider::BuildStaticIA2Data(
|
||||
NotNull<mscom::IInterceptor*> aInterceptor, StaticIA2Data* aOutData) {
|
||||
MOZ_ASSERT(aOutData);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mTargetUnk);
|
||||
MOZ_ASSERT(IsTargetInterfaceCacheable());
|
||||
|
||||
// Include interfaces the client is likely to request.
|
||||
// This is cheap here and saves multiple cross-process calls later.
|
||||
// These interfaces must be released in ReleaseStaticIA2DataInterfaces!
|
||||
|
||||
// If the target is already an IAccessible2, this pointer is redundant.
|
||||
// However, the target might be an IAccessibleHyperlink, etc., in which
|
||||
// case the client will almost certainly QI for IAccessible2.
|
||||
HRESULT hr = aInterceptor->GetInterceptorForIID(NEWEST_IA2_IID,
|
||||
(void**)&aOutData->mIA2);
|
||||
if (FAILED(hr)) {
|
||||
// IA2 should always be present, so something has
|
||||
// gone very wrong if this fails.
|
||||
aOutData->mIA2 = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Some of these interfaces aren't present on all accessibles,
|
||||
// so it's not a failure if these interfaces can't be fetched.
|
||||
hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHypertext2,
|
||||
(void**)&aOutData->mIAHypertext);
|
||||
if (FAILED(hr)) {
|
||||
aOutData->mIAHypertext = nullptr;
|
||||
}
|
||||
|
||||
hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHyperlink,
|
||||
(void**)&aOutData->mIAHyperlink);
|
||||
if (FAILED(hr)) {
|
||||
aOutData->mIAHyperlink = nullptr;
|
||||
}
|
||||
|
||||
hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleTable,
|
||||
(void**)&aOutData->mIATable);
|
||||
if (FAILED(hr)) {
|
||||
aOutData->mIATable = nullptr;
|
||||
}
|
||||
|
||||
hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleTable2,
|
||||
(void**)&aOutData->mIATable2);
|
||||
if (FAILED(hr)) {
|
||||
aOutData->mIATable2 = nullptr;
|
||||
}
|
||||
|
||||
hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleTableCell,
|
||||
(void**)&aOutData->mIATableCell);
|
||||
if (FAILED(hr)) {
|
||||
aOutData->mIATableCell = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerProvider::BuildDynamicIA2Data(DynamicIA2Data* aOutIA2Data,
|
||||
bool aMarshaledByCom) {
|
||||
MOZ_ASSERT(aOutIA2Data);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(IsTargetInterfaceCacheable());
|
||||
|
||||
if (!mTargetUnk) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<NEWEST_IA2_INTERFACE> target;
|
||||
HRESULT hr =
|
||||
mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID, getter_AddRefs(target));
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = E_UNEXPECTED;
|
||||
|
||||
auto hasFailed = [&hr]() -> bool { return FAILED(hr); };
|
||||
|
||||
auto cleanup = [aOutIA2Data, aMarshaledByCom]() -> void {
|
||||
CleanupDynamicIA2Data(*aOutIA2Data, aMarshaledByCom);
|
||||
};
|
||||
|
||||
mscom::ExecuteWhen<decltype(hasFailed), decltype(cleanup)> onFail(hasFailed,
|
||||
cleanup);
|
||||
|
||||
// When allocating memory to be returned to the client, you *must* use
|
||||
// allocMem, not CoTaskMemAlloc!
|
||||
auto allocMem = [aMarshaledByCom](size_t aSize) {
|
||||
if (aMarshaledByCom) {
|
||||
return ::CoTaskMemAlloc(aSize);
|
||||
}
|
||||
// We use midl_user_allocate rather than CoTaskMemAlloc because this
|
||||
// struct is being marshaled by RPC, not COM.
|
||||
return ::midl_user_allocate(aSize);
|
||||
};
|
||||
|
||||
const VARIANT kChildIdSelf = {VT_I4};
|
||||
VARIANT varVal;
|
||||
|
||||
hr = target->accLocation(&aOutIA2Data->mLeft, &aOutIA2Data->mTop,
|
||||
&aOutIA2Data->mWidth, &aOutIA2Data->mHeight,
|
||||
kChildIdSelf);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_accRole(kChildIdSelf, &aOutIA2Data->mRole);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_accState(kChildIdSelf, &varVal);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aOutIA2Data->mState = varVal.lVal;
|
||||
|
||||
hr = target->get_accKeyboardShortcut(kChildIdSelf,
|
||||
&aOutIA2Data->mKeyboardShortcut);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_accName(kChildIdSelf, &aOutIA2Data->mName);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_accDescription(kChildIdSelf, &aOutIA2Data->mDescription);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_accDefaultAction(kChildIdSelf, &aOutIA2Data->mDefaultAction);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_accChildCount(&aOutIA2Data->mChildCount);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_accValue(kChildIdSelf, &aOutIA2Data->mValue);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_states(&aOutIA2Data->mIA2States);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->get_attributes(&aOutIA2Data->mAttributes);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
HWND hwnd;
|
||||
hr = target->get_windowHandle(&hwnd);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aOutIA2Data->mHwnd = PtrToLong(hwnd);
|
||||
|
||||
hr = target->get_locale(&aOutIA2Data->mIA2Locale);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = target->role(&aOutIA2Data->mIA2Role);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<IAccessibleAction> action;
|
||||
// It is not an error if this fails.
|
||||
hr = mTargetUnk.get()->QueryInterface(IID_IAccessibleAction,
|
||||
getter_AddRefs(action));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = action->nActions(&aOutIA2Data->mNActions);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<IAccessibleTableCell> cell;
|
||||
// It is not an error if this fails.
|
||||
hr = mTargetUnk.get()->QueryInterface(IID_IAccessibleTableCell,
|
||||
getter_AddRefs(cell));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = cell->get_rowColumnExtents(
|
||||
&aOutIA2Data->mRowIndex, &aOutIA2Data->mColumnIndex,
|
||||
&aOutIA2Data->mRowExtent, &aOutIA2Data->mColumnExtent,
|
||||
&aOutIA2Data->mCellIsSelected);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Because the same headers can apply to many cells, include the ids of
|
||||
// header cells, rather than the actual objects. Otherwise, we might
|
||||
// end up marshaling the same objects (and their payloads) many times.
|
||||
IUnknown** headers = nullptr;
|
||||
hr = cell->get_rowHeaderCells(&headers, &aOutIA2Data->mNRowHeaderCells);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
if (aOutIA2Data->mNRowHeaderCells > 0) {
|
||||
aOutIA2Data->mRowHeaderCellIds = static_cast<long*>(
|
||||
allocMem(sizeof(long) * aOutIA2Data->mNRowHeaderCells));
|
||||
for (long i = 0; i < aOutIA2Data->mNRowHeaderCells; ++i) {
|
||||
RefPtr<IAccessible2> headerAcc;
|
||||
hr = headers[i]->QueryInterface(IID_IAccessible2,
|
||||
getter_AddRefs(headerAcc));
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
headers[i]->Release();
|
||||
hr = headerAcc->get_uniqueID(&aOutIA2Data->mRowHeaderCellIds[i]);
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
}
|
||||
::CoTaskMemFree(headers);
|
||||
|
||||
hr = cell->get_columnHeaderCells(&headers,
|
||||
&aOutIA2Data->mNColumnHeaderCells);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
if (aOutIA2Data->mNColumnHeaderCells > 0) {
|
||||
aOutIA2Data->mColumnHeaderCellIds = static_cast<long*>(
|
||||
allocMem(sizeof(long) * aOutIA2Data->mNColumnHeaderCells));
|
||||
for (long i = 0; i < aOutIA2Data->mNColumnHeaderCells; ++i) {
|
||||
RefPtr<IAccessible2> headerAcc;
|
||||
hr = headers[i]->QueryInterface(IID_IAccessible2,
|
||||
getter_AddRefs(headerAcc));
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
headers[i]->Release();
|
||||
hr = headerAcc->get_uniqueID(&aOutIA2Data->mColumnHeaderCellIds[i]);
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
}
|
||||
::CoTaskMemFree(headers);
|
||||
}
|
||||
|
||||
// NB: get_uniqueID should be the final property retrieved in this method,
|
||||
// as its presence is used to determine whether the rest of this data
|
||||
// retrieval was successful.
|
||||
hr = target->get_uniqueID(&aOutIA2Data->mUniqueId);
|
||||
}
|
||||
|
||||
void HandlerProvider::BuildInitialIA2Data(
|
||||
NotNull<mscom::IInterceptor*> aInterceptor, StaticIA2Data* aOutStaticData,
|
||||
DynamicIA2Data* aOutDynamicData) {
|
||||
BuildStaticIA2Data(aInterceptor, aOutStaticData);
|
||||
if (!aOutStaticData->mIA2) {
|
||||
return;
|
||||
}
|
||||
BuildDynamicIA2Data(aOutDynamicData);
|
||||
}
|
||||
|
||||
bool HandlerProvider::IsTargetInterfaceCacheable() {
|
||||
return MarshalAs(mTargetUnkIid) == NEWEST_IA2_IID ||
|
||||
mTargetUnkIid == IID_IAccessibleHyperlink;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::WriteHandlerPayload(NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
NotNull<IStream*> aStream) {
|
||||
if (!IsTargetInterfaceCacheable()) {
|
||||
// No handler, so no payload for this instance.
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mSerializer || !(*mSerializer)) {
|
||||
// Failed payload serialization is non-fatal
|
||||
mscom::StructToStream emptyStruct;
|
||||
return emptyStruct.Write(aStream);
|
||||
}
|
||||
|
||||
HRESULT hr = mSerializer->Write(aStream);
|
||||
|
||||
mSerializer.reset();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
REFIID
|
||||
HandlerProvider::MarshalAs(REFIID aIid) {
|
||||
static_assert(&NEWEST_IA2_IID == &IID_IAccessible2_3,
|
||||
"You have modified NEWEST_IA2_IID. This code needs updating.");
|
||||
if (aIid == IID_IDispatch || aIid == IID_IAccessible ||
|
||||
aIid == IID_IAccessible2 || aIid == IID_IAccessible2_2 ||
|
||||
aIid == IID_IAccessible2_3) {
|
||||
// This should always be the newest IA2 interface ID
|
||||
return NEWEST_IA2_IID;
|
||||
}
|
||||
// Otherwise we juse return the identity.
|
||||
return aIid;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::DisconnectHandlerRemotes() {
|
||||
// If a handlerProvider call is pending on another thread,
|
||||
// CoDisconnectObject won't release this HandlerProvider immediately.
|
||||
// However, the interceptor and its target (mTargetUnk) might be destroyed.
|
||||
mTargetUnk = nullptr;
|
||||
|
||||
IUnknown* unk = static_cast<IGeckoBackChannel*>(this);
|
||||
return ::CoDisconnectObject(unk, 0);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::IsInterfaceMaybeSupported(REFIID aIid) {
|
||||
static_assert(&NEWEST_IA2_IID == &IID_IAccessible2_3,
|
||||
"You have modified NEWEST_IA2_IID. This code needs updating.");
|
||||
if (aIid == IID_IUnknown || aIid == IID_IDispatch ||
|
||||
aIid == IID_IAccessible || aIid == IID_IServiceProvider ||
|
||||
aIid == IID_IEnumVARIANT || aIid == IID_IAccessible2 ||
|
||||
aIid == IID_IAccessible2_2 || aIid == IID_IAccessible2_3 ||
|
||||
aIid == IID_IAccessibleAction || aIid == IID_IAccessibleApplication ||
|
||||
aIid == IID_IAccessibleComponent || aIid == IID_IAccessibleDocument ||
|
||||
aIid == IID_IAccessibleEditableText || aIid == IID_IAccessibleHyperlink ||
|
||||
aIid == IID_IAccessibleHypertext || aIid == IID_IAccessibleHypertext2 ||
|
||||
aIid == IID_IAccessibleImage || aIid == IID_IAccessibleRelation ||
|
||||
aIid == IID_IAccessibleTable || aIid == IID_IAccessibleTable2 ||
|
||||
aIid == IID_IAccessibleTableCell || aIid == IID_IAccessibleText ||
|
||||
aIid == IID_IAccessibleValue || aIid == IID_ISimpleDOMNode ||
|
||||
aIid == IID_ISimpleDOMDocument || aIid == IID_ISimpleDOMText ||
|
||||
aIid == IID_IAccessibleEx || aIid == IID_IRawElementProviderSimple) {
|
||||
return S_OK;
|
||||
}
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
REFIID
|
||||
HandlerProvider::GetEffectiveOutParamIid(REFIID aCallIid, ULONG aCallMethod) {
|
||||
if (aCallIid == IID_IAccessibleTable || aCallIid == IID_IAccessibleTable2 ||
|
||||
aCallIid == IID_IAccessibleDocument ||
|
||||
aCallIid == IID_IAccessibleTableCell ||
|
||||
aCallIid == IID_IAccessibleRelation) {
|
||||
return NEWEST_IA2_IID;
|
||||
}
|
||||
|
||||
// IAccessible2_2::accessibleWithCaret
|
||||
static_assert(&NEWEST_IA2_IID == &IID_IAccessible2_3,
|
||||
"You have modified NEWEST_IA2_IID. This code needs updating.");
|
||||
if ((aCallIid == IID_IAccessible2_2 || aCallIid == IID_IAccessible2_3) &&
|
||||
aCallMethod == 47) {
|
||||
return NEWEST_IA2_IID;
|
||||
}
|
||||
|
||||
// IAccessible::get_accSelection
|
||||
if ((aCallIid == IID_IAccessible || aCallIid == IID_IAccessible2 ||
|
||||
aCallIid == IID_IAccessible2_2 || aCallIid == IID_IAccessible2_3) &&
|
||||
aCallMethod == 19) {
|
||||
return IID_IEnumVARIANT;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false);
|
||||
return IID_IUnknown;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::NewInstance(
|
||||
REFIID aIid, mscom::InterceptorTargetPtr<IUnknown> aTarget,
|
||||
NotNull<mscom::IHandlerProvider**> aOutNewPayload) {
|
||||
RefPtr<IHandlerProvider> newPayload(
|
||||
new HandlerProvider(aIid, std::move(aTarget)));
|
||||
newPayload.forget(aOutNewPayload.get());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void HandlerProvider::SetHandlerControlOnMainThread(
|
||||
DWORD aPid, mscom::ProxyUniquePtr<IHandlerControl> aCtrl) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// XXX This is no longer used and will soon be removed.
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::put_HandlerControl(long aPid, IHandlerControl* aCtrl) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!aCtrl) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
auto ptrProxy = mscom::ToProxyUniquePtr(aCtrl);
|
||||
|
||||
if (!mscom::InvokeOnMainThread(
|
||||
"HandlerProvider::SetHandlerControlOnMainThread", this,
|
||||
&HandlerProvider::SetHandlerControlOnMainThread,
|
||||
static_cast<DWORD>(aPid), std::move(ptrProxy))) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::Refresh(DynamicIA2Data* aOutData) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!mTargetUnk) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
|
||||
if (!mscom::InvokeOnMainThread("HandlerProvider::BuildDynamicIA2Data", this,
|
||||
&HandlerProvider::BuildDynamicIA2Data,
|
||||
std::forward<DynamicIA2Data*>(aOutData),
|
||||
/* aMarshaledByCom */ true)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (!aOutData->mUniqueId) {
|
||||
// BuildDynamicIA2Data failed.
|
||||
if (!mTargetUnk) {
|
||||
// Even though we checked this before, the accessible can be shut down
|
||||
// before BuildDynamicIA2Data executes on the main thread.
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void HandlerProvider::PrebuildPayload(
|
||||
NotNull<mscom::IInterceptor*> aInterceptor) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MutexAutoLock lock(mPayloadMutex);
|
||||
mPayload.reset(new IA2Payload());
|
||||
BuildInitialIA2Data(aInterceptor, &mPayload->mStaticData,
|
||||
&mPayload->mDynamicData);
|
||||
if (!mPayload->mDynamicData.mUniqueId) {
|
||||
// Building the payload failed.
|
||||
mPayload.reset();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Interface>
|
||||
HRESULT HandlerProvider::ToWrappedObject(Interface** aObj) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mscom::STAUniquePtr<Interface> inObj(*aObj);
|
||||
RefPtr<HandlerProvider> hprov = new HandlerProvider(
|
||||
__uuidof(Interface), mscom::ToInterceptorTargetPtr(inObj));
|
||||
HRESULT hr =
|
||||
mscom::MainThreadHandoff::WrapInterface(std::move(inObj), hprov, aObj);
|
||||
if (FAILED(hr)) {
|
||||
*aObj = nullptr;
|
||||
return hr;
|
||||
}
|
||||
// Build the payload for this object now to avoid a cross-thread call when
|
||||
// marshaling it later.
|
||||
RefPtr<mscom::IInterceptor> interceptor;
|
||||
hr = (*aObj)->QueryInterface(mscom::IID_IInterceptor,
|
||||
getter_AddRefs(interceptor));
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
// Even though we created a new HandlerProvider, that won't be used if
|
||||
// there's an existing Interceptor. Therefore, we must get the
|
||||
// HandlerProvider from the Interceptor.
|
||||
RefPtr<mscom::IInterceptorSink> interceptorSink;
|
||||
interceptor->GetEventSink(getter_AddRefs(interceptorSink));
|
||||
MOZ_ASSERT(interceptorSink);
|
||||
RefPtr<mscom::IMainThreadHandoff> handoff;
|
||||
hr = interceptorSink->QueryInterface(mscom::IID_IMainThreadHandoff,
|
||||
getter_AddRefs(handoff));
|
||||
// If a11y Interceptors stop using MainThreadHandoff as their event sink, we
|
||||
// *really* want to know about it ASAP.
|
||||
MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(hr),
|
||||
"A11y Interceptor isn't using MainThreadHandoff");
|
||||
RefPtr<mscom::IHandlerProvider> usedIHprov;
|
||||
handoff->GetHandlerProvider(getter_AddRefs(usedIHprov));
|
||||
MOZ_ASSERT(usedIHprov);
|
||||
auto usedHprov = static_cast<HandlerProvider*>(usedIHprov.get());
|
||||
usedHprov->PrebuildPayload(WrapNotNull(interceptor));
|
||||
return hr;
|
||||
}
|
||||
|
||||
void HandlerProvider::GetAllTextInfoMainThread(
|
||||
BSTR* aText, IAccessibleHyperlink*** aHyperlinks, long* aNHyperlinks,
|
||||
IA2TextSegment** aAttribRuns, long* aNAttribRuns, HRESULT* result) {
|
||||
MOZ_ASSERT(aText);
|
||||
MOZ_ASSERT(aHyperlinks);
|
||||
MOZ_ASSERT(aNHyperlinks);
|
||||
MOZ_ASSERT(aAttribRuns);
|
||||
MOZ_ASSERT(aNAttribRuns);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTargetUnk) {
|
||||
*result = CO_E_OBJNOTCONNECTED;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<IAccessibleHypertext2> ht;
|
||||
HRESULT hr =
|
||||
mTargetUnk->QueryInterface(IID_IAccessibleHypertext2, getter_AddRefs(ht));
|
||||
if (FAILED(hr)) {
|
||||
*result = hr;
|
||||
return;
|
||||
}
|
||||
|
||||
hr = ht->get_text(0, IA2_TEXT_OFFSET_LENGTH, aText);
|
||||
if (FAILED(hr)) {
|
||||
*result = hr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hr == S_FALSE) {
|
||||
// No text.
|
||||
*aHyperlinks = nullptr;
|
||||
*aNHyperlinks = 0;
|
||||
*aAttribRuns = nullptr;
|
||||
*aNAttribRuns = 0;
|
||||
*result = S_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
hr = ht->get_hyperlinks(aHyperlinks, aNHyperlinks);
|
||||
if (FAILED(hr)) {
|
||||
*aHyperlinks = nullptr;
|
||||
// -1 signals to the handler that it should call hyperlinks itself.
|
||||
*aNHyperlinks = -1;
|
||||
}
|
||||
// We must wrap these hyperlinks in an interceptor.
|
||||
for (long index = 0; index < *aNHyperlinks; ++index) {
|
||||
ToWrappedObject(&(*aHyperlinks)[index]);
|
||||
}
|
||||
|
||||
// Fetch all attribute runs.
|
||||
nsTArray<IA2TextSegment> attribRuns;
|
||||
long end = 0;
|
||||
long length = ::SysStringLen(*aText);
|
||||
while (end < length) {
|
||||
long offset = end;
|
||||
long start;
|
||||
BSTR attribs;
|
||||
// The (exclusive) end of the last run is the start of the next run.
|
||||
hr = ht->get_attributes(offset, &start, &end, &attribs);
|
||||
// Bug 1421873: Gecko can return end <= offset in some rare cases, which
|
||||
// isn't valid. This is perhaps because the text mutated during the loop
|
||||
// for some reason, making this offset invalid.
|
||||
if (FAILED(hr) || end <= offset) {
|
||||
break;
|
||||
}
|
||||
attribRuns.AppendElement(IA2TextSegment({attribs, start, end}));
|
||||
}
|
||||
|
||||
// Put the attribute runs in a COM array.
|
||||
*aNAttribRuns = attribRuns.Length();
|
||||
*aAttribRuns = static_cast<IA2TextSegment*>(
|
||||
::CoTaskMemAlloc(sizeof(IA2TextSegment) * *aNAttribRuns));
|
||||
for (long index = 0; index < *aNAttribRuns; ++index) {
|
||||
(*aAttribRuns)[index] = attribRuns[index];
|
||||
}
|
||||
|
||||
*result = S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::get_AllTextInfo(BSTR* aText,
|
||||
IAccessibleHyperlink*** aHyperlinks,
|
||||
long* aNHyperlinks,
|
||||
IA2TextSegment** aAttribRuns,
|
||||
long* aNAttribRuns) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!mTargetUnk) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
if (!mscom::InvokeOnMainThread(
|
||||
"HandlerProvider::GetAllTextInfoMainThread", this,
|
||||
&HandlerProvider::GetAllTextInfoMainThread,
|
||||
std::forward<BSTR*>(aText),
|
||||
std::forward<IAccessibleHyperlink***>(aHyperlinks),
|
||||
std::forward<long*>(aNHyperlinks),
|
||||
std::forward<IA2TextSegment**>(aAttribRuns),
|
||||
std::forward<long*>(aNAttribRuns), std::forward<HRESULT*>(&hr))) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void HandlerProvider::GetRelationsInfoMainThread(IARelationData** aRelations,
|
||||
long* aNRelations,
|
||||
HRESULT* hr) {
|
||||
MOZ_ASSERT(aRelations);
|
||||
MOZ_ASSERT(aNRelations);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTargetUnk) {
|
||||
*hr = CO_E_OBJNOTCONNECTED;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<NEWEST_IA2_INTERFACE> acc;
|
||||
*hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID, getter_AddRefs(acc));
|
||||
if (FAILED(*hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
*hr = acc->get_nRelations(aNRelations);
|
||||
if (FAILED(*hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto rawRels = MakeUnique<IAccessibleRelation*[]>(*aNRelations);
|
||||
*hr = acc->get_relations(*aNRelations, rawRels.get(), aNRelations);
|
||||
if (FAILED(*hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
*aRelations = static_cast<IARelationData*>(
|
||||
::CoTaskMemAlloc(sizeof(IARelationData) * *aNRelations));
|
||||
for (long index = 0; index < *aNRelations; ++index) {
|
||||
IAccessibleRelation* rawRel = rawRels[index];
|
||||
IARelationData& relData = (*aRelations)[index];
|
||||
*hr = rawRel->get_relationType(&relData.mType);
|
||||
if (FAILED(*hr)) {
|
||||
relData.mType = nullptr;
|
||||
}
|
||||
*hr = rawRel->get_nTargets(&relData.mNTargets);
|
||||
if (FAILED(*hr)) {
|
||||
relData.mNTargets = -1;
|
||||
}
|
||||
rawRel->Release();
|
||||
}
|
||||
|
||||
*hr = S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::get_RelationsInfo(IARelationData** aRelations,
|
||||
long* aNRelations) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!mTargetUnk) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
if (!mscom::InvokeOnMainThread(
|
||||
"HandlerProvider::GetRelationsInfoMainThread", this,
|
||||
&HandlerProvider::GetRelationsInfoMainThread,
|
||||
std::forward<IARelationData**>(aRelations),
|
||||
std::forward<long*>(aNRelations), std::forward<HRESULT*>(&hr))) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Helper function for GetAllChildrenMainThread.
|
||||
static bool SetChildDataForTextLeaf(NEWEST_IA2_INTERFACE* acc,
|
||||
AccChildData& data) {
|
||||
const VARIANT kChildIdSelf = {VT_I4};
|
||||
VARIANT varVal;
|
||||
|
||||
// 1. Check whether this is a text leaf.
|
||||
|
||||
// 1.1. A text leaf always has ROLE_SYSTEM_TEXT or ROLE_SYSTEM_WHITESPACE.
|
||||
HRESULT hr = acc->get_accRole(kChildIdSelf, &varVal);
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
if (varVal.vt != VT_I4) {
|
||||
return false;
|
||||
}
|
||||
long role = varVal.lVal;
|
||||
if (role != ROLE_SYSTEM_TEXT && role != ROLE_SYSTEM_WHITESPACE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.2. A text leaf doesn't support IAccessibleText.
|
||||
RefPtr<IAccessibleText> iaText;
|
||||
hr = acc->QueryInterface(IID_IAccessibleText, getter_AddRefs(iaText));
|
||||
if (SUCCEEDED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.3. A text leaf doesn't have children.
|
||||
long count;
|
||||
hr = acc->get_accChildCount(&count);
|
||||
if (FAILED(hr) || count != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Update |data| with the data for this text leaf.
|
||||
// Because marshaling objects is more expensive than marshaling other data,
|
||||
// we just marshal the data we need for text leaf children, rather than
|
||||
// marshaling the full accessible object.
|
||||
|
||||
// |data| has already been zeroed, so we don't need to do anything if these
|
||||
// calls fail.
|
||||
acc->get_accName(kChildIdSelf, &data.mText);
|
||||
data.mTextRole = role;
|
||||
acc->get_uniqueID(&data.mTextId);
|
||||
acc->get_accState(kChildIdSelf, &varVal);
|
||||
data.mTextState = varVal.lVal;
|
||||
acc->accLocation(&data.mTextLeft, &data.mTextTop, &data.mTextWidth,
|
||||
&data.mTextHeight, kChildIdSelf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlerProvider::GetAllChildrenMainThread(AccChildData** aChildren,
|
||||
ULONG* aNChildren, HRESULT* hr) {
|
||||
MOZ_ASSERT(aChildren);
|
||||
MOZ_ASSERT(aNChildren);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mTargetUnk) {
|
||||
*hr = CO_E_OBJNOTCONNECTED;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<NEWEST_IA2_INTERFACE> acc;
|
||||
*hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID, getter_AddRefs(acc));
|
||||
if (FAILED(*hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
long count;
|
||||
*hr = acc->get_accChildCount(&count);
|
||||
if (FAILED(*hr)) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(count >= 0);
|
||||
|
||||
if (count == 0) {
|
||||
*aChildren = nullptr;
|
||||
*aNChildren = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<IEnumVARIANT> enumVar;
|
||||
*hr = mTargetUnk.get()->QueryInterface(IID_IEnumVARIANT,
|
||||
getter_AddRefs(enumVar));
|
||||
if (FAILED(*hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto rawChildren = MakeUnique<VARIANT[]>(count);
|
||||
*hr = enumVar->Next((ULONG)count, rawChildren.get(), aNChildren);
|
||||
if (FAILED(*hr)) {
|
||||
*aChildren = nullptr;
|
||||
*aNChildren = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*aChildren = static_cast<AccChildData*>(
|
||||
::CoTaskMemAlloc(sizeof(AccChildData) * *aNChildren));
|
||||
for (ULONG index = 0; index < *aNChildren; ++index) {
|
||||
(*aChildren)[index] = {};
|
||||
AccChildData& child = (*aChildren)[index];
|
||||
|
||||
MOZ_ASSERT(rawChildren[index].vt == VT_DISPATCH);
|
||||
MOZ_ASSERT(rawChildren[index].pdispVal);
|
||||
RefPtr<NEWEST_IA2_INTERFACE> childAcc;
|
||||
*hr = rawChildren[index].pdispVal->QueryInterface(NEWEST_IA2_IID,
|
||||
getter_AddRefs(childAcc));
|
||||
rawChildren[index].pdispVal->Release();
|
||||
MOZ_ASSERT(SUCCEEDED(*hr));
|
||||
if (FAILED(*hr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SetChildDataForTextLeaf(childAcc, child)) {
|
||||
// This isn't a text leaf. Marshal the accessible.
|
||||
childAcc.forget(&child.mAccessible);
|
||||
// We must wrap this accessible in an Interceptor.
|
||||
ToWrappedObject(&child.mAccessible);
|
||||
}
|
||||
}
|
||||
|
||||
*hr = S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::get_AllChildren(AccChildData** aChildren, ULONG* aNChildren) {
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
HRESULT hr;
|
||||
if (!mscom::InvokeOnMainThread(
|
||||
"HandlerProvider::GetAllChildrenMainThread", this,
|
||||
&HandlerProvider::GetAllChildrenMainThread,
|
||||
std::forward<AccChildData**>(aChildren),
|
||||
std::forward<ULONG*>(aNChildren), std::forward<HRESULT*>(&hr))) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,145 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_a11y_HandlerProvider_h
|
||||
#define mozilla_a11y_HandlerProvider_h
|
||||
|
||||
#include "mozilla/a11y/AccessibleHandler.h"
|
||||
#include "mozilla/a11y/HandlerDataCleanup.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/mscom/IHandlerProvider.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/StructStream.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "HandlerData.h"
|
||||
|
||||
struct NEWEST_IA2_INTERFACE;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace mscom {
|
||||
|
||||
class StructToStream;
|
||||
|
||||
} // namespace mscom
|
||||
|
||||
namespace a11y {
|
||||
|
||||
class HandlerProvider final : public IGeckoBackChannel,
|
||||
public mscom::IHandlerProvider {
|
||||
public:
|
||||
HandlerProvider(REFIID aIid, mscom::InterceptorTargetPtr<IUnknown> aTarget);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
// IHandlerProvider
|
||||
STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
|
||||
STDMETHODIMP GetHandlerPayloadSize(NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
NotNull<DWORD*> aOutPayloadSize) override;
|
||||
STDMETHODIMP WriteHandlerPayload(NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
NotNull<IStream*> aStream) override;
|
||||
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
|
||||
STDMETHODIMP DisconnectHandlerRemotes() override;
|
||||
STDMETHODIMP IsInterfaceMaybeSupported(REFIID aIid) override;
|
||||
STDMETHODIMP_(REFIID)
|
||||
GetEffectiveOutParamIid(REFIID aCallIid, ULONG aCallMethod) override;
|
||||
STDMETHODIMP NewInstance(
|
||||
REFIID aIid, mscom::InterceptorTargetPtr<IUnknown> aTarget,
|
||||
NotNull<mscom::IHandlerProvider**> aOutNewPayload) override;
|
||||
|
||||
// IGeckoBackChannel
|
||||
STDMETHODIMP put_HandlerControl(long aPid, IHandlerControl* aCtrl) override;
|
||||
STDMETHODIMP Refresh(DynamicIA2Data* aOutData) override;
|
||||
STDMETHODIMP get_AllTextInfo(BSTR* aText, IAccessibleHyperlink*** aHyperlinks,
|
||||
long* aNHyperlinks, IA2TextSegment** aAttribRuns,
|
||||
long* aNAttribRuns) override;
|
||||
STDMETHODIMP get_RelationsInfo(IARelationData** aRelations,
|
||||
long* aNRelations) override;
|
||||
STDMETHODIMP get_AllChildren(AccChildData** aChildren,
|
||||
ULONG* aNChildren) override;
|
||||
|
||||
private:
|
||||
~HandlerProvider() = default;
|
||||
|
||||
void SetHandlerControlOnMainThread(
|
||||
DWORD aPid, mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
|
||||
void GetAndSerializePayload(const MutexAutoLock&,
|
||||
NotNull<mscom::IInterceptor*> aInterceptor);
|
||||
void BuildStaticIA2Data(NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
StaticIA2Data* aOutData);
|
||||
/**
|
||||
* Pass true for aMarshaledByCom if this struct is being directly marshaled as
|
||||
* an out parameter of a COM method, currently only
|
||||
* IGeckoBackChannel::Refresh.
|
||||
* When aMarshaledByCom is false, this means the struct is being marshaled
|
||||
* by RPC encoding functions. This means we must allocate memory differently,
|
||||
* even though we're using this as part of a COM handler payload.
|
||||
*/
|
||||
void BuildDynamicIA2Data(DynamicIA2Data* aOutIA2Data,
|
||||
bool aMarshaledByCom = false);
|
||||
void BuildInitialIA2Data(NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
StaticIA2Data* aOutStaticData,
|
||||
DynamicIA2Data* aOutDynamicData);
|
||||
bool IsTargetInterfaceCacheable();
|
||||
|
||||
/**
|
||||
* Build the payload for later marshaling.
|
||||
* This is intended to be used during a bulk fetch operation and must only be
|
||||
* called from the main thread.
|
||||
*/
|
||||
void PrebuildPayload(NotNull<mscom::IInterceptor*> aInterceptor);
|
||||
|
||||
// Replace a raw object from the main thread with a wrapped, intercepted
|
||||
// object suitable for calling from the MTA.
|
||||
// The reference to the original object is adopted; i.e. you should not
|
||||
// separately release it.
|
||||
// This is intended for objects returned from method calls on the main thread.
|
||||
template <typename Interface>
|
||||
HRESULT ToWrappedObject(Interface** aObj);
|
||||
void GetAllTextInfoMainThread(BSTR* aText,
|
||||
IAccessibleHyperlink*** aHyperlinks,
|
||||
long* aNHyperlinks,
|
||||
IA2TextSegment** aAttribRuns,
|
||||
long* aNAttribRuns, HRESULT* result);
|
||||
void GetRelationsInfoMainThread(IARelationData** aRelations,
|
||||
long* aNRelations, HRESULT* result);
|
||||
void GetAllChildrenMainThread(AccChildData** aChildren, ULONG* aNChildren,
|
||||
HRESULT* result);
|
||||
|
||||
Atomic<uint32_t> mRefCnt;
|
||||
Mutex mMutex MOZ_UNANNOTATED; // Protects mSerializer
|
||||
const IID mTargetUnkIid;
|
||||
mscom::InterceptorTargetPtr<IUnknown>
|
||||
mTargetUnk; // Constant, main thread only
|
||||
UniquePtr<mscom::StructToStream> mSerializer;
|
||||
RefPtr<IUnknown> mFastMarshalUnk;
|
||||
|
||||
struct IA2PayloadDeleter {
|
||||
void operator()(IA2Payload* aPayload) {
|
||||
// When CoMarshalInterface writes interfaces out to a stream, it AddRefs.
|
||||
// Therefore, we must release our references after this.
|
||||
ReleaseStaticIA2DataInterfaces(aPayload->mStaticData);
|
||||
CleanupDynamicIA2Data(aPayload->mDynamicData);
|
||||
delete aPayload;
|
||||
}
|
||||
};
|
||||
using IA2PayloadPtr = UniquePtr<IA2Payload, IA2PayloadDeleter>;
|
||||
|
||||
// Used when the payload is built prior to marshaling the object by a bulk
|
||||
// fetch operation. See prebuildPayload().
|
||||
IA2PayloadPtr mPayload;
|
||||
Mutex mPayloadMutex MOZ_UNANNOTATED; // Protects mPayload
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_HandlerProvider_h
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- 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 "mozilla/a11y/AccessibleHandler.h"
|
||||
#include "mozilla/a11y/PlatformChild.h"
|
||||
#include "mozilla/mscom/ActCtxResource.h"
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
#include "mozilla/mscom/InterceptorLog.h"
|
||||
|
||||
#include "Accessible2.h"
|
||||
#include "Accessible2_2.h"
|
||||
#include "AccessibleHypertext2.h"
|
||||
#include "AccessibleTable2.h"
|
||||
#include "AccessibleTableCell.h"
|
||||
|
||||
#include "AccessibleDocument_i.c"
|
||||
#include "AccessibleHypertext2_i.c"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
/**
|
||||
* Unfortunately the COM interceptor does not intrinsically handle array
|
||||
* outparams. Instead we manually define the relevant metadata here, and
|
||||
* register it in a call to mozilla::mscom::RegisterArrayData.
|
||||
* @see mozilla::mscom::ArrayData
|
||||
*/
|
||||
static const mozilla::mscom::ArrayData sPlatformChildArrayData[] = {
|
||||
{IID_IEnumVARIANT, 3, 1, VT_DISPATCH, IID_IDispatch, 2},
|
||||
{IID_IAccessible2, 30, 1, VT_UNKNOWN | VT_BYREF, IID_IAccessibleRelation,
|
||||
2},
|
||||
{IID_IAccessibleRelation, 7, 1, VT_UNKNOWN | VT_BYREF, NEWEST_IA2_IID, 2},
|
||||
{IID_IAccessible2_2, 48, 2, VT_UNKNOWN | VT_BYREF, NEWEST_IA2_IID, 3,
|
||||
mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
|
||||
{IID_IAccessibleTableCell, 4, 0, VT_UNKNOWN | VT_BYREF, NEWEST_IA2_IID, 1,
|
||||
mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
|
||||
{IID_IAccessibleTableCell, 7, 0, VT_UNKNOWN | VT_BYREF, NEWEST_IA2_IID, 1,
|
||||
mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
|
||||
{IID_IAccessibleHypertext2, 25, 0, VT_UNKNOWN | VT_BYREF,
|
||||
IID_IAccessibleHyperlink, 1,
|
||||
mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
|
||||
{IID_IAccessibleTable2, 12, 0, VT_UNKNOWN | VT_BYREF, NEWEST_IA2_IID, 1,
|
||||
mozilla::mscom::ArrayData::Flag::eAllocatedByServer}};
|
||||
|
||||
// Type libraries are thread-neutral, so we can register those from any
|
||||
// apartment. OTOH, proxies must be registered from within the apartment where
|
||||
// we intend to instantiate them. Therefore RegisterProxy() must be called
|
||||
// via EnsureMTA.
|
||||
PlatformChild::PlatformChild()
|
||||
: mIA2Proxy(mozilla::mscom::RegisterProxy(L"ia2marshal.dll")),
|
||||
mAccTypelib(mozilla::mscom::RegisterTypelib(
|
||||
L"oleacc.dll",
|
||||
mozilla::mscom::RegistrationFlags::eUseSystemDirectory)),
|
||||
mMiscTypelib(mozilla::mscom::RegisterTypelib(L"Accessible.tlb")),
|
||||
mSdnTypelib(mozilla::mscom::RegisterTypelib(L"AccessibleMarshal.dll")) {
|
||||
auto actCtxResource = mscom::ActCtxResource::GetAccessibilityResource();
|
||||
|
||||
mozilla::mscom::MTADeletePtr<mozilla::mscom::ActivationContextRegion>
|
||||
tmpActCtxMTA;
|
||||
mozilla::mscom::EnsureMTA([actCtxResource, &tmpActCtxMTA]() -> void {
|
||||
tmpActCtxMTA.reset(
|
||||
new mozilla::mscom::ActivationContextRegion(actCtxResource));
|
||||
});
|
||||
mActCtxMTA = std::move(tmpActCtxMTA);
|
||||
|
||||
mozilla::mscom::InterceptorLog::Init();
|
||||
mozilla::mscom::RegisterArrayData(sPlatformChildArrayData);
|
||||
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> customProxy;
|
||||
mozilla::mscom::EnsureMTA([&customProxy]() -> void {
|
||||
customProxy = mozilla::mscom::RegisterProxy();
|
||||
});
|
||||
mCustomProxy = std::move(customProxy);
|
||||
|
||||
// IA2 needs to be registered in both the main thread's STA as well as the MTA
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> ia2ProxyMTA;
|
||||
mozilla::mscom::EnsureMTA([&ia2ProxyMTA]() -> void {
|
||||
ia2ProxyMTA = mozilla::mscom::RegisterProxy(L"ia2marshal.dll");
|
||||
});
|
||||
mIA2ProxyMTA = std::move(ia2ProxyMTA);
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_a11y_PlatformChild_h
|
||||
#define mozilla_a11y_PlatformChild_h
|
||||
|
||||
#include "mozilla/mscom/ActivationContext.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/Registration.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class PlatformChild {
|
||||
public:
|
||||
PlatformChild();
|
||||
|
||||
PlatformChild(PlatformChild&) = delete;
|
||||
PlatformChild(PlatformChild&&) = delete;
|
||||
PlatformChild& operator=(PlatformChild&) = delete;
|
||||
PlatformChild& operator=(PlatformChild&&) = delete;
|
||||
|
||||
private:
|
||||
mscom::MTADeletePtr<mozilla::mscom::ActivationContextRegion> mActCtxMTA;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mCustomProxy;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mIA2Proxy;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mIA2ProxyMTA;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mAccTypelib;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mMiscTypelib;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mSdnTypelib;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_PlatformChild_h
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,12 @@
|
|||
;+# 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/.
|
||||
|
||||
LIBRARY AccessibleHandler.dll
|
||||
|
||||
EXPORTS DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
||||
GetProxyDllInfo PRIVATE
|
||||
RegisterMsix PRIVATE
|
|
@ -0,0 +1,336 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_a11y_AccessibleHandler_h
|
||||
#define mozilla_a11y_AccessibleHandler_h
|
||||
|
||||
#define NEWEST_IA2_BASENAME Accessible2_3
|
||||
|
||||
#define __GENIFACE(base) I##base
|
||||
#define INTERFACEFOR(base) __GENIFACE(base)
|
||||
#define NEWEST_IA2_INTERFACE INTERFACEFOR(NEWEST_IA2_BASENAME)
|
||||
|
||||
#define __GENIID(iface) IID_##iface
|
||||
#define IIDFOR(iface) __GENIID(iface)
|
||||
#define NEWEST_IA2_IID IIDFOR(NEWEST_IA2_INTERFACE)
|
||||
|
||||
#if defined(__midl) || defined(__WIDL__)
|
||||
|
||||
import "Accessible2_3.idl";
|
||||
|
||||
#else
|
||||
|
||||
# include "HandlerData.h"
|
||||
|
||||
# include <windows.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
static const GUID kUnsupportedServices[] = {
|
||||
// clang-format off
|
||||
// Unknown, queried by Windows on devices with touch screens or similar devices
|
||||
// connected.
|
||||
{0x33f139ee, 0xe509, 0x47f7, {0xbf, 0x39, 0x83, 0x76, 0x44, 0xf7, 0x45, 0x76}},
|
||||
// Unknown, queried by Windows
|
||||
{0xFDA075CF, 0x7C8B, 0x498C, { 0xB5, 0x14, 0xA9, 0xCB, 0x52, 0x1B, 0xBF, 0xB4 }},
|
||||
// Unknown, queried by Windows
|
||||
{0x8EDAA462, 0x21F4, 0x4C87, { 0xA0, 0x12, 0xB3, 0xCD, 0xA3, 0xAB, 0x01, 0xFC }},
|
||||
// Unknown, queried by Windows
|
||||
{0xacd46652, 0x829d, 0x41cb, { 0xa5, 0xfc, 0x17, 0xac, 0xf4, 0x36, 0x61, 0xac }},
|
||||
// SID_IsUIAutomationObject (undocumented), queried by Windows
|
||||
{0xb96fdb85, 0x7204, 0x4724, { 0x84, 0x2b, 0xc7, 0x05, 0x9d, 0xed, 0xb9, 0xd0 }},
|
||||
// IIS_IsOleaccProxy (undocumented), queried by Windows
|
||||
{0x902697FA, 0x80E4, 0x4560, {0x80, 0x2A, 0xA1, 0x3F, 0x22, 0xA6, 0x47, 0x09}},
|
||||
// IID_IHTMLElement, queried by JAWS
|
||||
{0x3050F1FF, 0x98B5, 0x11CF, {0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B}}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
# if !defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
# include "Accessible2_3.h"
|
||||
# include "AccessibleHyperlink.h"
|
||||
# include "AccessibleHypertext2.h"
|
||||
# include "AccessibleTableCell.h"
|
||||
# include "Handler.h"
|
||||
# include "mozilla/mscom/StructStream.h"
|
||||
# include "mozilla/UniquePtr.h"
|
||||
|
||||
# include <ocidl.h>
|
||||
# include <servprov.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class AccessibleHandler final : public mscom::Handler,
|
||||
public NEWEST_IA2_INTERFACE,
|
||||
public IServiceProvider,
|
||||
public IProvideClassInfo,
|
||||
public IAccessibleHyperlink,
|
||||
public IAccessibleTableCell,
|
||||
public IAccessibleHypertext2 {
|
||||
public:
|
||||
static HRESULT Create(IUnknown* aOuter, REFIID aIid, void** aOutInterface);
|
||||
|
||||
// mscom::Handler
|
||||
HRESULT QueryHandlerInterface(IUnknown* aProxyUnknown, REFIID aIid,
|
||||
void** aOutInterface) override;
|
||||
HRESULT ReadHandlerPayload(IStream* aStream, REFIID aIid) override;
|
||||
|
||||
REFIID MarshalAs(REFIID aRequestedIid) override;
|
||||
HRESULT GetMarshalInterface(REFIID aMarshalAsIid, NotNull<IUnknown*> aProxy,
|
||||
NotNull<IID*> aOutIid,
|
||||
NotNull<IUnknown**> aOutUnk) override;
|
||||
HRESULT GetHandlerPayloadSize(REFIID aIid, DWORD* aOutPayloadSize) override;
|
||||
HRESULT WriteHandlerPayload(IStream* aStream, REFIID aIId) override;
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
// IDispatch
|
||||
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) override;
|
||||
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid,
|
||||
ITypeInfo** ppTInfo) override;
|
||||
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
|
||||
LCID lcid, DISPID* rgDispId) override;
|
||||
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
|
||||
DISPPARAMS* pDispParams, VARIANT* pVarResult,
|
||||
EXCEPINFO* pExcepInfo, UINT* puArgErr) override;
|
||||
|
||||
// IAccessible
|
||||
STDMETHODIMP get_accParent(IDispatch** ppdispParent) override;
|
||||
STDMETHODIMP get_accChildCount(long* pcountChildren) override;
|
||||
STDMETHODIMP get_accChild(VARIANT varChild, IDispatch** ppdispChild) override;
|
||||
STDMETHODIMP get_accName(VARIANT varChild, BSTR* pszName) override;
|
||||
STDMETHODIMP get_accValue(VARIANT varChild, BSTR* pszValue) override;
|
||||
STDMETHODIMP get_accDescription(VARIANT varChild,
|
||||
BSTR* pszDescription) override;
|
||||
STDMETHODIMP get_accRole(VARIANT varChild, VARIANT* pvarRole) override;
|
||||
STDMETHODIMP get_accState(VARIANT varChild, VARIANT* pvarState) override;
|
||||
STDMETHODIMP get_accHelp(VARIANT varChild, BSTR* pszHelp) override;
|
||||
STDMETHODIMP get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild,
|
||||
long* pidTopic) override;
|
||||
STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild,
|
||||
BSTR* pszKeyboardShortcut) override;
|
||||
STDMETHODIMP get_accFocus(VARIANT* pvarChild) override;
|
||||
STDMETHODIMP get_accSelection(VARIANT* pvarChildren) override;
|
||||
STDMETHODIMP get_accDefaultAction(VARIANT varChild,
|
||||
BSTR* pszDefaultAction) override;
|
||||
STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild) override;
|
||||
STDMETHODIMP accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
|
||||
long* pcyHeight, VARIANT varChild) override;
|
||||
STDMETHODIMP accNavigate(long navDir, VARIANT varStart,
|
||||
VARIANT* pvarEndUpAt) override;
|
||||
STDMETHODIMP accHitTest(long xLeft, long yTop, VARIANT* pvarChild) override;
|
||||
STDMETHODIMP accDoDefaultAction(VARIANT varChild) override;
|
||||
STDMETHODIMP put_accName(VARIANT varChild, BSTR szName) override;
|
||||
STDMETHODIMP put_accValue(VARIANT varChild, BSTR szValue) override;
|
||||
|
||||
// IAccessible2
|
||||
STDMETHODIMP get_nRelations(long* nRelations) override;
|
||||
STDMETHODIMP get_relation(long relationIndex,
|
||||
IAccessibleRelation** relation) override;
|
||||
STDMETHODIMP get_relations(long maxRelations, IAccessibleRelation** relations,
|
||||
long* nRelations) override;
|
||||
STDMETHODIMP role(long* role) override;
|
||||
STDMETHODIMP scrollTo(IA2ScrollType scrollType) override;
|
||||
STDMETHODIMP scrollToPoint(IA2CoordinateType coordinateType, long x,
|
||||
long y) override;
|
||||
STDMETHODIMP get_groupPosition(long* groupLevel, long* similarItemsInGroup,
|
||||
long* positionInGroup) override;
|
||||
STDMETHODIMP get_states(AccessibleStates* states) override;
|
||||
STDMETHODIMP get_extendedRole(BSTR* extendedRole) override;
|
||||
STDMETHODIMP get_localizedExtendedRole(BSTR* localizedExtendedRole) override;
|
||||
STDMETHODIMP get_nExtendedStates(long* nExtendedStates) override;
|
||||
STDMETHODIMP get_extendedStates(long maxExtendedStates, BSTR** extendedStates,
|
||||
long* nExtendedStates) override;
|
||||
STDMETHODIMP get_localizedExtendedStates(
|
||||
long maxLocalizedExtendedStates, BSTR** localizedExtendedStates,
|
||||
long* nLocalizedExtendedStates) override;
|
||||
STDMETHODIMP get_uniqueID(long* uniqueID) override;
|
||||
STDMETHODIMP get_windowHandle(HWND* windowHandle) override;
|
||||
STDMETHODIMP get_indexInParent(long* indexInParent) override;
|
||||
STDMETHODIMP get_locale(IA2Locale* locale) override;
|
||||
STDMETHODIMP get_attributes(BSTR* attributes) override;
|
||||
|
||||
// IAccessible2_2
|
||||
STDMETHODIMP get_attribute(BSTR name, VARIANT* attribute) override;
|
||||
STDMETHODIMP get_accessibleWithCaret(IUnknown** accessible,
|
||||
long* caretOffset) override;
|
||||
STDMETHODIMP get_relationTargetsOfType(BSTR type, long maxTargets,
|
||||
IUnknown*** targets,
|
||||
long* nTargets) override;
|
||||
|
||||
// IAccessible2_3
|
||||
STDMETHODIMP get_selectionRanges(IA2Range** ranges, long* nRanges) override;
|
||||
|
||||
// IServiceProvider
|
||||
STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aIid,
|
||||
void** aOutInterface) override;
|
||||
|
||||
// IProvideClassInfo
|
||||
STDMETHODIMP GetClassInfo(ITypeInfo** aOutTypeInfo) override;
|
||||
|
||||
// IAccessibleAction
|
||||
STDMETHODIMP nActions(long* nActions) override;
|
||||
STDMETHODIMP doAction(long actionIndex) override;
|
||||
STDMETHODIMP get_description(long actionIndex, BSTR* description) override;
|
||||
STDMETHODIMP get_keyBinding(long actionIndex, long nMaxBindings,
|
||||
BSTR** keyBindings, long* nBindings) override;
|
||||
STDMETHODIMP get_name(long actionIndex, BSTR* name) override;
|
||||
STDMETHODIMP get_localizedName(long actionIndex,
|
||||
BSTR* localizedName) override;
|
||||
|
||||
// IAccessibleHyperlink
|
||||
STDMETHODIMP get_anchor(long index, VARIANT* anchor) override;
|
||||
STDMETHODIMP get_anchorTarget(long index, VARIANT* anchorTarget) override;
|
||||
STDMETHODIMP get_startIndex(long* index) override;
|
||||
STDMETHODIMP get_endIndex(long* index) override;
|
||||
STDMETHODIMP get_valid(boolean* valid) override;
|
||||
|
||||
// IAccessibleTableCell
|
||||
STDMETHODIMP get_columnExtent(long* nColumnsSpanned) override;
|
||||
STDMETHODIMP get_columnHeaderCells(IUnknown*** cellAccessibles,
|
||||
long* nColumnHeaderCells) override;
|
||||
STDMETHODIMP get_columnIndex(long* columnIndex) override;
|
||||
STDMETHODIMP get_rowExtent(long* nRowsSpanned) override;
|
||||
STDMETHODIMP get_rowHeaderCells(IUnknown*** cellAccessibles,
|
||||
long* nRowHeaderCells) override;
|
||||
STDMETHODIMP get_rowIndex(long* rowIndex) override;
|
||||
STDMETHODIMP get_isSelected(boolean* isSelected) override;
|
||||
STDMETHODIMP get_rowColumnExtents(long* row, long* column, long* rowExtents,
|
||||
long* columnExtents,
|
||||
boolean* isSelected) override;
|
||||
STDMETHODIMP get_table(IUnknown** table) override;
|
||||
|
||||
// IAccessibleText
|
||||
STDMETHODIMP addSelection(long startOffset, long endOffset) override;
|
||||
STDMETHODIMP get_attributes(long offset, long* startOffset, long* endOffset,
|
||||
BSTR* textAttributes) override;
|
||||
STDMETHODIMP get_caretOffset(long* offset) override;
|
||||
STDMETHODIMP get_characterExtents(long offset,
|
||||
enum IA2CoordinateType coordType, long* x,
|
||||
long* y, long* width,
|
||||
long* height) override;
|
||||
STDMETHODIMP get_nSelections(long* nSelections) override;
|
||||
STDMETHODIMP get_offsetAtPoint(long x, long y,
|
||||
enum IA2CoordinateType coordType,
|
||||
long* offset) override;
|
||||
STDMETHODIMP get_selection(long selectionIndex, long* startOffset,
|
||||
long* endOffset) override;
|
||||
STDMETHODIMP get_text(long startOffset, long endOffset, BSTR* text) override;
|
||||
STDMETHODIMP get_textBeforeOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long* startOffset, long* endOffset,
|
||||
BSTR* text) override;
|
||||
STDMETHODIMP get_textAfterOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long* startOffset, long* endOffset,
|
||||
BSTR* text) override;
|
||||
STDMETHODIMP get_textAtOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long* startOffset, long* endOffset,
|
||||
BSTR* text) override;
|
||||
STDMETHODIMP removeSelection(long selectionIndex) override;
|
||||
STDMETHODIMP setCaretOffset(long offset) override;
|
||||
STDMETHODIMP setSelection(long selectionIndex, long startOffset,
|
||||
long endOffset) override;
|
||||
STDMETHODIMP get_nCharacters(long* nCharacters) override;
|
||||
STDMETHODIMP scrollSubstringTo(long startIndex, long endIndex,
|
||||
enum IA2ScrollType scrollType) override;
|
||||
STDMETHODIMP scrollSubstringToPoint(long startIndex, long endIndex,
|
||||
enum IA2CoordinateType coordinateType,
|
||||
long x, long y) override;
|
||||
STDMETHODIMP get_newText(IA2TextSegment* newText) override;
|
||||
STDMETHODIMP get_oldText(IA2TextSegment* oldText) override;
|
||||
|
||||
// IAccessibleHypertext
|
||||
STDMETHODIMP get_nHyperlinks(long* hyperlinkCount) override;
|
||||
STDMETHODIMP get_hyperlink(long index,
|
||||
IAccessibleHyperlink** hyperlink) override;
|
||||
STDMETHODIMP get_hyperlinkIndex(long charIndex,
|
||||
long* hyperlinkIndex) override;
|
||||
|
||||
// IAccessibleHypertext2
|
||||
STDMETHODIMP get_hyperlinks(IAccessibleHyperlink*** hyperlinks,
|
||||
long* nHyperlinks) override;
|
||||
|
||||
private:
|
||||
AccessibleHandler(IUnknown* aOuter, HRESULT* aResult);
|
||||
virtual ~AccessibleHandler();
|
||||
|
||||
HRESULT ResolveIA2();
|
||||
HRESULT ResolveIDispatch();
|
||||
HRESULT ResolveIAHyperlink();
|
||||
HRESULT ResolveIAHypertext();
|
||||
HRESULT ResolveIATableCell();
|
||||
HRESULT MaybeUpdateCachedData();
|
||||
HRESULT GetAllTextInfo(BSTR* aText);
|
||||
void ClearTextCache();
|
||||
HRESULT GetRelationsInfo();
|
||||
void ClearRelationCache();
|
||||
|
||||
RefPtr<IUnknown> mDispatchUnk;
|
||||
/**
|
||||
* Handlers aggregate their proxies. This means that their proxies delegate
|
||||
* their IUnknown implementation to us.
|
||||
*
|
||||
* mDispatchUnk and the result of Handler::GetProxy() are both strong
|
||||
* references to the aggregated objects. OTOH, any interfaces that are QI'd
|
||||
* from those aggregated objects have delegated unknowns.
|
||||
*
|
||||
* AddRef'ing an interface with a delegated unknown ends up incrementing the
|
||||
* refcount of the *aggregator*. Since we are the aggregator of mDispatchUnk
|
||||
* and of the wrapped proxy, holding a strong reference to any interfaces
|
||||
* QI'd off of those objects would create a reference cycle.
|
||||
*
|
||||
* We may hold onto pointers to those references, but when we query them we
|
||||
* must immediately Release() them to prevent these cycles.
|
||||
*
|
||||
* It is safe for us to use these raw pointers because the aggregated
|
||||
* objects's lifetimes are proper subsets of our own lifetime.
|
||||
*/
|
||||
IDispatch* mDispatch; // weak
|
||||
NEWEST_IA2_INTERFACE* mIA2PassThru; // weak
|
||||
IServiceProvider* mServProvPassThru; // weak
|
||||
IAccessibleHyperlink* mIAHyperlinkPassThru; // weak
|
||||
IAccessibleTableCell* mIATableCellPassThru; // weak
|
||||
IAccessibleHypertext2* mIAHypertextPassThru; // weak
|
||||
IA2Payload mCachedData;
|
||||
bool mCachedDynamicDataMarshaledByCom;
|
||||
UniquePtr<mscom::StructToStream> mSerializer;
|
||||
uint32_t mCacheGen;
|
||||
IAccessibleHyperlink** mCachedHyperlinks;
|
||||
long mCachedNHyperlinks;
|
||||
IA2TextSegment* mCachedTextAttribRuns;
|
||||
long mCachedNTextAttribRuns;
|
||||
IARelationData* mCachedRelations;
|
||||
long mCachedNRelations;
|
||||
bool mIsEmulatedWindow;
|
||||
};
|
||||
|
||||
inline static BSTR CopyBSTR(BSTR aSrc) {
|
||||
if (!aSrc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ::SysAllocStringLen(aSrc, ::SysStringLen(aSrc));
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
# endif // !defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#endif // defined(__midl)
|
||||
|
||||
#endif // mozilla_a11y_AccessibleHandler_h
|
|
@ -0,0 +1,5 @@
|
|||
/* 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/. */
|
||||
|
||||
1 typelib HandlerData.tlb
|
|
@ -0,0 +1,221 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include "AccessibleHandlerControl.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "AccessibleEventId.h"
|
||||
#include "AccessibleHandler.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
mscom::SingletonFactory<AccessibleHandlerControl> gControlFactory;
|
||||
|
||||
namespace detail {
|
||||
|
||||
TextChange::TextChange() : mIA2UniqueId(0), mIsInsert(false), mText() {}
|
||||
|
||||
TextChange::TextChange(long aIA2UniqueId, bool aIsInsert,
|
||||
NotNull<IA2TextSegment*> aText)
|
||||
: mIA2UniqueId(aIA2UniqueId),
|
||||
mIsInsert(aIsInsert),
|
||||
mText{BSTRCopy(aText->text), aText->start, aText->end} {}
|
||||
|
||||
TextChange::TextChange(TextChange&& aOther) : mText() {
|
||||
*this = std::move(aOther);
|
||||
}
|
||||
|
||||
TextChange::TextChange(const TextChange& aOther) : mText() { *this = aOther; }
|
||||
|
||||
TextChange& TextChange::operator=(TextChange&& aOther) {
|
||||
mIA2UniqueId = aOther.mIA2UniqueId;
|
||||
mIsInsert = aOther.mIsInsert;
|
||||
aOther.mIA2UniqueId = 0;
|
||||
::SysFreeString(mText.text);
|
||||
mText = aOther.mText;
|
||||
aOther.mText.text = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextChange& TextChange::operator=(const TextChange& aOther) {
|
||||
mIA2UniqueId = aOther.mIA2UniqueId;
|
||||
mIsInsert = aOther.mIsInsert;
|
||||
::SysFreeString(mText.text);
|
||||
mText = {BSTRCopy(aOther.mText.text), aOther.mText.start, aOther.mText.end};
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextChange::~TextChange() { ::SysFreeString(mText.text); }
|
||||
|
||||
HRESULT
|
||||
TextChange::GetOld(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutOldSegment) {
|
||||
if (mIsInsert || aIA2UniqueId != mIA2UniqueId) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return SegCopy(*aOutOldSegment, mText);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
TextChange::GetNew(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutNewSegment) {
|
||||
if (!mIsInsert || aIA2UniqueId != mIA2UniqueId) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return SegCopy(*aOutNewSegment, mText);
|
||||
}
|
||||
|
||||
/* static */
|
||||
BSTR TextChange::BSTRCopy(const BSTR& aIn) {
|
||||
return ::SysAllocStringLen(aIn, ::SysStringLen(aIn));
|
||||
}
|
||||
|
||||
/* static */
|
||||
HRESULT TextChange::SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc) {
|
||||
aDest = {BSTRCopy(aSrc.text), aSrc.start, aSrc.end};
|
||||
if (aSrc.text && !aDest.text) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (!::SysStringLen(aDest.text)) {
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject) {
|
||||
if (!aOutObject) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<AccessibleHandlerControl> ctl(new AccessibleHandlerControl());
|
||||
ctl.forget(aOutObject);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
AccessibleHandlerControl::AccessibleHandlerControl()
|
||||
: mIsRegistered(false),
|
||||
mCacheGen(0),
|
||||
mIA2Proxy(mscom::RegisterProxy(L"ia2marshal.dll")),
|
||||
mHandlerProxy(mscom::RegisterProxy()) {
|
||||
MOZ_ASSERT(mIA2Proxy);
|
||||
}
|
||||
|
||||
IMPL_IUNKNOWN1(AccessibleHandlerControl, IHandlerControl)
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Invalidate() {
|
||||
++mCacheGen;
|
||||
// We can't just call mAccessibleCache.clear() because doing so would release
|
||||
// remote objects, making remote COM calls. Since this is an STA, an incoming
|
||||
// COM call might be handled which might marshal an AccessibleHandler,
|
||||
// which in turn might add itself to mAccessibleCache. Since we'd be in the
|
||||
// middle of mutating mAccessibleCache, that might cause a crash. Instead,
|
||||
// swap mAccessibleCache into a temporary map first, which will empty
|
||||
// mAccessibleCache without releasing remote objects. Once mAccessibleCache
|
||||
// is empty, it's safe to let the temporary map be destroyed when it goes
|
||||
// out of scope. Remote calls will be made, but nothing will re-enter
|
||||
// the temporary map while it's being destroyed.
|
||||
AccessibleCache oldCache;
|
||||
mAccessibleCache.swap(oldCache);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::OnTextChange(long aHwnd, long aIA2UniqueId,
|
||||
VARIANT_BOOL aIsInsert,
|
||||
IA2TextSegment* aText) {
|
||||
if (!aText) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
mTextChange = detail::TextChange(aIA2UniqueId, aIsInsert, WrapNotNull(aText));
|
||||
NotifyWinEvent(aIsInsert ? IA2_EVENT_TEXT_INSERTED : IA2_EVENT_TEXT_REMOVED,
|
||||
reinterpret_cast<HWND>(static_cast<uintptr_t>(aHwnd)),
|
||||
OBJID_CLIENT, aIA2UniqueId);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::GetNewText(long aIA2UniqueId,
|
||||
NotNull<IA2TextSegment*> aOutNewText) {
|
||||
return mTextChange.GetNew(aIA2UniqueId, aOutNewText);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::GetOldText(long aIA2UniqueId,
|
||||
NotNull<IA2TextSegment*> aOutOldText) {
|
||||
return mTextChange.GetOld(aIA2UniqueId, aOutOldText);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo) {
|
||||
if (!mHandlerProxy) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
return mHandlerProxy->GetTypeInfoForGuid(CLSID_AccessibleHandler,
|
||||
aOutTypeInfo);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Register(NotNull<IGeckoBackChannel*> aGecko) {
|
||||
if (mIsRegistered) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
long pid = static_cast<long>(::GetCurrentProcessId());
|
||||
HRESULT hr = aGecko->put_HandlerControl(pid, this);
|
||||
mIsRegistered = SUCCEEDED(hr);
|
||||
MOZ_ASSERT(mIsRegistered);
|
||||
return hr;
|
||||
}
|
||||
|
||||
void AccessibleHandlerControl::CacheAccessible(long aUniqueId,
|
||||
AccessibleHandler* aAccessible) {
|
||||
MOZ_ASSERT(aUniqueId && aAccessible);
|
||||
mAccessibleCache[aUniqueId] = aAccessible;
|
||||
}
|
||||
|
||||
HRESULT AccessibleHandlerControl::GetCachedAccessible(
|
||||
long aUniqueId, AccessibleHandler** aAccessible) {
|
||||
MOZ_ASSERT(aUniqueId && aAccessible);
|
||||
auto it = mAccessibleCache.find(aUniqueId);
|
||||
if (it == mAccessibleCache.end()) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
RefPtr<AccessibleHandler> ref = it->second;
|
||||
ref.forget(aAccessible);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AccessibleHandlerControl::SuppressA11yForClipboardCopy() {
|
||||
mA11yClipboardCopySuppressionStartTime = ::GetTickCount();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool AccessibleHandlerControl::IsA11ySuppressedForClipboardCopy() {
|
||||
// Must be kept in sync with kSuppressTimeout in
|
||||
// accessible/windows/msaa/Compatibility.cpp.
|
||||
constexpr DWORD kSuppressTimeout = 1500; // ms
|
||||
if (!mA11yClipboardCopySuppressionStartTime) {
|
||||
return false;
|
||||
}
|
||||
return ::GetTickCount() - mA11yClipboardCopySuppressionStartTime <
|
||||
kSuppressTimeout;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,103 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#ifndef mozilla_a11y_AccessibleHandlerControl_h
|
||||
# define mozilla_a11y_AccessibleHandlerControl_h
|
||||
|
||||
# include <unordered_map>
|
||||
# include "Factory.h"
|
||||
# include "HandlerData.h"
|
||||
# include "IUnknownImpl.h"
|
||||
# include "mozilla/mscom/Registration.h"
|
||||
# include "mozilla/NotNull.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class TextChange final {
|
||||
public:
|
||||
TextChange();
|
||||
TextChange(long aIA2UniqueId, bool aIsInsert, NotNull<IA2TextSegment*> aText);
|
||||
TextChange(TextChange&& aOther);
|
||||
TextChange(const TextChange& aOther);
|
||||
|
||||
TextChange& operator=(TextChange&& aOther);
|
||||
TextChange& operator=(const TextChange& aOther);
|
||||
|
||||
~TextChange();
|
||||
|
||||
HRESULT GetOld(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutOldSegment);
|
||||
HRESULT GetNew(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutNewSegment);
|
||||
|
||||
private:
|
||||
static BSTR BSTRCopy(const BSTR& aIn);
|
||||
static HRESULT SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc);
|
||||
|
||||
long mIA2UniqueId;
|
||||
bool mIsInsert;
|
||||
IA2TextSegment mText;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class AccessibleHandler;
|
||||
|
||||
class AccessibleHandlerControl final : public IHandlerControl {
|
||||
public:
|
||||
static HRESULT Create(AccessibleHandlerControl** aOutObject);
|
||||
|
||||
DECL_IUNKNOWN
|
||||
|
||||
// IHandlerControl
|
||||
STDMETHODIMP Invalidate() override;
|
||||
STDMETHODIMP OnTextChange(long aHwnd, long aIA2UniqueId,
|
||||
VARIANT_BOOL aIsInsert,
|
||||
IA2TextSegment* aText) override;
|
||||
STDMETHODIMP SuppressA11yForClipboardCopy() override;
|
||||
|
||||
uint32_t GetCacheGen() const { return mCacheGen; }
|
||||
|
||||
HRESULT GetNewText(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutNewText);
|
||||
HRESULT GetOldText(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutOldText);
|
||||
|
||||
HRESULT GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo);
|
||||
|
||||
HRESULT Register(NotNull<IGeckoBackChannel*> aGecko);
|
||||
|
||||
void CacheAccessible(long aUniqueId, AccessibleHandler* aAccessible);
|
||||
HRESULT GetCachedAccessible(long aUniqueId, AccessibleHandler** aAccessible);
|
||||
|
||||
bool IsA11ySuppressedForClipboardCopy();
|
||||
|
||||
private:
|
||||
AccessibleHandlerControl();
|
||||
~AccessibleHandlerControl() = default;
|
||||
|
||||
bool mIsRegistered;
|
||||
uint32_t mCacheGen;
|
||||
detail::TextChange mTextChange;
|
||||
UniquePtr<mscom::RegisteredProxy> mIA2Proxy;
|
||||
UniquePtr<mscom::RegisteredProxy> mHandlerProxy;
|
||||
// We can't use Gecko APIs in this dll, hence the use of std::unordered_map.
|
||||
typedef std::unordered_map<long, RefPtr<AccessibleHandler>> AccessibleCache;
|
||||
AccessibleCache mAccessibleCache;
|
||||
// Time when SuppressA11yForClipboardCopy() was called, as returned by
|
||||
// ::GetTickCount().
|
||||
DWORD mA11yClipboardCopySuppressionStartTime = 0;
|
||||
};
|
||||
|
||||
extern mscom::SingletonFactory<AccessibleHandlerControl> gControlFactory;
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_AccessibleHandlerControl_h
|
|
@ -0,0 +1,170 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include "HandlerChildEnumerator.h"
|
||||
#include "HandlerTextLeaf.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
HandlerChildEnumerator::HandlerChildEnumerator(
|
||||
AccessibleHandler* aHandler, IGeckoBackChannel* aGeckoBackChannel)
|
||||
: mHandler(aHandler),
|
||||
mGeckoBackChannel(aGeckoBackChannel),
|
||||
mChildCount(0),
|
||||
mNextChild(0) {
|
||||
MOZ_ASSERT(aHandler);
|
||||
MOZ_ASSERT(aGeckoBackChannel);
|
||||
}
|
||||
|
||||
HandlerChildEnumerator::HandlerChildEnumerator(
|
||||
const HandlerChildEnumerator& aEnumerator)
|
||||
: mHandler(aEnumerator.mHandler),
|
||||
mGeckoBackChannel(aEnumerator.mGeckoBackChannel),
|
||||
mChildCount(aEnumerator.mChildCount),
|
||||
mNextChild(aEnumerator.mNextChild) {
|
||||
if (mChildCount == 0) {
|
||||
return;
|
||||
}
|
||||
mChildren = MakeUnique<VARIANT[]>(mChildCount);
|
||||
CopyMemory(mChildren.get(), aEnumerator.mChildren.get(),
|
||||
sizeof(VARIANT) * mChildCount);
|
||||
for (ULONG index = 0; index < mChildCount; ++index) {
|
||||
mChildren[index].pdispVal->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
HandlerChildEnumerator::~HandlerChildEnumerator() { ClearCache(); }
|
||||
|
||||
void HandlerChildEnumerator::ClearCache() {
|
||||
if (!mChildren) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ULONG index = 0; index < mChildCount; ++index) {
|
||||
mChildren[index].pdispVal->Release();
|
||||
}
|
||||
|
||||
mChildren = nullptr;
|
||||
mChildCount = 0;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerChildEnumerator::MaybeCacheChildren() {
|
||||
if (mChildren) {
|
||||
// Already cached.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
AccChildData* children;
|
||||
HRESULT hr = mGeckoBackChannel->get_AllChildren(&children, &mChildCount);
|
||||
if (FAILED(hr)) {
|
||||
mChildCount = 0;
|
||||
ClearCache();
|
||||
return hr;
|
||||
}
|
||||
|
||||
HWND hwnd = nullptr;
|
||||
hr = mHandler->get_windowHandle(&hwnd);
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
RefPtr<IDispatch> parent;
|
||||
hr = mHandler->QueryInterface(IID_IDispatch, getter_AddRefs(parent));
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
mChildren = MakeUnique<VARIANT[]>(mChildCount);
|
||||
for (ULONG index = 0; index < mChildCount; ++index) {
|
||||
AccChildData& data = children[index];
|
||||
VARIANT& child = mChildren[index];
|
||||
if (data.mAccessible) {
|
||||
RefPtr<IDispatch> disp;
|
||||
hr =
|
||||
data.mAccessible->QueryInterface(IID_IDispatch, getter_AddRefs(disp));
|
||||
data.mAccessible->Release();
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
if (FAILED(hr)) {
|
||||
child.vt = VT_EMPTY;
|
||||
continue;
|
||||
}
|
||||
child.vt = VT_DISPATCH;
|
||||
disp.forget(&child.pdispVal);
|
||||
} else {
|
||||
// Text leaf.
|
||||
RefPtr<IDispatch> leaf(new HandlerTextLeaf(parent, index, hwnd, data));
|
||||
child.vt = VT_DISPATCH;
|
||||
leaf.forget(&child.pdispVal);
|
||||
}
|
||||
}
|
||||
|
||||
::CoTaskMemFree(children);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IMPL_IUNKNOWN_QUERY_HEAD(HandlerChildEnumerator)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT)
|
||||
IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler)
|
||||
|
||||
/*** IEnumVARIANT ***/
|
||||
|
||||
HRESULT
|
||||
HandlerChildEnumerator::Clone(IEnumVARIANT** aPpEnum) {
|
||||
RefPtr<HandlerChildEnumerator> newEnum(new HandlerChildEnumerator(*this));
|
||||
newEnum.forget(aPpEnum);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerChildEnumerator::Next(ULONG aCelt, VARIANT* aRgVar,
|
||||
ULONG* aPCeltFetched) {
|
||||
if (!aRgVar || aCelt == 0) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr = MaybeCacheChildren();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (ULONG index = 0; index < aCelt; ++index) {
|
||||
if (mNextChild >= mChildCount) {
|
||||
// Less elements remaining than were requested.
|
||||
if (aPCeltFetched) {
|
||||
*aPCeltFetched = index;
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
aRgVar[index] = mChildren[mNextChild];
|
||||
aRgVar[index].pdispVal->AddRef();
|
||||
++mNextChild;
|
||||
}
|
||||
*aPCeltFetched = aCelt;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerChildEnumerator::Reset() {
|
||||
mNextChild = 0;
|
||||
ClearCache();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerChildEnumerator::Skip(ULONG aCelt) {
|
||||
mNextChild += aCelt;
|
||||
if (mNextChild > mChildCount) {
|
||||
// Less elements remaining than the client requested to skip.
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,51 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#ifndef mozilla_a11y_HandlerChildEnumerator_h
|
||||
# define mozilla_a11y_HandlerChildEnumerator_h
|
||||
|
||||
# include "AccessibleHandler.h"
|
||||
# include "IUnknownImpl.h"
|
||||
# include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class HandlerChildEnumerator final : public IEnumVARIANT {
|
||||
public:
|
||||
explicit HandlerChildEnumerator(AccessibleHandler* aHandler,
|
||||
IGeckoBackChannel* aGeckoBackChannel);
|
||||
|
||||
DECL_IUNKNOWN
|
||||
|
||||
// IEnumVARIANT
|
||||
STDMETHODIMP Clone(IEnumVARIANT** aPpEnum) override;
|
||||
STDMETHODIMP Next(ULONG aCelt, VARIANT* aRgVar,
|
||||
ULONG* aPCeltFetched) override;
|
||||
STDMETHODIMP Reset() override;
|
||||
STDMETHODIMP Skip(ULONG aCelt) override;
|
||||
|
||||
private:
|
||||
explicit HandlerChildEnumerator(const HandlerChildEnumerator& aEnumerator);
|
||||
~HandlerChildEnumerator();
|
||||
void ClearCache();
|
||||
HRESULT MaybeCacheChildren();
|
||||
|
||||
RefPtr<AccessibleHandler> mHandler;
|
||||
RefPtr<IGeckoBackChannel> mGeckoBackChannel;
|
||||
UniquePtr<VARIANT[]> mChildren;
|
||||
ULONG mChildCount;
|
||||
ULONG mNextChild;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_HandlerChildEnumerator_h
|
|
@ -0,0 +1,11 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
[explicit_handle]
|
||||
interface HandlerData
|
||||
{
|
||||
typedef [encode,decode] IA2Payload;
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla-config.h"
|
||||
#include "AccessibleHandler.h"
|
||||
#include "HandlerDataUUID.h"
|
||||
|
||||
import "ocidl.idl";
|
||||
import "servprov.idl";
|
||||
|
||||
import "Accessible2_3.idl";
|
||||
import "AccessibleHypertext2.idl";
|
||||
import "AccessibleHyperlink.idl";
|
||||
import "AccessibleTable.idl";
|
||||
import "AccessibleTable2.idl";
|
||||
import "AccessibleTableCell.idl";
|
||||
|
||||
typedef struct _StaticIA2Data
|
||||
{
|
||||
NEWEST_IA2_INTERFACE* mIA2;
|
||||
IAccessibleHypertext2* mIAHypertext;
|
||||
IAccessibleHyperlink* mIAHyperlink;
|
||||
IAccessibleTable* mIATable;
|
||||
IAccessibleTable2* mIATable2;
|
||||
IAccessibleTableCell* mIATableCell;
|
||||
} StaticIA2Data;
|
||||
|
||||
typedef struct _DynamicIA2Data
|
||||
{
|
||||
// From IAccessible/IAccessible2
|
||||
VARIANT mRole;
|
||||
long mState;
|
||||
long mChildCount;
|
||||
long mIA2Role;
|
||||
AccessibleStates mIA2States;
|
||||
long mLeft;
|
||||
long mTop;
|
||||
long mWidth;
|
||||
long mHeight;
|
||||
long mHwnd;
|
||||
BSTR mKeyboardShortcut;
|
||||
BSTR mName;
|
||||
BSTR mDescription;
|
||||
BSTR mDefaultAction;
|
||||
BSTR mValue;
|
||||
BSTR mAttributes;
|
||||
IA2Locale mIA2Locale;
|
||||
// From IAccessibleAction
|
||||
long mNActions;
|
||||
// From IAccessibleTableCell
|
||||
long mRowIndex;
|
||||
long mColumnIndex;
|
||||
long mRowExtent;
|
||||
long mColumnExtent;
|
||||
boolean mCellIsSelected;
|
||||
long mNRowHeaderCells;
|
||||
[size_is(mNRowHeaderCells)] long* mRowHeaderCellIds;
|
||||
long mNColumnHeaderCells;
|
||||
[size_is(mNColumnHeaderCells)] long* mColumnHeaderCellIds;
|
||||
// From IAccessible2
|
||||
long mUniqueId;
|
||||
} DynamicIA2Data;
|
||||
|
||||
interface IGeckoBackChannel;
|
||||
|
||||
[uuid(2b0e83b3-fd1a-443f-9ed6-c00d39055b58)]
|
||||
interface HandlerData
|
||||
{
|
||||
typedef struct _IA2Payload
|
||||
{
|
||||
StaticIA2Data mStaticData;
|
||||
DynamicIA2Data mDynamicData;
|
||||
IGeckoBackChannel* mGeckoBackChannel;
|
||||
} IA2Payload;
|
||||
}
|
||||
|
||||
[object,
|
||||
uuid(IHANDLERCONTROL_IID),
|
||||
async_uuid(ASYNCIHANDLERCONTROL_IID),
|
||||
pointer_default(unique)]
|
||||
interface IHandlerControl : IUnknown
|
||||
{
|
||||
HRESULT Invalidate();
|
||||
HRESULT OnTextChange([in] long aHwnd, [in] long aIA2UniqueId,
|
||||
[in] VARIANT_BOOL aIsInsert,
|
||||
[in] IA2TextSegment* aText);
|
||||
HRESULT SuppressA11yForClipboardCopy();
|
||||
}
|
||||
|
||||
typedef struct _IARelationData
|
||||
{
|
||||
BSTR mType;
|
||||
long mNTargets;
|
||||
} IARelationData;
|
||||
|
||||
typedef struct _AccChildData
|
||||
{
|
||||
NEWEST_IA2_INTERFACE* mAccessible;
|
||||
BSTR mText;
|
||||
long mTextRole;
|
||||
long mTextId;
|
||||
long mTextState;
|
||||
long mTextLeft;
|
||||
long mTextTop;
|
||||
long mTextWidth;
|
||||
long mTextHeight;
|
||||
} AccChildData;
|
||||
|
||||
[object,
|
||||
uuid(IGECKOBACKCHANNEL_IID),
|
||||
pointer_default(unique)]
|
||||
interface IGeckoBackChannel : IUnknown
|
||||
{
|
||||
[propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl);
|
||||
HRESULT Refresh([out] DynamicIA2Data* aOutData);
|
||||
[propget] HRESULT AllTextInfo([out] BSTR* aText,
|
||||
[out, size_is(,*aNHyperlinks)] IAccessibleHyperlink*** aHyperlinks,
|
||||
[out] long* aNHyperlinks,
|
||||
[out, size_is(,*aNAttribRuns)] IA2TextSegment** aAttribRuns,
|
||||
[out] long* aNAttribRuns);
|
||||
[propget] HRESULT RelationsInfo(
|
||||
[out, size_is(,*aNRelations)] IARelationData** aRelations,
|
||||
[out] long* aNRelations);
|
||||
[propget] HRESULT AllChildren(
|
||||
[out, size_is(,*aNChildren)] AccChildData** aChildren,
|
||||
[out] ULONG* aNChildren);
|
||||
}
|
||||
|
||||
[uuid(1e545f07-f108-4912-9471-546827a80983)]
|
||||
library AccessibleHandlerTypeLib
|
||||
{
|
||||
importlib("stdole2.tlb");
|
||||
|
||||
/**
|
||||
* This definition is required in order for the handler implementation to
|
||||
* support IDispatch (aka Automation). This is used by interpreted language
|
||||
* FFIs to discover which interfaces may be controlled via IDispatch.
|
||||
* (In particular, the python FFI used by NVDA needs this).
|
||||
*
|
||||
* In reality, the only a11y interface that is Automation compliant is
|
||||
* IAccessible; our remaining interfaces are not.
|
||||
*
|
||||
* Once the FFI knows that IAccessible is supported, the FFI queries for
|
||||
* IAccessible and is then able to resolve non-automation interfaces from
|
||||
* there.
|
||||
*/
|
||||
[uuid(HANDLER_CLSID)]
|
||||
coclass AccessibleHandler
|
||||
{
|
||||
[default] interface IAccessible;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_a11y_HandlerDataCleanup_h
|
||||
#define mozilla_a11y_HandlerDataCleanup_h
|
||||
|
||||
#include <oleauto.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
inline void ReleaseStaticIA2DataInterfaces(StaticIA2Data& aData) {
|
||||
// Only interfaces of the proxied object wrapped by this handler should be
|
||||
// released here, never other objects!
|
||||
// For example, if StaticIA2Data were to include accParent in future,
|
||||
// that must not be released here.
|
||||
if (aData.mIA2) {
|
||||
aData.mIA2->Release();
|
||||
}
|
||||
if (aData.mIAHypertext) {
|
||||
aData.mIAHypertext->Release();
|
||||
}
|
||||
if (aData.mIAHyperlink) {
|
||||
aData.mIAHyperlink->Release();
|
||||
}
|
||||
if (aData.mIATable) {
|
||||
aData.mIATable->Release();
|
||||
}
|
||||
if (aData.mIATable2) {
|
||||
aData.mIATable2->Release();
|
||||
}
|
||||
if (aData.mIATableCell) {
|
||||
aData.mIATableCell->Release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass true for aMarshaledByCom if this struct was directly marshaled as an
|
||||
* out parameter of a COM method, currently only IGeckoBackChannel::Refresh.
|
||||
*/
|
||||
inline void CleanupDynamicIA2Data(DynamicIA2Data& aData,
|
||||
bool aMarshaledByCom = false) {
|
||||
// If freeing generic memory returned to the client, you *must* use freeMem,
|
||||
// not CoTaskMemFree!
|
||||
auto freeMem = [aMarshaledByCom](void* aMem) {
|
||||
if (aMarshaledByCom) {
|
||||
::CoTaskMemFree(aMem);
|
||||
} else {
|
||||
::midl_user_free(aMem);
|
||||
}
|
||||
};
|
||||
|
||||
::VariantClear(&aData.mRole);
|
||||
if (aData.mKeyboardShortcut) {
|
||||
::SysFreeString(aData.mKeyboardShortcut);
|
||||
}
|
||||
if (aData.mName) {
|
||||
::SysFreeString(aData.mName);
|
||||
}
|
||||
if (aData.mDescription) {
|
||||
::SysFreeString(aData.mDescription);
|
||||
}
|
||||
if (aData.mDefaultAction) {
|
||||
::SysFreeString(aData.mDefaultAction);
|
||||
}
|
||||
if (aData.mValue) {
|
||||
::SysFreeString(aData.mValue);
|
||||
}
|
||||
if (aData.mAttributes) {
|
||||
::SysFreeString(aData.mAttributes);
|
||||
}
|
||||
if (aData.mIA2Locale.language) {
|
||||
::SysFreeString(aData.mIA2Locale.language);
|
||||
}
|
||||
if (aData.mIA2Locale.country) {
|
||||
::SysFreeString(aData.mIA2Locale.country);
|
||||
}
|
||||
if (aData.mIA2Locale.variant) {
|
||||
::SysFreeString(aData.mIA2Locale.variant);
|
||||
}
|
||||
if (aData.mRowHeaderCellIds) {
|
||||
freeMem(aData.mRowHeaderCellIds);
|
||||
}
|
||||
if (aData.mColumnHeaderCellIds) {
|
||||
freeMem(aData.mColumnHeaderCellIds);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_HandlerDataCleanup_h
|
|
@ -0,0 +1,16 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// We use different CLSIDs and IIDs depending on channel and officiality.
|
||||
// This prevents handlers from installing overtop one another when multiple
|
||||
// channels are present. Note that we only do this for the UUIDs that are
|
||||
// written to the registry.
|
||||
// The specific UUIDs are defined in branding configuration.
|
||||
|
||||
#define HANDLER_CLSID @MOZ_HANDLER_CLSID@
|
||||
#define IHANDLERCONTROL_IID @MOZ_IHANDLERCONTROL_IID@
|
||||
#define ASYNCIHANDLERCONTROL_IID @MOZ_ASYNCIHANDLERCONTROL_IID@
|
||||
#define IGECKOBACKCHANNEL_IID @MOZ_IGECKOBACKCHANNEL_IID@
|
|
@ -0,0 +1,138 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include "HandlerRelation.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "AccessibleRelation_i.c"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
HandlerRelation::HandlerRelation(AccessibleHandler* aHandler,
|
||||
IARelationData& aData)
|
||||
: mHandler(aHandler), mData(aData), mTargets(nullptr) {
|
||||
// This instance now owns any pointers, so ensure no one else can
|
||||
// manipulate them.
|
||||
aData.mType = nullptr;
|
||||
}
|
||||
|
||||
HandlerRelation::~HandlerRelation() {
|
||||
if (mData.mType) {
|
||||
::SysFreeString(mData.mType);
|
||||
}
|
||||
|
||||
if (mTargets) {
|
||||
for (long index = 0; index < mData.mNTargets; ++index) {
|
||||
mTargets[index]->Release();
|
||||
}
|
||||
::CoTaskMemFree(mTargets);
|
||||
mTargets = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerRelation::GetTargets() {
|
||||
if (mTargets) {
|
||||
// Already cached.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Marshaling all of the IAccessibleRelation objects across processes is
|
||||
// slow, and the client probably only wants targets for a few of them.
|
||||
// Therefore, we just use IAccessible2_2::relationTargetsOfType, passing
|
||||
// the type we have cached. This is a bit inefficient because Gecko has
|
||||
// to look up the relation twice, but it's significantly faster than
|
||||
// marshaling the relation objects regardless.
|
||||
return mHandler->get_relationTargetsOfType(mData.mType, 0, &mTargets,
|
||||
&mData.mNTargets);
|
||||
}
|
||||
|
||||
IMPL_IUNKNOWN1(HandlerRelation, IAccessibleRelation)
|
||||
|
||||
/*** IAccessibleRelation ***/
|
||||
|
||||
HRESULT
|
||||
HandlerRelation::get_relationType(BSTR* aType) {
|
||||
if (!aType) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (!mData.mType) {
|
||||
return E_FAIL;
|
||||
}
|
||||
*aType = CopyBSTR(mData.mType);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerRelation::get_localizedRelationType(BSTR* aLocalizedType) {
|
||||
// This is not implemented as per ia2AccessibleRelation.
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerRelation::get_nTargets(long* aNTargets) {
|
||||
if (!aNTargets) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (mData.mNTargets == -1) {
|
||||
return E_FAIL;
|
||||
}
|
||||
*aNTargets = mData.mNTargets;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerRelation::get_target(long aIndex, IUnknown** aTarget) {
|
||||
if (!aTarget) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr = GetTargets();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
if (aIndex >= mData.mNTargets) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*aTarget = mTargets[aIndex];
|
||||
(*aTarget)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerRelation::get_targets(long aMaxTargets, IUnknown** aTargets,
|
||||
long* aNTargets) {
|
||||
if (aMaxTargets == 0 || !aTargets || !aNTargets) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr = GetTargets();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (mData.mNTargets > aMaxTargets) {
|
||||
// Don't give back more targets than were requested.
|
||||
*aNTargets = aMaxTargets;
|
||||
} else {
|
||||
*aNTargets = mData.mNTargets;
|
||||
}
|
||||
|
||||
for (long index = 0; index < *aNTargets; ++index) {
|
||||
aTargets[index] = mTargets[index];
|
||||
aTargets[index]->AddRef();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#ifndef mozilla_a11y_HandlerRelation_h
|
||||
# define mozilla_a11y_HandlerRelation_h
|
||||
|
||||
# include "AccessibleHandler.h"
|
||||
# include "IUnknownImpl.h"
|
||||
# include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class HandlerRelation final : public IAccessibleRelation {
|
||||
public:
|
||||
explicit HandlerRelation(AccessibleHandler* aHandler, IARelationData& aData);
|
||||
|
||||
DECL_IUNKNOWN
|
||||
|
||||
// IAccessibleRelation
|
||||
STDMETHODIMP get_relationType(BSTR* aType) override;
|
||||
STDMETHODIMP get_localizedRelationType(BSTR* aLocalizedType) override;
|
||||
STDMETHODIMP get_nTargets(long* aNTargets) override;
|
||||
STDMETHODIMP get_target(long aIndex, IUnknown** aTarget) override;
|
||||
STDMETHODIMP get_targets(long aMaxTargets, IUnknown** aTargets,
|
||||
long* aNTargets) override;
|
||||
|
||||
private:
|
||||
virtual ~HandlerRelation();
|
||||
HRESULT GetTargets();
|
||||
RefPtr<AccessibleHandler> mHandler;
|
||||
IARelationData mData;
|
||||
IUnknown** mTargets;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_HandlerRelation_h
|
|
@ -0,0 +1,337 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include "HandlerTextLeaf.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
HandlerTextLeaf::HandlerTextLeaf(IDispatch* aParent, long aIndexInParent,
|
||||
HWND aHwnd, AccChildData& aData)
|
||||
: mParent(aParent),
|
||||
mIndexInParent(aIndexInParent),
|
||||
mHwnd(aHwnd),
|
||||
mData(aData) {
|
||||
MOZ_ASSERT(aParent);
|
||||
}
|
||||
|
||||
HandlerTextLeaf::~HandlerTextLeaf() {
|
||||
if (mData.mText) {
|
||||
::SysFreeString(mData.mText);
|
||||
}
|
||||
}
|
||||
|
||||
IMPL_IUNKNOWN_QUERY_HEAD(HandlerTextLeaf)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IDispatch)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IAccessible)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IAccessible2)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
|
||||
IMPL_IUNKNOWN_QUERY_TAIL
|
||||
|
||||
/*** IDispatch ***/
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
|
||||
LCID lcid, DISPID* rgDispId) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
|
||||
WORD wFlags, DISPPARAMS* pDispParams,
|
||||
VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
|
||||
UINT* puArgErr) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
/*** IAccessible ***/
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accParent(IDispatch** ppdispParent) {
|
||||
if (!ppdispParent) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<IDispatch> parent(mParent);
|
||||
parent.forget(ppdispParent);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accChildCount(long* pcountChildren) {
|
||||
if (!pcountChildren) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*pcountChildren = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accChild(VARIANT varChild, IDispatch** ppdispChild) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accName(VARIANT varChild, BSTR* pszName) {
|
||||
if (varChild.lVal != CHILDID_SELF || !pszName) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*pszName = CopyBSTR(mData.mText);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accValue(VARIANT varChild, BSTR* pszValue) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accDescription(VARIANT varChild, BSTR* pszDescription) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accRole(VARIANT varChild, VARIANT* pvarRole) {
|
||||
if (varChild.lVal != CHILDID_SELF || !pvarRole) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
pvarRole->vt = VT_I4;
|
||||
pvarRole->lVal = mData.mTextRole;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accState(VARIANT varChild, VARIANT* pvarState) {
|
||||
if (varChild.lVal != CHILDID_SELF || !pvarState) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
pvarState->vt = VT_I4;
|
||||
pvarState->lVal = mData.mTextState;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accHelp(VARIANT varChild, BSTR* pszHelp) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild,
|
||||
long* pidTopic) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accKeyboardShortcut(VARIANT varChild,
|
||||
BSTR* pszKeyboardShortcut) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accFocus(VARIANT* pvarChild) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accSelection(VARIANT* pvarChildren) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_accDefaultAction(VARIANT varChild,
|
||||
BSTR* pszDefaultAction) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::accSelect(long flagsSelect, VARIANT varChild) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
|
||||
long* pcyHeight, VARIANT varChild) {
|
||||
if (varChild.lVal != CHILDID_SELF || !pxLeft || !pyTop || !pcxWidth ||
|
||||
!pcyHeight) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*pxLeft = mData.mTextLeft;
|
||||
*pyTop = mData.mTextTop;
|
||||
*pcxWidth = mData.mTextWidth;
|
||||
*pcyHeight = mData.mTextHeight;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::accNavigate(long navDir, VARIANT varStart,
|
||||
VARIANT* pvarEndUpAt) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::accHitTest(long xLeft, long yTop, VARIANT* pvarChild) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::accDoDefaultAction(VARIANT varChild) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::put_accName(VARIANT varChild, BSTR szName) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::put_accValue(VARIANT varChild, BSTR szValue) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
/*** IAccessible2 ***/
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_nRelations(long* nRelations) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_relation(long relationIndex,
|
||||
IAccessibleRelation** relation) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_relations(long maxRelations,
|
||||
IAccessibleRelation** relations,
|
||||
long* nRelations) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::role(long* role) {
|
||||
if (!role) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*role = mData.mTextRole;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::scrollTo(IA2ScrollType scrollType) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::scrollToPoint(IA2CoordinateType coordinateType, long x,
|
||||
long y) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_groupPosition(long* groupLevel, long* similarItemsInGroup,
|
||||
long* positionInGroup) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_states(AccessibleStates* states) {
|
||||
if (!states) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*states = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_extendedRole(BSTR* extendedRole) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_localizedExtendedRole(BSTR* localizedExtendedRole) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_nExtendedStates(long* nExtendedStates) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_extendedStates(long maxExtendedStates,
|
||||
BSTR** extendedStates,
|
||||
long* nExtendedStates) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_localizedExtendedStates(long maxLocalizedExtendedStates,
|
||||
BSTR** localizedExtendedStates,
|
||||
long* nLocalizedExtendedStates) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_uniqueID(long* uniqueID) {
|
||||
if (!uniqueID) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*uniqueID = mData.mTextId;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_windowHandle(HWND* windowHandle) {
|
||||
if (!windowHandle) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*windowHandle = mHwnd;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_indexInParent(long* indexInParent) {
|
||||
if (!indexInParent) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*indexInParent = mIndexInParent;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_locale(IA2Locale* locale) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::get_attributes(BSTR* attributes) { return E_NOTIMPL; }
|
||||
|
||||
/*** IServiceProvider ***/
|
||||
|
||||
HRESULT
|
||||
HandlerTextLeaf::QueryService(REFGUID aServiceId, REFIID aIid,
|
||||
void** aOutInterface) {
|
||||
if (aIid == IID_IAccessible2) {
|
||||
RefPtr<IAccessible2> ia2(this);
|
||||
ia2.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
# error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#ifndef mozilla_a11y_HandlerTextLeaf_h
|
||||
# define mozilla_a11y_HandlerTextLeaf_h
|
||||
|
||||
# include "AccessibleHandler.h"
|
||||
# include "IUnknownImpl.h"
|
||||
# include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class HandlerTextLeaf final : public IAccessible2, public IServiceProvider {
|
||||
public:
|
||||
explicit HandlerTextLeaf(IDispatch* aParent, long aIndexInParent, HWND aHwnd,
|
||||
AccChildData& aData);
|
||||
|
||||
DECL_IUNKNOWN
|
||||
|
||||
// IDispatch
|
||||
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) override;
|
||||
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid,
|
||||
ITypeInfo** ppTInfo) override;
|
||||
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
|
||||
LCID lcid, DISPID* rgDispId) override;
|
||||
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
|
||||
DISPPARAMS* pDispParams, VARIANT* pVarResult,
|
||||
EXCEPINFO* pExcepInfo, UINT* puArgErr) override;
|
||||
|
||||
// IAccessible
|
||||
STDMETHODIMP get_accParent(IDispatch** ppdispParent) override;
|
||||
STDMETHODIMP get_accChildCount(long* pcountChildren) override;
|
||||
STDMETHODIMP get_accChild(VARIANT varChild, IDispatch** ppdispChild) override;
|
||||
STDMETHODIMP get_accName(VARIANT varChild, BSTR* pszName) override;
|
||||
STDMETHODIMP get_accValue(VARIANT varChild, BSTR* pszValue) override;
|
||||
STDMETHODIMP get_accDescription(VARIANT varChild,
|
||||
BSTR* pszDescription) override;
|
||||
STDMETHODIMP get_accRole(VARIANT varChild, VARIANT* pvarRole) override;
|
||||
STDMETHODIMP get_accState(VARIANT varChild, VARIANT* pvarState) override;
|
||||
STDMETHODIMP get_accHelp(VARIANT varChild, BSTR* pszHelp) override;
|
||||
STDMETHODIMP get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild,
|
||||
long* pidTopic) override;
|
||||
STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild,
|
||||
BSTR* pszKeyboardShortcut) override;
|
||||
STDMETHODIMP get_accFocus(VARIANT* pvarChild) override;
|
||||
STDMETHODIMP get_accSelection(VARIANT* pvarChildren) override;
|
||||
STDMETHODIMP get_accDefaultAction(VARIANT varChild,
|
||||
BSTR* pszDefaultAction) override;
|
||||
STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild) override;
|
||||
STDMETHODIMP accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
|
||||
long* pcyHeight, VARIANT varChild) override;
|
||||
STDMETHODIMP accNavigate(long navDir, VARIANT varStart,
|
||||
VARIANT* pvarEndUpAt) override;
|
||||
STDMETHODIMP accHitTest(long xLeft, long yTop, VARIANT* pvarChild) override;
|
||||
STDMETHODIMP accDoDefaultAction(VARIANT varChild) override;
|
||||
STDMETHODIMP put_accName(VARIANT varChild, BSTR szName) override;
|
||||
STDMETHODIMP put_accValue(VARIANT varChild, BSTR szValue) override;
|
||||
|
||||
// IAccessible2
|
||||
STDMETHODIMP get_nRelations(long* nRelations) override;
|
||||
STDMETHODIMP get_relation(long relationIndex,
|
||||
IAccessibleRelation** relation) override;
|
||||
STDMETHODIMP get_relations(long maxRelations, IAccessibleRelation** relations,
|
||||
long* nRelations) override;
|
||||
STDMETHODIMP role(long* role) override;
|
||||
STDMETHODIMP scrollTo(IA2ScrollType scrollType) override;
|
||||
STDMETHODIMP scrollToPoint(IA2CoordinateType coordinateType, long x,
|
||||
long y) override;
|
||||
STDMETHODIMP get_groupPosition(long* groupLevel, long* similarItemsInGroup,
|
||||
long* positionInGroup) override;
|
||||
STDMETHODIMP get_states(AccessibleStates* states) override;
|
||||
STDMETHODIMP get_extendedRole(BSTR* extendedRole) override;
|
||||
STDMETHODIMP get_localizedExtendedRole(BSTR* localizedExtendedRole) override;
|
||||
STDMETHODIMP get_nExtendedStates(long* nExtendedStates) override;
|
||||
STDMETHODIMP get_extendedStates(long maxExtendedStates, BSTR** extendedStates,
|
||||
long* nExtendedStates) override;
|
||||
STDMETHODIMP get_localizedExtendedStates(
|
||||
long maxLocalizedExtendedStates, BSTR** localizedExtendedStates,
|
||||
long* nLocalizedExtendedStates) override;
|
||||
STDMETHODIMP get_uniqueID(long* uniqueID) override;
|
||||
STDMETHODIMP get_windowHandle(HWND* windowHandle) override;
|
||||
STDMETHODIMP get_indexInParent(long* indexInParent) override;
|
||||
STDMETHODIMP get_locale(IA2Locale* locale) override;
|
||||
STDMETHODIMP get_attributes(BSTR* attributes) override;
|
||||
|
||||
// IServiceProvider
|
||||
STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aIid,
|
||||
void** aOutInterface) override;
|
||||
|
||||
private:
|
||||
~HandlerTextLeaf();
|
||||
|
||||
RefPtr<IDispatch> mParent;
|
||||
long mIndexInParent;
|
||||
HWND mHwnd;
|
||||
AccChildData mData;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_HandlerTextLeaf_h
|
|
@ -0,0 +1,132 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
SharedLibrary("AccessibleHandler")
|
||||
|
||||
EXPORTS.mozilla.a11y += [
|
||||
"AccessibleHandler.h",
|
||||
"HandlerDataCleanup.h",
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"/accessible/interfaces/ia2",
|
||||
"/ipc/mscom/oop",
|
||||
]
|
||||
|
||||
# We want to generate distinct UUIDs on a per-channel basis, so we need
|
||||
# finer granularity than the standard preprocessor definitions offer.
|
||||
# This generated include allow us to separate local builds from automated
|
||||
# builds, separate beta from release, and use different UUIDs in downstream
|
||||
# projects such as Thunderbird.
|
||||
CONFIGURE_SUBST_FILES += ["HandlerDataUUID.h"]
|
||||
flags = []
|
||||
|
||||
GeneratedFile(
|
||||
"HandlerData.h",
|
||||
"HandlerData_p.c",
|
||||
"HandlerData_i.c",
|
||||
"HandlerData_c.c",
|
||||
"HandlerData_dlldata.c",
|
||||
"HandlerData.tlb",
|
||||
inputs=["HandlerData.idl"],
|
||||
script="/build/midl.py",
|
||||
entry_point="midl",
|
||||
flags=flags
|
||||
+ [
|
||||
"-I",
|
||||
TOPOBJDIR,
|
||||
"-I",
|
||||
TOPOBJDIR + "/dist/include",
|
||||
"-I",
|
||||
TOPSRCDIR + "/other-licenses/ia2",
|
||||
"-I",
|
||||
SRCDIR,
|
||||
"-I",
|
||||
OBJDIR,
|
||||
"-acf",
|
||||
SRCDIR + "/HandlerData.acf",
|
||||
"-dlldata",
|
||||
OBJDIR + "/HandlerData_dlldata.c",
|
||||
],
|
||||
)
|
||||
|
||||
SOURCES += [
|
||||
"!HandlerData_c.c",
|
||||
"!HandlerData_dlldata.c",
|
||||
"!HandlerData_i.c",
|
||||
"!HandlerData_p.c",
|
||||
"AccessibleHandler.cpp",
|
||||
"AccessibleHandlerControl.cpp",
|
||||
"HandlerChildEnumerator.cpp",
|
||||
"HandlerRelation.cpp",
|
||||
"HandlerTextLeaf.cpp",
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
"!HandlerData.h",
|
||||
"!HandlerData_i.c",
|
||||
"!HandlerDataUUID.h",
|
||||
]
|
||||
|
||||
# Give some symbols a unique name in each translation unit, to avoid
|
||||
# collisions caused by https://llvm.org/pr41817.
|
||||
if CONFIG["CC_TYPE"] == "clang-cl":
|
||||
SOURCES["!HandlerData_p.c"].flags += [
|
||||
"-DHandlerData__MIDL_ProcFormatString=HandlerData__MIDL_ProcFormatString__HandlerData_p"
|
||||
]
|
||||
SOURCES["!HandlerData_p.c"].flags += [
|
||||
"-DHandlerData__MIDL_TypeFormatString=HandlerData__MIDL_TypeFormatString__HandlerData_p"
|
||||
]
|
||||
for p in ("dlldata", "c", "i", "p"):
|
||||
SOURCES["!HandlerData_%s.c" % p].flags += [
|
||||
"-DUserMarshalRoutines=UserMarshalRoutines__HandlerData_%s" % p
|
||||
]
|
||||
|
||||
DEFFILE = "AccessibleHandler.def"
|
||||
|
||||
USE_LIBS += [
|
||||
"mscom_oop",
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
"advapi32",
|
||||
"uuid",
|
||||
"rpcrt4",
|
||||
"oleacc",
|
||||
"user32",
|
||||
]
|
||||
|
||||
RCINCLUDE = "AccessibleHandler.rc"
|
||||
|
||||
# Suppress warnings from the MIDL generated code.
|
||||
if CONFIG["CC_TYPE"] == "clang-cl":
|
||||
CFLAGS += [
|
||||
"-Wno-extern-initializer",
|
||||
"-Wno-incompatible-pointer-types",
|
||||
"-Wno-missing-braces",
|
||||
"-Wno-unused-const-variable",
|
||||
]
|
||||
|
||||
# Since we are defining our own COM entry points (DllRegisterServer et al),
|
||||
# but we still want to be able to delegate some work to the generated code,
|
||||
# we add the prefix "Proxy" to all of the generated counterparts.
|
||||
DEFINES["ENTRY_PREFIX"] = "Proxy"
|
||||
DEFINES["REGISTER_PROXY_DLL"] = True
|
||||
LIBRARY_DEFINES["MOZ_MSCOM_REMARSHAL_NO_HANDLER"] = True
|
||||
|
||||
# This DLL may be loaded into other processes, so we need static libs for
|
||||
# Windows 7 and Windows 8.
|
||||
USE_STATIC_LIBS = True
|
||||
|
||||
LIBRARY_DEFINES["UNICODE"] = True
|
||||
LIBRARY_DEFINES["_UNICODE"] = True
|
||||
LIBRARY_DEFINES["MOZ_NO_MOZALLOC"] = True
|
||||
DisableStlWrapping()
|
||||
|
||||
DELAYLOAD_DLLS += [
|
||||
"advapi32.dll",
|
||||
"ktmw32.dll",
|
||||
]
|
|
@ -4,18 +4,38 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG["COMPILE_ENVIRONMENT"] and CONFIG["ACCESSIBILITY"]:
|
||||
DIRS += [
|
||||
"handler",
|
||||
"typelib",
|
||||
]
|
||||
|
||||
if CONFIG["ACCESSIBILITY"]:
|
||||
IPDL_SOURCES += ["PDocAccessible.ipdl"]
|
||||
|
||||
EXPORTS.mozilla.a11y += [
|
||||
"COMPtrTypes.h",
|
||||
"DocAccessibleChild.h",
|
||||
"HandlerProvider.h",
|
||||
"PlatformChild.h",
|
||||
"RemoteAccessible.h",
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
"!./handler/HandlerData_c.c",
|
||||
"COMPtrTypes.cpp",
|
||||
"DocAccessibleChild.cpp",
|
||||
"HandlerProvider.cpp",
|
||||
"PlatformChild.cpp",
|
||||
]
|
||||
|
||||
# Give some symbols a unique name in each translation unit, to avoid
|
||||
# collisions caused by https://llvm.org/pr41817.
|
||||
if CONFIG["CC_TYPE"] == "clang-cl":
|
||||
SOURCES["!./handler/HandlerData_c.c"].flags += [
|
||||
"-DUserMarshalRoutines=UserMarshalRoutines__HandlerData_c"
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"/accessible/base",
|
||||
"/accessible/generic",
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import "oaidl.idl";
|
||||
import "servprov.idl";
|
||||
|
||||
[uuid(b4d37cda-0dac-45e6-b613-158a5eb94293)]
|
||||
library Accessible
|
||||
{
|
||||
interface IEnumVARIANT;
|
||||
interface IServiceProvider;
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
FINAL_TARGET_FILES += [
|
||||
"!Accessible.tlb",
|
||||
]
|
||||
|
||||
GeneratedFile(
|
||||
"Accessible.tlb",
|
||||
inputs=["Accessible.idl"],
|
||||
script="/build/midl.py",
|
||||
entry_point="midl",
|
||||
)
|
|
@ -8,7 +8,6 @@
|
|||
#include "ia2AccessibleHypertext.h"
|
||||
|
||||
#include "AccessibleHypertext_i.c"
|
||||
#include "AccessibleHypertext2_i.c"
|
||||
|
||||
#include "mozilla/a11y/HyperTextAccessibleBase.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- 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 "GeckoCustom.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
IMPL_IUNKNOWN_QUERY_HEAD(GeckoCustom)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IGeckoCustom)
|
||||
IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mMsaa)
|
||||
|
||||
HRESULT
|
||||
GeckoCustom::get_anchorCount(long* aCount) {
|
||||
AccessibleWrap* acc = mMsaa->LocalAcc();
|
||||
if (!acc) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
*aCount = acc->AnchorCount();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GeckoCustom::get_boundsInCSSPixels(int32_t* aX, int32_t* aY, int32_t* aWidth,
|
||||
int32_t* aHeight) {
|
||||
AccessibleWrap* acc = mMsaa->LocalAcc();
|
||||
if (!acc) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
nsIntRect bounds = acc->BoundsInCSSPixels();
|
||||
if (!bounds.IsEmpty()) {
|
||||
*aWidth = bounds.Width();
|
||||
*aHeight = bounds.Height();
|
||||
}
|
||||
// We should always report positional bounds info, even if
|
||||
// our rect is empty.
|
||||
*aX = bounds.X();
|
||||
*aY = bounds.Y();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GeckoCustom::get_DOMNodeID(BSTR* aID) {
|
||||
AccessibleWrap* acc = mMsaa->LocalAcc();
|
||||
if (!acc) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
nsIContent* content = acc->GetContent();
|
||||
if (!content) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
nsAtom* id = content->GetID();
|
||||
if (id) {
|
||||
nsAutoString idStr;
|
||||
id->ToString(idStr);
|
||||
*aID = ::SysAllocStringLen(idStr.get(), idStr.Length());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
GeckoCustom::get_ID(uint64_t* aID) {
|
||||
AccessibleWrap* acc = mMsaa->LocalAcc();
|
||||
if (!acc) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
*aID = acc->IsDoc() ? 0 : reinterpret_cast<uintptr_t>(acc);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
GeckoCustom::get_minimumIncrement(double* aIncrement) {
|
||||
AccessibleWrap* acc = mMsaa->LocalAcc();
|
||||
if (!acc) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
*aIncrement = acc->Step();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
GeckoCustom::get_mozState(uint64_t* aState) {
|
||||
AccessibleWrap* acc = mMsaa->LocalAcc();
|
||||
if (!acc) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
*aState = acc->State();
|
||||
return S_OK;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_a11y_GeckoCustom_h_
|
||||
#define mozilla_a11y_GeckoCustom_h_
|
||||
|
||||
#include "IUnknownImpl.h"
|
||||
#include "IGeckoCustom.h"
|
||||
#include "MsaaAccessible.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
/**
|
||||
* a dumpster to put things exposed by the xpcom API but not a windows platform
|
||||
* API for the purposes of testing.
|
||||
*/
|
||||
class GeckoCustom final : public IGeckoCustom {
|
||||
public:
|
||||
explicit GeckoCustom(MsaaAccessible* aMsaa) : mMsaa(aMsaa) {}
|
||||
|
||||
// IUnknown
|
||||
DECL_IUNKNOWN
|
||||
|
||||
virtual STDMETHODIMP get_anchorCount(long* aCount);
|
||||
virtual STDMETHODIMP get_boundsInCSSPixels(int32_t* aX, int32_t* aY,
|
||||
int32_t* aWidth, int32_t* aHeight);
|
||||
virtual STDMETHODIMP get_DOMNodeID(BSTR* aID);
|
||||
virtual STDMETHODIMP get_ID(uint64_t* aID);
|
||||
virtual STDMETHODIMP get_minimumIncrement(double* aIncrement);
|
||||
virtual STDMETHODIMP get_mozState(uint64_t* aState);
|
||||
|
||||
private:
|
||||
GeckoCustom() = delete;
|
||||
GeckoCustom& operator=(const GeckoCustom&) = delete;
|
||||
GeckoCustom(const GeckoCustom&) = delete;
|
||||
GeckoCustom(GeckoCustom&&) = delete;
|
||||
GeckoCustom& operator=(GeckoCustom&&) = delete;
|
||||
|
||||
~GeckoCustom() {}
|
||||
|
||||
protected:
|
||||
RefPtr<MsaaAccessible> mMsaa;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/a11y/LocalAccessible.h"
|
||||
#include "mozilla/a11y/AccessibleHandler.h"
|
||||
#include "mozilla/a11y/Compatibility.h"
|
||||
#include "mozilla/a11y/Platform.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
@ -723,26 +724,6 @@ LazyInstantiator::put_accValue(VARIANT varChild, BSTR szValue) {
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static const GUID kUnsupportedServices[] = {
|
||||
// clang-format off
|
||||
// Unknown, queried by Windows on devices with touch screens or similar devices
|
||||
// connected.
|
||||
{0x33f139ee, 0xe509, 0x47f7, {0xbf, 0x39, 0x83, 0x76, 0x44, 0xf7, 0x45, 0x76}},
|
||||
// Unknown, queried by Windows
|
||||
{0xFDA075CF, 0x7C8B, 0x498C, { 0xB5, 0x14, 0xA9, 0xCB, 0x52, 0x1B, 0xBF, 0xB4 }},
|
||||
// Unknown, queried by Windows
|
||||
{0x8EDAA462, 0x21F4, 0x4C87, { 0xA0, 0x12, 0xB3, 0xCD, 0xA3, 0xAB, 0x01, 0xFC }},
|
||||
// Unknown, queried by Windows
|
||||
{0xacd46652, 0x829d, 0x41cb, { 0xa5, 0xfc, 0x17, 0xac, 0xf4, 0x36, 0x61, 0xac }},
|
||||
// SID_IsUIAutomationObject (undocumented), queried by Windows
|
||||
{0xb96fdb85, 0x7204, 0x4724, { 0x84, 0x2b, 0xc7, 0x05, 0x9d, 0xed, 0xb9, 0xd0 }},
|
||||
// IIS_IsOleaccProxy (undocumented), queried by Windows
|
||||
{0x902697FA, 0x80E4, 0x4560, {0x80, 0x2A, 0xA1, 0x3F, 0x22, 0xA6, 0x47, 0x09}},
|
||||
// IID_IHTMLElement, queried by JAWS
|
||||
{0x3050F1FF, 0x98B5, 0x11CF, {0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B}}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
HRESULT
|
||||
LazyInstantiator::QueryService(REFGUID aServiceId, REFIID aServiceIid,
|
||||
void** aOutInterface) {
|
||||
|
|
|
@ -6,15 +6,25 @@
|
|||
|
||||
#include "Platform.h"
|
||||
|
||||
#include <olectl.h>
|
||||
|
||||
#include "AccEvent.h"
|
||||
#include "Compatibility.h"
|
||||
#include "HyperTextAccessibleWrap.h"
|
||||
#include "nsIWindowsRegKey.h"
|
||||
#include "nsWinUtils.h"
|
||||
#include "mozilla/a11y/DocAccessibleParent.h"
|
||||
#include "mozilla/a11y/RemoteAccessible.h"
|
||||
#include "mozilla/mscom/ActivationContext.h"
|
||||
#include "mozilla/mscom/InterceptorLog.h"
|
||||
#include "mozilla/mscom/Registration.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/WinHeaderOnlyUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "WinUtils.h"
|
||||
#include "ia2AccessibleText.h"
|
||||
|
||||
|
@ -28,17 +38,85 @@ using namespace mozilla;
|
|||
using namespace mozilla::a11y;
|
||||
using namespace mozilla::mscom;
|
||||
|
||||
static StaticAutoPtr<RegisteredProxy> gRegCustomProxy;
|
||||
static StaticAutoPtr<RegisteredProxy> gRegProxy;
|
||||
static StaticAutoPtr<RegisteredProxy> gRegAccTlb;
|
||||
static StaticAutoPtr<RegisteredProxy> gRegMiscTlb;
|
||||
static StaticRefPtr<nsIFile> gInstantiator;
|
||||
|
||||
static bool RegisterHandlerMsix() {
|
||||
// If we're running in an MSIX container, the handler isn't registered in
|
||||
// HKLM. We could do that via registry.dat, but that file is difficult to
|
||||
// manage. Instead, we register it in HKCU if it isn't already. This also
|
||||
// covers the case where we registered in HKCU in a previous run, but the
|
||||
// MSIX was updated and the dll now has a different path. In that case,
|
||||
// IsHandlerRegistered will return false because the paths are different,
|
||||
// RegisterHandlerMsix will get called and it will correct the HKCU entry. We
|
||||
// don't need to unregister because we'll always need this and Windows cleans
|
||||
// up the registry data for an MSIX app when it is uninstalled.
|
||||
nsCOMPtr<nsIFile> handlerPath;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(handlerPath));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rv = handlerPath->Append(u"AccessibleHandler.dll"_ns);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
nsAutoString path;
|
||||
rv = handlerPath->GetPath(path);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsModuleHandle handlerDll(LoadLibrary(path.get()));
|
||||
if (!handlerDll.get()) {
|
||||
return false;
|
||||
}
|
||||
auto RegisterMsix = reinterpret_cast<decltype(&DllRegisterServer)>(
|
||||
GetProcAddress(handlerDll, "RegisterMsix"));
|
||||
if (!RegisterMsix) {
|
||||
return false;
|
||||
}
|
||||
if (FAILED(RegisterMsix())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void a11y::PlatformInit() {
|
||||
nsWinUtils::MaybeStartWindowEmulation();
|
||||
ia2AccessibleText::InitTextChangeData();
|
||||
|
||||
mscom::InterceptorLog::Init();
|
||||
UniquePtr<RegisteredProxy> regCustomProxy(mscom::RegisterProxy());
|
||||
gRegCustomProxy = regCustomProxy.release();
|
||||
UniquePtr<RegisteredProxy> regProxy(mscom::RegisterProxy(L"ia2marshal.dll"));
|
||||
gRegProxy = regProxy.release();
|
||||
UniquePtr<RegisteredProxy> regAccTlb(mscom::RegisterTypelib(
|
||||
L"oleacc.dll", RegistrationFlags::eUseSystemDirectory));
|
||||
gRegAccTlb = regAccTlb.release();
|
||||
UniquePtr<RegisteredProxy> regMiscTlb(
|
||||
mscom::RegisterTypelib(L"Accessible.tlb"));
|
||||
gRegMiscTlb = regMiscTlb.release();
|
||||
|
||||
if (XRE_IsParentProcess() && widget::WinUtils::HasPackageIdentity() &&
|
||||
!IsHandlerRegistered()) {
|
||||
// See the comments at the top of RegisterHandlerMsix regarding why we do
|
||||
// this.
|
||||
RegisterHandlerMsix();
|
||||
}
|
||||
}
|
||||
|
||||
void a11y::PlatformShutdown() {
|
||||
::DestroyCaret();
|
||||
|
||||
nsWinUtils::ShutdownWindowEmulation();
|
||||
gRegCustomProxy = nullptr;
|
||||
gRegProxy = nullptr;
|
||||
gRegAccTlb = nullptr;
|
||||
gRegMiscTlb = nullptr;
|
||||
|
||||
if (gInstantiator) {
|
||||
gInstantiator = nullptr;
|
||||
|
@ -123,6 +201,60 @@ void a11y::ProxySelectionEvent(RemoteAccessible* aTarget, RemoteAccessible*,
|
|||
MsaaAccessible::FireWinEvent(aTarget, aType);
|
||||
}
|
||||
|
||||
bool a11y::IsHandlerRegistered() {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWindowsRegKey> regKey =
|
||||
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString clsid;
|
||||
GUIDToString(CLSID_AccessibleHandler, clsid);
|
||||
|
||||
nsAutoString subKey;
|
||||
subKey.AppendLiteral(u"SOFTWARE\\Classes\\CLSID\\");
|
||||
subKey.Append(clsid);
|
||||
subKey.AppendLiteral(u"\\InprocHandler32");
|
||||
|
||||
// If we're runnig in an MSIX container, we register this in HKCU, so look
|
||||
// there.
|
||||
const auto rootKey = widget::WinUtils::HasPackageIdentity()
|
||||
? nsIWindowsRegKey::ROOT_KEY_CURRENT_USER
|
||||
: nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE;
|
||||
rv = regKey->Open(rootKey, subKey, nsIWindowsRegKey::ACCESS_READ);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString handlerPath;
|
||||
rv = regKey->ReadStringValue(nsAutoString(), handlerPath);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> actualHandler;
|
||||
rv = NS_NewLocalFile(handlerPath, false, getter_AddRefs(actualHandler));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> expectedHandler;
|
||||
rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(expectedHandler));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rv = expectedHandler->Append(u"AccessibleHandler.dll"_ns);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool equal;
|
||||
rv = expectedHandler->Equals(actualHandler, &equal);
|
||||
return NS_SUCCEEDED(rv) && equal;
|
||||
}
|
||||
|
||||
static bool GetInstantiatorExecutable(const DWORD aPid,
|
||||
nsIFile** aOutClientExe) {
|
||||
nsAutoHandle callingProcess(
|
||||
|
|
|
@ -25,6 +25,7 @@ UNIFIED_SOURCES += [
|
|||
"CompatibilityUIA.cpp",
|
||||
"DocAccessibleWrap.cpp",
|
||||
"EnumVariant.cpp",
|
||||
"GeckoCustom.cpp",
|
||||
"HyperTextAccessibleWrap.cpp",
|
||||
"IUnknownImpl.cpp",
|
||||
"MsaaAccessible.cpp",
|
||||
|
|
|
@ -5,3 +5,9 @@
|
|||
MOZ_APP_DISPLAYNAME="Firefox Developer Edition"
|
||||
MOZ_APP_REMOTINGNAME=firefox-dev
|
||||
MOZ_DEV_EDITION=1
|
||||
|
||||
# Devedition builds - use same as release channel
|
||||
MOZ_HANDLER_CLSID="1baa303d-b4b9-45e5-9ccb-e3fca3e274b6"
|
||||
MOZ_IHANDLERCONTROL_IID="ce30f77e-8847-44f0-a648-a9656bd89c0d"
|
||||
MOZ_ASYNCIHANDLERCONTROL_IID="dca8d857-1a63-4045-8f36-8809eb093d04"
|
||||
MOZ_IGECKOBACKCHANNEL_IID="b32983ff-ef84-4945-8f86-fb7491b4f57b"
|
||||
|
|
|
@ -4,3 +4,8 @@
|
|||
|
||||
MOZ_APP_DISPLAYNAME="Firefox Nightly"
|
||||
MOZ_MACBUNDLE_ID=nightly
|
||||
|
||||
MOZ_HANDLER_CLSID="4629216b-8753-41bf-9527-5bff51401671"
|
||||
MOZ_IHANDLERCONTROL_IID="c57343fc-e011-40c2-b748-da82eabf0f1f"
|
||||
MOZ_ASYNCIHANDLERCONTROL_IID="648c92a1-ea35-46da-a806-6b55c6247373"
|
||||
MOZ_IGECKOBACKCHANNEL_IID="e61e038d-40dd-464a-9aba-66b206b6911b"
|
||||
|
|
|
@ -3,3 +3,17 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MOZ_APP_DISPLAYNAME=Firefox
|
||||
|
||||
if test "$MOZ_UPDATE_CHANNEL" = "beta"; then
|
||||
# Official beta builds
|
||||
MOZ_HANDLER_CLSID="21e9f98d-a6c9-4cb5-b288-ae2fd2a96c58"
|
||||
MOZ_IHANDLERCONTROL_IID="119149fa-d212-4f22-9517-082eecc1a084"
|
||||
MOZ_ASYNCIHANDLERCONTROL_IID="4e253d9b-59cf-4b32-a973-38bc85495d61"
|
||||
MOZ_IGECKOBACKCHANNEL_IID="77b75c7d-d1c2-4469-864d-31aaebb67cc6"
|
||||
else
|
||||
# Official release/esr builds
|
||||
MOZ_HANDLER_CLSID="1baa303d-b4b9-45e5-9ccb-e3fca3e274b6"
|
||||
MOZ_IHANDLERCONTROL_IID="ce30f77e-8847-44f0-a648-a9656bd89c0d"
|
||||
MOZ_ASYNCIHANDLERCONTROL_IID="dca8d857-1a63-4045-8f36-8809eb093d04"
|
||||
MOZ_IGECKOBACKCHANNEL_IID="b32983ff-ef84-4945-8f86-fb7491b4f57b"
|
||||
fi
|
||||
|
|
|
@ -3,3 +3,19 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MOZ_APP_DISPLAYNAME=Nightly
|
||||
|
||||
if test "$DEVELOPER_OPTIONS"; then
|
||||
if test "$MOZ_DEBUG"; then
|
||||
# Local debug builds
|
||||
MOZ_HANDLER_CLSID="398ffd8d-5382-48f7-9e3b-19012762d39a"
|
||||
MOZ_IHANDLERCONTROL_IID="a218497e-8b10-460b-b668-a92b7ee39ff2"
|
||||
MOZ_ASYNCIHANDLERCONTROL_IID="ca18b9ab-04b6-41be-87f7-d99913d6a2e8"
|
||||
MOZ_IGECKOBACKCHANNEL_IID="231c4946-4479-4c8e-aadc-8a0e48fc4c51"
|
||||
else
|
||||
# Local non-debug builds
|
||||
MOZ_HANDLER_CLSID="ce573faf-7815-4fc2-a031-b092268ace9e"
|
||||
MOZ_IHANDLERCONTROL_IID="2b715cce-1790-4fe1-aef5-48bb5acdf3a1"
|
||||
MOZ_ASYNCIHANDLERCONTROL_IID="8e089670-4f57-41a7-89c0-37f17482fa6f"
|
||||
MOZ_IGECKOBACKCHANNEL_IID="18e2488d-310f-400f-8339-0e50b513e801"
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -167,7 +167,10 @@
|
|||
; [Components]
|
||||
#ifdef ACCESSIBILITY
|
||||
#ifdef XP_WIN
|
||||
@BINPATH@/Accessible.tlb
|
||||
@BINPATH@/AccessibleHandler.dll
|
||||
@BINPATH@/AccessibleMarshal.dll
|
||||
@BINPATH@/IA2Marshal.dll
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ DEFINES["MOZILLA_VERSION"] = CONFIG["MOZILLA_VERSION"]
|
|||
# Turn `firefox` into `Firefox`.
|
||||
DEFINES["MOZ_TOAST_APP_NAME"] = "%s" % CONFIG["MOZ_APP_NAME"].title()
|
||||
|
||||
DEFINES["MOZ_HANDLER_CLSID"] = "{%s}" % CONFIG["MOZ_HANDLER_CLSID"]
|
||||
|
||||
if CONFIG["MOZ_DEFAULT_BROWSER_AGENT"]:
|
||||
DEFINES["MOZ_DEFAULT_BROWSER_AGENT"] = CONFIG["MOZ_DEFAULT_BROWSER_AGENT"]
|
||||
|
||||
|
|
|
@ -112,9 +112,20 @@
|
|||
<!-- These COM registrations allow Windows/MSAA to access Firefox accessibility features. -->
|
||||
<com:Extension Category="windows.comInterface">
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub DisplayName="AccessibleHandler"
|
||||
Id="@MOZ_IGECKOBACKCHANNEL_IID@"
|
||||
Path="VFS\ProgramFiles\@APPX_INSTDIR@\AccessibleHandler.dll" />
|
||||
<com:ProxyStub DisplayName="AccessibleMarshal"
|
||||
Id="1814ceeb-49e2-407f-af99-fa755a7d2607"
|
||||
Path="VFS\ProgramFiles\@APPX_INSTDIR@\AccessibleMarshal.dll" />
|
||||
<com:Interface Id="@MOZ_IGECKOBACKCHANNEL_IID@"
|
||||
ProxyStubClsid="@MOZ_IGECKOBACKCHANNEL_IID@" />
|
||||
<com:Interface Id="@MOZ_IHANDLERCONTROL_IID@"
|
||||
ProxyStubClsid="@MOZ_IGECKOBACKCHANNEL_IID@"
|
||||
AsynchronousInterface="@MOZ_ASYNCIHANDLERCONTROL_IID@" />
|
||||
<com:Interface Id="@MOZ_ASYNCIHANDLERCONTROL_IID@"
|
||||
ProxyStubClsid="@MOZ_IGECKOBACKCHANNEL_IID@"
|
||||
SynchronousInterface="@MOZ_IHANDLERCONTROL_IID@" />
|
||||
<com:Interface Id="4e747be5-2052-4265-8af0-8ecad7aad1c0"
|
||||
ProxyStubClsid="1814ceeb-49e2-407f-af99-fa755a7d2607" />
|
||||
<com:Interface Id="1814ceeb-49e2-407f-af99-fa755a7d2607"
|
||||
|
|
|
@ -72,6 +72,8 @@
|
|||
!define UpdateChannel "@MOZ_UPDATE_CHANNEL@"
|
||||
!endif
|
||||
|
||||
!define AccessibleHandlerCLSID "@MOZ_HANDLER_CLSID@"
|
||||
|
||||
#ifdef MOZ_LAUNCHER_PROCESS
|
||||
!define MOZ_LAUNCHER_PROCESS
|
||||
!define MOZ_LAUNCHER_SUBKEY "Software\Mozilla\${AppName}\Launcher"
|
||||
|
|
|
@ -373,6 +373,16 @@ Section "-Application" APP_IDX
|
|||
|
||||
ClearErrors
|
||||
|
||||
${RegisterDLL} "$INSTDIR\AccessibleHandler.dll"
|
||||
${If} ${Errors}
|
||||
${LogMsg} "** ERROR Registering: $INSTDIR\AccessibleHandler.dll **"
|
||||
${Else}
|
||||
${LogUninstall} "DLLReg: \AccessibleHandler.dll"
|
||||
${LogMsg} "Registered: $INSTDIR\AccessibleHandler.dll"
|
||||
${EndIf}
|
||||
|
||||
ClearErrors
|
||||
|
||||
; Record the Windows Error Reporting module
|
||||
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\RuntimeExceptionHelperModules" "$INSTDIR\mozwer.dll" 0
|
||||
${If} ${Errors}
|
||||
|
|
|
@ -113,6 +113,9 @@
|
|||
|
||||
RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}"
|
||||
|
||||
; Register AccessibleHandler.dll with COM (this requires write access to HKLM)
|
||||
${RegisterAccessibleHandler}
|
||||
|
||||
; Register AccessibleMarshal.dll with COM (this requires write access to HKLM)
|
||||
${RegisterAccessibleMarshal}
|
||||
|
||||
|
@ -1128,6 +1131,11 @@ ${RemoveDefaultBrowserAgentShortcut}
|
|||
!define AddMaintCertKeys "!insertmacro AddMaintCertKeys"
|
||||
!endif
|
||||
|
||||
!macro RegisterAccessibleHandler
|
||||
${RegisterDLL} "$INSTDIR\AccessibleHandler.dll"
|
||||
!macroend
|
||||
!define RegisterAccessibleHandler "!insertmacro RegisterAccessibleHandler"
|
||||
|
||||
!macro RegisterAccessibleMarshal
|
||||
${RegisterDLL} "$INSTDIR\AccessibleMarshal.dll"
|
||||
!macroend
|
||||
|
@ -1143,11 +1151,6 @@ ${RemoveDefaultBrowserAgentShortcut}
|
|||
; Remove protocol handler registry keys added by the MS shim
|
||||
DeleteRegKey HKLM "Software\Classes\Firefox.URL"
|
||||
DeleteRegKey HKCU "Software\Classes\Firefox.URL"
|
||||
|
||||
; Unregister deprecated AccessibleHandler.dll.
|
||||
${If} ${FileExists} "$INSTDIR\AccessibleHandler.dll"
|
||||
${UnregisterDLL} "$INSTDIR\AccessibleHandler.dll"
|
||||
${EndIf}
|
||||
!macroend
|
||||
!define RemoveDeprecatedKeys "!insertmacro RemoveDeprecatedKeys"
|
||||
|
||||
|
@ -1478,7 +1481,9 @@ ${RemoveDefaultBrowserAgentShortcut}
|
|||
; should be ${FileMainEXE} so if it is in use the CheckForFilesInUse macro
|
||||
; returns after the first check.
|
||||
Push "end"
|
||||
Push "AccessibleHandler.dll"
|
||||
Push "AccessibleMarshal.dll"
|
||||
Push "IA2Marshal.dll"
|
||||
Push "freebl3.dll"
|
||||
Push "nssckbi.dll"
|
||||
Push "nspr4.dll"
|
||||
|
|
|
@ -600,7 +600,9 @@ Section "Uninstall"
|
|||
${UnregisterDLL} "$INSTDIR\AccessibleMarshal.dll"
|
||||
${EndIf}
|
||||
|
||||
${If} ${FileExists} "$INSTDIR\AccessibleHandler.dll"
|
||||
; Only unregister the dll if the registration points to this installation
|
||||
ReadRegStr $R1 HKCR "CLSID\${AccessibleHandlerCLSID}\InprocHandler32" ""
|
||||
${If} "$INSTDIR\AccessibleHandler.dll" == "$R1"
|
||||
${UnregisterDLL} "$INSTDIR\AccessibleHandler.dll"
|
||||
${EndIf}
|
||||
|
||||
|
|
|
@ -770,6 +770,9 @@ void ContentChild::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint,
|
|||
// If communications with the parent have broken down, take the process
|
||||
// down so it's not hanging around.
|
||||
GetIPCChannel()->SetAbortOnError(true);
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_A11Y_REENTRY);
|
||||
#endif
|
||||
|
||||
// This must be checked before any IPDL message, which may hit sentinel
|
||||
// errors due to parent and content processes having different
|
||||
|
|
|
@ -25,12 +25,16 @@
|
|||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIBrowserDOMWindow.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
# include "mozilla/a11y/PDocAccessible.h"
|
||||
#endif
|
||||
#include "GMPServiceParent.h"
|
||||
#include "HandlerServiceParent.h"
|
||||
#include "IHistory.h"
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
# include "mozilla/a11y/AccessibleWrap.h"
|
||||
# include "mozilla/a11y/Compatibility.h"
|
||||
# include "mozilla/mscom/ActCtxResource.h"
|
||||
#endif
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
@ -314,6 +318,10 @@
|
|||
# include "mozilla/WinDllServices.h"
|
||||
#endif
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
# include "nsAccessibilityService.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CODE_COVERAGE
|
||||
# include "mozilla/CodeCoverageHandler.h"
|
||||
#endif
|
||||
|
@ -2641,6 +2649,20 @@ bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
|
|||
// processes.
|
||||
::mozilla::ipc::ExportSharedJSInit(*mSubprocess, extraArgs);
|
||||
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
// Determining the accessibility resource ID causes problems with the sandbox,
|
||||
// so we pass it on the command line as it is required very early in process
|
||||
// start up. It is not required when the caching mechanism is being used.
|
||||
if (!a11y::IsCacheActive()) {
|
||||
// The accessibility resource ID may not be set in some cases, for example
|
||||
// in xpcshell tests.
|
||||
auto resourceId = mscom::ActCtxResource::GetAccessibilityResourceId();
|
||||
if (resourceId) {
|
||||
geckoargs::sA11yResourceId.Put(resourceId, extraArgs);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Register ContentParent as an observer for changes to any pref
|
||||
// whose prefix matches the empty string, i.e. all of them. The
|
||||
// observation starts here in order to capture pref updates that
|
||||
|
@ -6242,6 +6264,22 @@ ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool ContentParent::HandleWindowsMessages(const Message& aMsg) const {
|
||||
MOZ_ASSERT(aMsg.is_sync());
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
// a11y messages can be triggered by windows messages, which means if we
|
||||
// allow handling windows messages while we wait for the response to a sync
|
||||
// a11y message we can reenter the ipc message sending code.
|
||||
if (a11y::PDocAccessible::PDocAccessibleStart < aMsg.type() &&
|
||||
a11y::PDocAccessible::PDocAccessibleEnd > aMsg.type()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvGetFilesRequest(
|
||||
const nsID& aUUID, const nsAString& aDirectoryPath,
|
||||
const bool& aRecursiveFlag) {
|
||||
|
|
|
@ -483,6 +483,8 @@ class ContentParent final : public PContentParent,
|
|||
bool DeallocPContentPermissionRequestParent(
|
||||
PContentPermissionRequestParent* actor);
|
||||
|
||||
virtual bool HandleWindowsMessages(const Message& aMsg) const override;
|
||||
|
||||
void ForkNewProcess(bool aBlocking);
|
||||
|
||||
mozilla::ipc::IPCResult RecvCreateWindow(
|
||||
|
|
|
@ -1312,6 +1312,7 @@ bool MessageChannel::Send(UniquePtr<Message> aMsg, UniquePtr<Message>* aReply) {
|
|||
int32_t transaction = nest ? stackTop->TransactionID() : seqno;
|
||||
aMsg->set_transaction_id(transaction);
|
||||
|
||||
bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg.get());
|
||||
AutoEnterTransaction transact(this, seqno, transaction, nestedLevel);
|
||||
|
||||
IPC_LOG("Send seqno=%d, xid=%d", seqno, transaction);
|
||||
|
@ -1339,7 +1340,7 @@ bool MessageChannel::Send(UniquePtr<Message> aMsg, UniquePtr<Message>* aReply) {
|
|||
MOZ_RELEASE_ASSERT(!transact.IsComplete());
|
||||
MOZ_RELEASE_ASSERT(mTransactionStack == &transact);
|
||||
|
||||
bool maybeTimedOut = !WaitForSyncNotify();
|
||||
bool maybeTimedOut = !WaitForSyncNotify(handleWindowsMessages);
|
||||
|
||||
if (mListener->NeedArtificialSleep()) {
|
||||
MonitorAutoUnlock unlock(*mMonitor);
|
||||
|
@ -1827,7 +1828,7 @@ bool MessageChannel::WaitResponse(bool aWaitTimedOut) {
|
|||
}
|
||||
|
||||
#ifndef OS_WIN
|
||||
bool MessageChannel::WaitForSyncNotify() {
|
||||
bool MessageChannel::WaitForSyncNotify(bool /* aHandleWindowsMessages */) {
|
||||
AssertWorkerThread();
|
||||
# ifdef DEBUG
|
||||
// WARNING: We don't release the lock here. We can't because the link
|
||||
|
|
|
@ -224,6 +224,11 @@ class MessageChannel : HasResultCodes {
|
|||
// that manage child processes which might create native UI, like
|
||||
// plugins.
|
||||
REQUIRE_DEFERRED_MESSAGE_PROTECTION = 1 << 0,
|
||||
// Windows: When this flag is specified, any wait that occurs during
|
||||
// synchronous IPC will be alertable, thus allowing a11y code in the
|
||||
// chrome process to reenter content while content is waiting on a
|
||||
// synchronous call.
|
||||
REQUIRE_A11Y_REENTRY = 1 << 1,
|
||||
};
|
||||
void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; }
|
||||
ChannelFlags GetChannelFlags() { return mFlags; }
|
||||
|
@ -358,7 +363,10 @@ class MessageChannel : HasResultCodes {
|
|||
|
||||
private:
|
||||
void SpinInternalEventLoop();
|
||||
#endif // defined(OS_WIN)
|
||||
# if defined(ACCESSIBILITY)
|
||||
bool WaitForSyncNotifyWithA11yReentry();
|
||||
# endif // defined(ACCESSIBILITY)
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
private:
|
||||
void PostErrorNotifyTask() MOZ_REQUIRES(*mMonitor);
|
||||
|
@ -405,7 +413,7 @@ class MessageChannel : HasResultCodes {
|
|||
//
|
||||
// So in sum: true is a meaningful return value; false isn't,
|
||||
// necessarily.
|
||||
bool WaitForSyncNotify() MOZ_REQUIRES(*mMonitor);
|
||||
bool WaitForSyncNotify(bool aHandleWindowsMessages) MOZ_REQUIRES(*mMonitor);
|
||||
|
||||
bool WaitResponse(bool aWaitTimedOut);
|
||||
|
||||
|
|
|
@ -470,6 +470,12 @@ class IToplevelProtocol : public IProtocol {
|
|||
|
||||
bool IsOnCxxStack() const;
|
||||
|
||||
/**
|
||||
* Return true if windows messages can be handled while waiting for a reply
|
||||
* to a sync IPDL message.
|
||||
*/
|
||||
virtual bool HandleWindowsMessages(const Message& aMsg) const { return true; }
|
||||
|
||||
virtual void ProcessRemoteNativeEventsInInterruptCall() {}
|
||||
|
||||
virtual void OnChannelReceivedMessage(const Message& aMsg) {}
|
||||
|
|
|
@ -850,16 +850,106 @@ SuppressedNeuteringRegion::~SuppressedNeuteringRegion() {
|
|||
|
||||
bool SuppressedNeuteringRegion::sSuppressNeutering = false;
|
||||
|
||||
bool MessageChannel::WaitForSyncNotify() {
|
||||
#if defined(ACCESSIBILITY)
|
||||
static DWORD WaitForSingleObjectExWrapper(HANDLE aEvent, DWORD aTimeout) {
|
||||
return ::WaitForSingleObjectEx(aEvent, aTimeout, TRUE);
|
||||
}
|
||||
|
||||
static DWORD CoWaitForMultipleHandlesWrapper(HANDLE aEvent, DWORD aTimeout) {
|
||||
DWORD waitResult = 0;
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
HRESULT hr = ::CoWaitForMultipleHandles(COWAIT_ALERTABLE, aTimeout, 1,
|
||||
&aEvent, &waitResult);
|
||||
if (hr == S_OK) {
|
||||
return waitResult;
|
||||
}
|
||||
if (hr == RPC_S_CALLPENDING) {
|
||||
return WAIT_TIMEOUT;
|
||||
}
|
||||
return WAIT_FAILED;
|
||||
}
|
||||
|
||||
bool MessageChannel::WaitForSyncNotifyWithA11yReentry() {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
MonitorAutoUnlock unlock(*mMonitor);
|
||||
|
||||
static auto* sWaitForEvent = IsWin32kLockedDown()
|
||||
? WaitForSingleObjectExWrapper
|
||||
: CoWaitForMultipleHandlesWrapper;
|
||||
|
||||
const DWORD waitStart = ::GetTickCount();
|
||||
DWORD elapsed = 0;
|
||||
DWORD timeout =
|
||||
mTimeoutMs == kNoTimeout ? INFINITE : static_cast<DWORD>(mTimeoutMs);
|
||||
bool timedOut = false;
|
||||
|
||||
while (true) {
|
||||
{ // Scope for lock
|
||||
MonitorAutoLock lock(*mMonitor);
|
||||
if (!Connected()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout != static_cast<DWORD>(kNoTimeout)) {
|
||||
elapsed = ::GetTickCount() - waitStart;
|
||||
}
|
||||
|
||||
if (elapsed >= timeout) {
|
||||
timedOut = true;
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD waitResult = sWaitForEvent(mEvent, timeout - elapsed);
|
||||
|
||||
if (waitResult == WAIT_OBJECT_0) {
|
||||
// mEvent is signaled
|
||||
BOOL success = ::ResetEvent(mEvent);
|
||||
if (!success) {
|
||||
gfxDevCrash(mozilla::gfx::LogReason::MessageChannelInvalidHandle)
|
||||
<< "WindowsMessageChannel::WaitForSyncNotifyWithA11yReentry "
|
||||
"failed to reset event. GetLastError: "
|
||||
<< GetLastError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (waitResult == WAIT_IO_COMPLETION) {
|
||||
// APC fired, keep waiting
|
||||
continue;
|
||||
}
|
||||
|
||||
if (waitResult == WAIT_TIMEOUT) {
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
|
||||
NS_ERROR("WaitForSyncNotifyWithA11yReentry failed");
|
||||
break;
|
||||
}
|
||||
|
||||
return WaitResponse(timedOut);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages) {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
if (!gUIThreadId) {
|
||||
mozilla::ipc::windows::InitUIThread();
|
||||
}
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
if (mFlags & REQUIRE_A11Y_REENTRY) {
|
||||
MOZ_ASSERT(!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION));
|
||||
return WaitForSyncNotifyWithA11yReentry();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Use a blocking wait if this channel does not require
|
||||
// Windows message deferral behavior.
|
||||
if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION)) {
|
||||
if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION) ||
|
||||
!aHandleWindowsMessages) {
|
||||
TimeDuration timeout = (kNoTimeout == mTimeoutMs)
|
||||
? TimeDuration::Forever()
|
||||
: TimeDuration::FromMilliseconds(mTimeoutMs);
|
||||
|
|
|
@ -228,9 +228,15 @@ void EnsureMTA::SyncDispatchToPersistentThread(nsIRunnable* aRunnable) {
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
const BOOL alertable = XRE_IsContentProcess() && NS_IsMainThread();
|
||||
#else
|
||||
const BOOL alertable = FALSE;
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
AUTO_PROFILER_THREAD_SLEEP;
|
||||
DWORD waitResult;
|
||||
while ((waitResult = ::WaitForSingleObjectEx(event, INFINITE, FALSE)) ==
|
||||
while ((waitResult = ::WaitForSingleObjectEx(event, INFINITE, alertable)) ==
|
||||
WAIT_IO_COMPLETION) {
|
||||
}
|
||||
MOZ_ASSERT(waitResult == WAIT_OBJECT_0);
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
|
||||
#include "mozilla/mscom/ProcessRuntime.h"
|
||||
|
||||
#if defined(ACCESSIBILITY) && \
|
||||
(defined(MOZILLA_INTERNAL_API) || defined(MOZ_HAS_MOZGLUE))
|
||||
# include "mozilla/mscom/ActCtxResource.h"
|
||||
#endif // defined(ACCESSIBILITY) && (defined(MOZILLA_INTERNAL_API) ||
|
||||
// defined(MOZ_HAS_MOZGLUE))
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DynamicallyLinkedFunctionPtr.h"
|
||||
#include "mozilla/mscom/COMWrappers.h"
|
||||
|
@ -50,6 +55,23 @@ ProcessRuntime::ProcessRuntime(const GeckoProcessType aProcessType)
|
|||
|
||||
ProcessRuntime::ProcessRuntime(const ProcessCategory aProcessCategory)
|
||||
: mInitResult(CO_E_NOTINITIALIZED), mProcessCategory(aProcessCategory) {
|
||||
#if defined(ACCESSIBILITY)
|
||||
# if defined(MOZILLA_INTERNAL_API)
|
||||
// If we're inside XUL, and we're the parent process, then we trust that
|
||||
// this has already been initialized for us prior to XUL being loaded.
|
||||
// Only required in the child if the Resource ID has been passed down.
|
||||
if (aProcessCategory != ProcessCategory::GeckoBrowserParent &&
|
||||
ActCtxResource::GetAccessibilityResourceId()) {
|
||||
mActCtxRgn.emplace(ActCtxResource::GetAccessibilityResource());
|
||||
}
|
||||
# elif defined(MOZ_HAS_MOZGLUE)
|
||||
// If we're here, then we're in mozglue and initializing this for the parent
|
||||
// process.
|
||||
MOZ_ASSERT(aProcessCategory == ProcessCategory::GeckoBrowserParent);
|
||||
mActCtxRgn.emplace(ActCtxResource::GetAccessibilityResource());
|
||||
# endif
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
MOZ_DIAGNOSTIC_ASSERT(!sInstance);
|
||||
sInstance = this;
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#define mozilla_mscom_ProcessRuntime_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#if defined(ACCESSIBILITY)
|
||||
# include "mozilla/mscom/ActivationContext.h"
|
||||
# include "mozilla/Maybe.h"
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
#include "mozilla/mscom/ApartmentRegion.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
|
@ -73,6 +77,11 @@ class MOZ_NON_TEMPORARY_CLASS ProcessRuntime final {
|
|||
private:
|
||||
HRESULT mInitResult;
|
||||
const ProcessCategory mProcessCategory;
|
||||
#if defined(ACCESSIBILITY) && \
|
||||
(defined(MOZILLA_INTERNAL_API) || defined(MOZ_HAS_MOZGLUE))
|
||||
Maybe<ActivationContextRegion> mActCtxRgn;
|
||||
#endif // defined(ACCESSIBILITY) && (defined(MOZILLA_INTERNAL_API) ||
|
||||
// defined(MOZ_HAS_MOZGLUE))
|
||||
ApartmentRegion mAptRegion;
|
||||
|
||||
private:
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <utility>
|
||||
#if defined(ACCESSIBILITY)
|
||||
# include "HandlerData.h"
|
||||
# include "mozilla/a11y/Platform.h"
|
||||
# include "mozilla/mscom/ActivationContext.h"
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
#include "mozilla/mscom/ProxyStream.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
|
@ -62,13 +67,25 @@ ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf,
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
const uint32_t expectedStreamLen = GetOBJREFSize(WrapNotNull(mStream));
|
||||
nsAutoCString strActCtx;
|
||||
nsAutoString manifestPath;
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
HRESULT unmarshalResult = S_OK;
|
||||
|
||||
// We need to convert to an interface here otherwise we mess up const
|
||||
// correctness with IPDL. We'll request an IUnknown and then QI the
|
||||
// actual interface later.
|
||||
|
||||
auto marshalFn = [this, &unmarshalResult, &aIID, aEnv]() -> void {
|
||||
#if defined(ACCESSIBILITY)
|
||||
auto marshalFn = [this, &strActCtx, &manifestPath, &unmarshalResult, &aIID,
|
||||
aEnv]() -> void
|
||||
#else
|
||||
auto marshalFn = [this, &unmarshalResult, &aIID, aEnv]() -> void
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
{
|
||||
if (aEnv) {
|
||||
bool pushOk = aEnv->Push();
|
||||
MOZ_DIAGNOSTIC_ASSERT(pushOk);
|
||||
|
@ -89,6 +106,17 @@ ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf,
|
|||
MOZ_DIAGNOSTIC_ASSERT(popOk);
|
||||
});
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
auto curActCtx = ActivationContext::GetCurrent();
|
||||
if (curActCtx.isOk()) {
|
||||
strActCtx.AppendPrintf("0x%" PRIxPTR, curActCtx.unwrap());
|
||||
} else {
|
||||
strActCtx.AppendPrintf("HRESULT 0x%08lX", curActCtx.unwrapErr());
|
||||
}
|
||||
|
||||
ActivationContext::GetCurrentManifestPath(manifestPath);
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
unmarshalResult = ::CoUnmarshalInterface(mStream, aIID,
|
||||
getter_AddRefs(mUnmarshaledProxy));
|
||||
MOZ_ASSERT(SUCCEEDED(unmarshalResult));
|
||||
|
@ -114,6 +142,24 @@ ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf,
|
|||
CrashReporter::AnnotateCrashReport(kCrashReportKey,
|
||||
"!mUnmarshaledProxy"_ns);
|
||||
}
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
AnnotateClassRegistration(CLSID_AccessibleHandler);
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::UnmarshalActCtx, strActCtx);
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::UnmarshalActCtxManifestPath,
|
||||
NS_ConvertUTF16toUTF8(manifestPath));
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::A11yHandlerRegistered,
|
||||
a11y::IsHandlerRegistered() ? "true"_ns : "false"_ns);
|
||||
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::ExpectedStreamLen, expectedStreamLen);
|
||||
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::ActualStreamLen, aInitBufSize);
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,9 +281,16 @@ ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
|
|||
HRESULT statResult = S_OK;
|
||||
HRESULT getHGlobalResult = S_OK;
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
nsAutoString manifestPath;
|
||||
auto marshalFn = [&aIID, aObject, mshlFlags, &stream, &streamSize, &hglobal,
|
||||
&createStreamResult, &marshalResult, &statResult,
|
||||
&getHGlobalResult, aEnv, &manifestPath]() -> void {
|
||||
#else
|
||||
auto marshalFn = [&aIID, aObject, mshlFlags, &stream, &streamSize, &hglobal,
|
||||
&createStreamResult, &marshalResult, &statResult,
|
||||
&getHGlobalResult, aEnv]() -> void {
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
if (aEnv) {
|
||||
bool pushOk = aEnv->Push();
|
||||
MOZ_DIAGNOSTIC_ASSERT(pushOk);
|
||||
|
@ -264,6 +317,10 @@ ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
ActivationContext::GetCurrentManifestPath(manifestPath);
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
marshalResult = ::CoMarshalInterface(stream, aIID, aObject, MSHCTX_LOCAL,
|
||||
nullptr, mshlFlags);
|
||||
MOZ_ASSERT(marshalResult != E_INVALIDARG);
|
||||
|
@ -303,6 +360,11 @@ ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv,
|
|||
nsPrintfCString hrAsStr("0x%08lX", marshalResult);
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::CoMarshalInterfaceFailure, hrAsStr);
|
||||
#if defined(ACCESSIBILITY)
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::MarshalActCtxManifestPath,
|
||||
NS_ConvertUTF16toUTF8(manifestPath));
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
}
|
||||
|
||||
if (FAILED(statResult)) {
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/* 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 "ActCtxResource.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "mozilla/GetKnownFolderPath.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
#if !defined(HAVE_64BIT_BUILD)
|
||||
|
||||
static bool ReadCOMRegDefaultString(const std::wstring& aRegPath,
|
||||
std::wstring& aOutBuf) {
|
||||
aOutBuf.clear();
|
||||
|
||||
std::wstring fullyQualifiedRegPath;
|
||||
fullyQualifiedRegPath.append(L"SOFTWARE\\Classes\\");
|
||||
fullyQualifiedRegPath.append(aRegPath);
|
||||
|
||||
// Get the required size and type of the registry value.
|
||||
// We expect either REG_SZ or REG_EXPAND_SZ.
|
||||
DWORD type;
|
||||
DWORD bufLen = 0;
|
||||
LONG result =
|
||||
::RegGetValueW(HKEY_LOCAL_MACHINE, fullyQualifiedRegPath.c_str(), nullptr,
|
||||
RRF_RT_ANY, &type, nullptr, &bufLen);
|
||||
if (result != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now obtain the value
|
||||
DWORD flags = type == REG_SZ ? RRF_RT_REG_SZ : RRF_RT_REG_EXPAND_SZ;
|
||||
|
||||
aOutBuf.resize((bufLen + 1) / sizeof(char16_t));
|
||||
|
||||
result = ::RegGetValueW(HKEY_LOCAL_MACHINE, fullyQualifiedRegPath.c_str(),
|
||||
nullptr, flags, nullptr, &aOutBuf[0], &bufLen);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
aOutBuf.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Truncate terminator
|
||||
aOutBuf.resize((bufLen + 1) / sizeof(char16_t) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsSystemOleAcc(HANDLE aFile) {
|
||||
if (aFile == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION info = {};
|
||||
if (!::GetFileInformationByHandle(aFile, &info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use FOLDERID_SystemX86 so that Windows doesn't give us a redirected
|
||||
// system32 if we're a 32-bit process running on a 64-bit OS. This is
|
||||
// necessary because the values that we are reading from the registry
|
||||
// are not redirected; they reference SysWOW64 directly.
|
||||
auto systemPath = GetKnownFolderPath(FOLDERID_SystemX86);
|
||||
if (!systemPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring oleAccPath(systemPath.get());
|
||||
oleAccPath.append(L"\\oleacc.dll");
|
||||
|
||||
nsAutoHandle oleAcc(
|
||||
::CreateFileW(oleAccPath.c_str(), GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
|
||||
if (oleAcc.get() == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION oleAccInfo = {};
|
||||
if (!::GetFileInformationByHandle(oleAcc, &oleAccInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return info.dwVolumeSerialNumber == oleAccInfo.dwVolumeSerialNumber &&
|
||||
info.nFileIndexLow == oleAccInfo.nFileIndexLow &&
|
||||
info.nFileIndexHigh == oleAccInfo.nFileIndexHigh;
|
||||
}
|
||||
|
||||
static bool IsTypelibPreferred() {
|
||||
// If IAccessible's Proxy/Stub CLSID is kUniversalMarshalerClsid, then any
|
||||
// external a11y clients are expecting to use a typelib.
|
||||
const wchar_t kUniversalMarshalerClsid[] =
|
||||
L"{00020424-0000-0000-C000-000000000046}";
|
||||
|
||||
const wchar_t kIAccessiblePSClsidPath[] =
|
||||
L"Interface\\{618736E0-3C3D-11CF-810C-00AA00389B71}"
|
||||
L"\\ProxyStubClsid32";
|
||||
|
||||
std::wstring psClsid;
|
||||
if (!ReadCOMRegDefaultString(kIAccessiblePSClsidPath, psClsid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (psClsid.size() !=
|
||||
sizeof(kUniversalMarshalerClsid) / sizeof(kUniversalMarshalerClsid)[0] -
|
||||
1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
while (kUniversalMarshalerClsid[index]) {
|
||||
if (toupper(psClsid[index]) != kUniversalMarshalerClsid[index]) {
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsIAccessibleTypelibRegistered() {
|
||||
// The system default IAccessible typelib is always registered with version
|
||||
// 1.1, under the neutral locale (LCID 0).
|
||||
const wchar_t kIAccessibleTypelibRegPath[] =
|
||||
L"TypeLib\\{1EA4DBF0-3C3B-11CF-810C-00AA00389B71}\\1.1\\0\\win32";
|
||||
|
||||
std::wstring typelibPath;
|
||||
if (!ReadCOMRegDefaultString(kIAccessibleTypelibRegPath, typelibPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoHandle libTestFile(
|
||||
::CreateFileW(typelibPath.c_str(), GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
|
||||
return IsSystemOleAcc(libTestFile);
|
||||
}
|
||||
|
||||
static bool IsIAccessiblePSRegistered() {
|
||||
const wchar_t kIAccessiblePSRegPath[] =
|
||||
L"CLSID\\{03022430-ABC4-11D0-BDE2-00AA001A1953}\\InProcServer32";
|
||||
|
||||
std::wstring proxyStubPath;
|
||||
if (!ReadCOMRegDefaultString(kIAccessiblePSRegPath, proxyStubPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoHandle libTestFile(
|
||||
::CreateFileW(proxyStubPath.c_str(), GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
|
||||
return IsSystemOleAcc(libTestFile);
|
||||
}
|
||||
|
||||
static bool UseIAccessibleProxyStub() {
|
||||
// If a typelib is preferred then external clients are expecting to use
|
||||
// typelib marshaling, so we should use that whenever available.
|
||||
if (IsTypelibPreferred() && IsIAccessibleTypelibRegistered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise we try the proxy/stub
|
||||
if (IsIAccessiblePSRegistered()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // !defined(HAVE_64BIT_BUILD)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
#endif
|
||||
|
||||
static HMODULE GetContainingModuleHandle() {
|
||||
HMODULE thisModule = nullptr;
|
||||
#if defined(_MSC_VER)
|
||||
thisModule = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
#else
|
||||
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
reinterpret_cast<LPCWSTR>(&GetContainingModuleHandle),
|
||||
&thisModule)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return thisModule;
|
||||
}
|
||||
|
||||
static uint16_t sActCtxResourceId = 0;
|
||||
|
||||
/* static */
|
||||
void ActCtxResource::SetAccessibilityResourceId(uint16_t aResourceId) {
|
||||
sActCtxResourceId = aResourceId;
|
||||
}
|
||||
|
||||
/* static */
|
||||
uint16_t ActCtxResource::GetAccessibilityResourceId() {
|
||||
return sActCtxResourceId;
|
||||
}
|
||||
|
||||
static void EnsureAccessibilityResourceId() {
|
||||
if (!sActCtxResourceId) {
|
||||
#if defined(HAVE_64BIT_BUILD)
|
||||
// The manifest for 64-bit Windows is embedded with resource ID 64.
|
||||
sActCtxResourceId = 64;
|
||||
#else
|
||||
// The manifest for 32-bit Windows is embedded with resource ID 32.
|
||||
// Beginning with Windows 10 Creators Update, 32-bit builds always use the
|
||||
// 64-bit manifest. Older builds of Windows may or may not require the
|
||||
// 64-bit manifest: UseIAccessibleProxyStub() determines the course of
|
||||
// action.
|
||||
if (mozilla::IsWin10CreatorsUpdateOrLater() || UseIAccessibleProxyStub()) {
|
||||
sActCtxResourceId = 64;
|
||||
} else {
|
||||
sActCtxResourceId = 32;
|
||||
}
|
||||
#endif // defined(HAVE_64BIT_BUILD)
|
||||
}
|
||||
}
|
||||
|
||||
ActCtxResource ActCtxResource::GetAccessibilityResource() {
|
||||
ActCtxResource result = {};
|
||||
result.mModule = GetContainingModuleHandle();
|
||||
EnsureAccessibilityResourceId();
|
||||
result.mId = GetAccessibilityResourceId();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
|
@ -15,6 +15,23 @@ namespace mscom {
|
|||
struct ActCtxResource {
|
||||
uint16_t mId;
|
||||
HMODULE mModule;
|
||||
|
||||
/**
|
||||
* Set the resource ID used by GetAccessibilityResource. This is so that
|
||||
* sandboxed child processes can use a value passed down from the parent.
|
||||
*/
|
||||
static MFBT_API void SetAccessibilityResourceId(uint16_t aResourceId);
|
||||
|
||||
/**
|
||||
* Get the resource ID used by GetAccessibilityResource.
|
||||
*/
|
||||
static MFBT_API uint16_t GetAccessibilityResourceId();
|
||||
|
||||
/**
|
||||
* @return ActCtxResource of a11y manifest resource to be passed to
|
||||
* mscom::ActivationContext
|
||||
*/
|
||||
static MFBT_API ActCtxResource GetAccessibilityResource();
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
|
|
|
@ -12,5 +12,6 @@ EXPORTS.mozilla.mscom += [
|
|||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"ActCtxResource.cpp",
|
||||
"ProcessRuntimeShared.cpp",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="Mozilla.Firefox.mozglue" version="1.0.0.0" />
|
||||
<file name="mozglue.dll" />
|
||||
<comInterfaceExternalProxyStub
|
||||
iid="{618736E0-3C3D-11CF-810C-00AA00389B71}"
|
||||
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
|
||||
name="IAccessible"
|
||||
tlbid="{1EA4DBF0-3C3B-11CF-810C-00AA00389B71}"
|
||||
/>
|
||||
</assembly>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="Mozilla.Firefox.mozglue" version="1.0.0.0" />
|
||||
<file name="mozglue.dll" />
|
||||
<comInterfaceExternalProxyStub
|
||||
iid="{618736E0-3C3D-11CF-810C-00AA00389B71}"
|
||||
proxyStubClsid32="{03022430-ABC4-11D0-BDE2-00AA001A1953}"
|
||||
name="IAccessible"
|
||||
/>
|
||||
</assembly>
|
|
@ -104,6 +104,18 @@ USE_LIBS += [
|
|||
"mfbt",
|
||||
]
|
||||
|
||||
if CONFIG["OS_ARCH"] == "WINNT":
|
||||
RCINCLUDE = "/mozglue/mozglue.rc"
|
||||
|
||||
if not CONFIG["HAVE_64BIT_BUILD"]:
|
||||
EXPORTS += [
|
||||
"IAccessible32.manifest",
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
"IAccessible64.manifest",
|
||||
]
|
||||
|
||||
LIBRARY_DEFINES["IMPL_MFBT"] = True
|
||||
LIBRARY_DEFINES["MOZ_HAS_MOZGLUE"] = True
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include "mozilla-config.h"
|
||||
#ifdef ACCESSIBILITY
|
||||
64 24 IAccessible64.manifest
|
||||
#ifndef HAVE_64BIT_BUILD
|
||||
32 24 IAccessible32.manifest
|
||||
#endif
|
||||
#endif
|
|
@ -1343,6 +1343,21 @@ if test -n "$MOZ_DEV_EDITION"; then
|
|||
AC_DEFINE(MOZ_DEV_EDITION)
|
||||
fi
|
||||
|
||||
dnl Windows AccessibilityHandler
|
||||
dnl ========================================================
|
||||
|
||||
if test -z "$MOZ_HANDLER_CLSID"; then
|
||||
MOZ_HANDLER_CLSID="4a195748-dca2-45fb-9295-0a139e76a9e7"
|
||||
MOZ_IHANDLERCONTROL_IID="3316ce35-f892-4832-97c5-06c52c03cdba"
|
||||
MOZ_ASYNCIHANDLERCONTROL_IID="15b48b76-ad38-4ad3-bd1a-d3c48a5a9947"
|
||||
MOZ_IGECKOBACKCHANNEL_IID="dd2e4a89-999e-4d65-8b65-440c923ddb61"
|
||||
fi
|
||||
|
||||
AC_SUBST(MOZ_HANDLER_CLSID)
|
||||
AC_SUBST(MOZ_IHANDLERCONTROL_IID)
|
||||
AC_SUBST(MOZ_ASYNCIHANDLERCONTROL_IID)
|
||||
AC_SUBST(MOZ_IGECKOBACKCHANNEL_IID)
|
||||
|
||||
dnl Spit out some output
|
||||
dnl ========================================================
|
||||
|
||||
|
|
|
@ -486,6 +486,34 @@ def repackage_msix(
|
|||
if locale.partition("#")[0].strip()
|
||||
)
|
||||
|
||||
# We don't have a build at repackage-time to give us these values, and the
|
||||
# source of truth is a branding-specific `configure.sh` shell script that we
|
||||
# can't easily evaluate completely here. Instead, we choose a value from
|
||||
# `configure.sh` depending on the channel.
|
||||
brandingUuids = {}
|
||||
lines = open(mozpath.join(branding, "configure.sh")).readlines()
|
||||
# For official (release) and unofficial channels, we want the second UUID in
|
||||
# configure.sh. For official, this is because the first set of UUIDs are for
|
||||
# beta, but we want release. For unofficial, the first set of UUIDs are for
|
||||
# debug builds; we assume non-debug here.
|
||||
if channel in ("official", "unofficial"):
|
||||
# To get the last UUID, we reverse the lines.
|
||||
lines.reverse()
|
||||
for key in (
|
||||
"MOZ_IGECKOBACKCHANNEL_IID",
|
||||
"MOZ_IHANDLERCONTROL_IID",
|
||||
"MOZ_ASYNCIHANDLERCONTROL_IID",
|
||||
):
|
||||
for line in lines:
|
||||
if key not in line:
|
||||
continue
|
||||
_, _, uuid = line.partition("=")
|
||||
uuid = uuid.strip()
|
||||
if uuid.startswith(('"', "'")):
|
||||
uuid = uuid[1:-1]
|
||||
brandingUuids[key] = uuid
|
||||
break
|
||||
|
||||
# The convention is $MOZBUILD_STATE_PATH/cache/$FEATURE.
|
||||
output_dir = mozpath.normsep(
|
||||
mozpath.join(
|
||||
|
@ -688,6 +716,7 @@ def repackage_msix(
|
|||
# Keep synchronized with `toolkit\mozapps\notificationserver\NotificationComServer.cpp`.
|
||||
"MOZ_INOTIFICATIONACTIVATION_CLSID": "916f9b5d-b5b2-4d36-b047-03c7a52f81c8",
|
||||
}
|
||||
defines.update(brandingUuids)
|
||||
|
||||
m.add_preprocess(
|
||||
mozpath.join(template, "AppxManifest.xml.in"),
|
||||
|
|
|
@ -1132,6 +1132,11 @@ var snapshotFormatters = {
|
|||
$("a11y-activated").textContent = data.isActive;
|
||||
$("a11y-force-disabled").textContent = data.forceDisabled || 0;
|
||||
|
||||
let a11yHandlerUsed = $("a11y-handler-used");
|
||||
if (a11yHandlerUsed) {
|
||||
a11yHandlerUsed.textContent = data.handlerUsed;
|
||||
}
|
||||
|
||||
let a11yInstantiator = $("a11y-instantiator");
|
||||
if (a11yInstantiator) {
|
||||
a11yInstantiator.textContent = data.instantiator;
|
||||
|
|
|
@ -691,6 +691,13 @@
|
|||
</td>
|
||||
</tr>
|
||||
#if defined(XP_WIN)
|
||||
<tr>
|
||||
<th class="column" data-l10n-id="a11y-handler-used"/>
|
||||
|
||||
<td id="a11y-handler-used">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th class="column" data-l10n-id="a11y-instantiator"/>
|
||||
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
# - ping: A boolean that indicates whether the annotation is allowlisted for
|
||||
# going into the crash ping, if not specified this defaults to false
|
||||
|
||||
A11yHandlerRegistered:
|
||||
description: >
|
||||
Set to "true" if the accessibility handler is registered, "false" otherwise.
|
||||
type: string
|
||||
|
||||
AbortMessage:
|
||||
description: >
|
||||
Message passed to NS_DebugBreak().
|
||||
|
@ -32,6 +37,11 @@ AccessibilityInProcClient:
|
|||
accessible/windows/msaa/Compatibility.h for the mappings.
|
||||
type: string
|
||||
|
||||
ActualStreamLen:
|
||||
description: >
|
||||
Actual length of an IPC proxy stream.
|
||||
type: integer
|
||||
|
||||
AdapterDeviceID:
|
||||
description: >
|
||||
Graphics adapter name.
|
||||
|
@ -292,6 +302,11 @@ EventLoopNestingLevel:
|
|||
type: integer
|
||||
ping: true
|
||||
|
||||
ExpectedStreamLen:
|
||||
description: >
|
||||
Expected length of an IPC proxy stream.
|
||||
type: integer
|
||||
|
||||
ExperimentalFeatures:
|
||||
description: >
|
||||
Comma-separated list of enabled experimental features from about:preferences#experimental.
|
||||
|
@ -648,6 +663,11 @@ MainThreadRunnableName:
|
|||
type: string
|
||||
ping: true
|
||||
|
||||
MarshalActCtxManifestPath:
|
||||
description: >
|
||||
Proxy stream marshalling current activation context manifest path.
|
||||
type: string
|
||||
|
||||
MozCrashReason:
|
||||
description: >
|
||||
Plaintext description of why Firefox crashed, this is usually set by
|
||||
|
@ -948,6 +968,16 @@ UnknownNetAddrSocketFamily:
|
|||
requested family number.
|
||||
type: integer
|
||||
|
||||
UnmarshalActCtx:
|
||||
description: >
|
||||
Proxy stream unmarshalling current activation context.
|
||||
type: string
|
||||
|
||||
UnmarshalActCtxManifestPath:
|
||||
description: >
|
||||
Proxy stream unmarshalling current activation context manifest path.
|
||||
type: string
|
||||
|
||||
UptimeTS:
|
||||
description: >
|
||||
Uptime in seconds. This annotation uses a string instead of an integer
|
||||
|
|
|
@ -4,3 +4,6 @@
|
|||
|
||||
#include "mozilla-config.h"
|
||||
#include "widget.rc"
|
||||
#ifdef ACCESSIBILITY
|
||||
1 typelib IGeckoCustom.tlb
|
||||
#endif
|
||||
|
|
|
@ -892,6 +892,7 @@ var dataProviders = {
|
|||
"accessibility.force_disabled"
|
||||
);
|
||||
} catch (e) {}
|
||||
data.handlerUsed = Services.appinfo.accessibleHandlerUsed;
|
||||
data.instantiator = Services.appinfo.accessibilityInstantiator;
|
||||
done(data);
|
||||
},
|
||||
|
|
|
@ -134,6 +134,10 @@ static CommandLineArg<bool> sNotForBrowser{"-notForBrowser", "notforbrowser"};
|
|||
static CommandLineArg<bool> sWin32kLockedDown{"-win32kLockedDown",
|
||||
"win32klockeddown"};
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
# if defined(ACCESSIBILITY)
|
||||
static CommandLineArg<uint64_t> sA11yResourceId{"-a11yResourceId",
|
||||
"a11yresourceid"};
|
||||
# endif // defined(ACCESSIBILITY)
|
||||
static CommandLineArg<bool> sDisableDynamicDllBlocklist{
|
||||
"-disableDynamicBlocklist", "disabledynamicblocklist"};
|
||||
#endif // defined(XP_WIN)
|
||||
|
|
|
@ -1463,6 +1463,17 @@ nsXULAppInfo::GetAccessibilityEnabled(bool* aResult) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULAppInfo::GetAccessibleHandlerUsed(bool* aResult) {
|
||||
#if defined(ACCESSIBILITY) && defined(XP_WIN)
|
||||
*aResult = Preferences::GetBool("accessibility.handler.enabled", false) &&
|
||||
a11y::IsHandlerRegistered();
|
||||
#else
|
||||
*aResult = false;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULAppInfo::GetAccessibilityInstantiator(nsAString& aInstantiator) {
|
||||
#if defined(ACCESSIBILITY) && defined(XP_WIN)
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
# include "mozilla/WinDllServices.h"
|
||||
# include "mozilla/WindowsBCryptInitialization.h"
|
||||
# include "WinUtils.h"
|
||||
# ifdef ACCESSIBILITY
|
||||
# include "mozilla/GeckoArgs.h"
|
||||
# include "mozilla/mscom/ActCtxResource.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "nsAppRunner.h"
|
||||
|
@ -558,6 +562,16 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
|
|||
// Associate this thread with a UI MessageLoop
|
||||
MessageLoop uiMessageLoop(uiLoopType);
|
||||
{
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
// The accessibility resource ID is passed down on the command line
|
||||
// because its retrieval causes issues with the sandbox. When it is set,
|
||||
// it is required for ProcessRuntime construction within ProcessChild.
|
||||
auto a11yResourceId = geckoargs::sA11yResourceId.Get(aArgc, aArgv);
|
||||
if (a11yResourceId.isSome()) {
|
||||
mscom::ActCtxResource::SetAccessibilityResourceId(*a11yResourceId);
|
||||
}
|
||||
#endif
|
||||
|
||||
UniquePtr<ProcessChild> process;
|
||||
switch (XRE_GetProcessType()) {
|
||||
case GeckoProcessType_Default:
|
||||
|
|
|
@ -267,6 +267,11 @@ interface nsIXULRuntime : nsISupports
|
|||
*/
|
||||
readonly attribute boolean accessibilityEnabled;
|
||||
|
||||
/**
|
||||
* If true, the AccessibleHandler dll is used.
|
||||
*/
|
||||
readonly attribute boolean accessibleHandlerUsed;
|
||||
|
||||
/**
|
||||
* Executable of Windows service that activated accessibility.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче