Bug 1963625: Fix some cases where UIA is enabled or disabled at runtime. r=eeejay
When a UIA client first queries us, the accessibility engine hasn't yet been initialised. Previously, this also meant that we hadn't yet called InitConsumers() to figure out which Windows clients were present. This in turn meant that we would initially believe UIA should be enabled, even if we later realised NVDA/a Vispero product was present and then believed it should be disabled. To fix this, call InitConsumers() appropriately if it hasn't been called yet. Even with the above fix, the following scenario might still be possible: 1. UIA is enabled. 2. A client QueryInterfaces to IRawElementProviderSimple. 3. UIA gets disabled. 4. Only then does the client try to call a method on IRawElementProviderSimple. In this scenario, LazyInstantiator::MaybeResolveRoot won't set mWeakUia, but the IRawElementProviderSimple method will try to use mWeakUia, causing a crash. To fix this, add a new RESOLVE_ROOT_UIA macro used by IRawElementProviderSimple methods. In addition to calling RESOLVE_ROOT, this also checks mWeakUia and fails gracefully if that is null. Differential Revision: https://phabricator.services.mozilla.com/D247504
This commit is contained in:
committed by
jteh@mozilla.com
parent
a1d64e2d7c
commit
f2254a1d58
@@ -228,6 +228,12 @@ bool Compatibility::IsUiaEnabled() {
|
||||
}
|
||||
// Bug 1956415: Some screen readers break when native UIA is enabled, so don't
|
||||
// enable it when they're detected.
|
||||
// Call InitConsumers() if we haven't already. It's safe to call this multiple
|
||||
// times, but it still does a small amount of work and we can easily avoid
|
||||
// unnecessary calls here.
|
||||
if (!(sConsumers & UIAUTOMATION)) {
|
||||
InitConsumers();
|
||||
}
|
||||
return !IsJAWS() && !IsOldJAWS() && !IsVisperoShared() &&
|
||||
!(sConsumers & NVDA);
|
||||
}
|
||||
|
||||
@@ -410,6 +410,15 @@ LazyInstantiator::MaybeResolveRoot() {
|
||||
} \
|
||||
}
|
||||
|
||||
#define RESOLVE_ROOT_UIA_RETURN_IF_FAIL \
|
||||
RESOLVE_ROOT \
|
||||
if (!mWeakUia) { \
|
||||
/* UIA was previously enabled, allowing QueryInterface to a UIA interface. \
|
||||
* It was subsequently disabled before we could resolve the root. \
|
||||
*/ \
|
||||
return E_FAIL; \
|
||||
}
|
||||
|
||||
IMPL_IUNKNOWN_QUERY_HEAD(LazyInstantiator)
|
||||
if (NS_WARN_IF(!NS_IsMainThread())) {
|
||||
// Bug 1814780, bug 1949617: The COM marshaler sometimes calls QueryInterface
|
||||
@@ -797,8 +806,9 @@ STDMETHODIMP
|
||||
LazyInstantiator::get_ProviderOptions(
|
||||
__RPC__out enum ProviderOptions* aOptions) {
|
||||
// This method is called before a UIA connection is fully established and thus
|
||||
// before we can detect the client. We must not call RESOLVE_ROOT here because
|
||||
// this might turn out to be a client we want to block.
|
||||
// before we can detect the client. We must not call
|
||||
// RESOLVE_ROOT_UIA_RETURN_IF_FAIL here because this might turn out to be a
|
||||
// client we want to block.
|
||||
if (!aOptions) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
@@ -809,14 +819,14 @@ LazyInstantiator::get_ProviderOptions(
|
||||
STDMETHODIMP
|
||||
LazyInstantiator::GetPatternProvider(
|
||||
PATTERNID aPatternId, __RPC__deref_out_opt IUnknown** aPatternProvider) {
|
||||
RESOLVE_ROOT;
|
||||
RESOLVE_ROOT_UIA_RETURN_IF_FAIL;
|
||||
return mWeakUia->GetPatternProvider(aPatternId, aPatternProvider);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
LazyInstantiator::GetPropertyValue(PROPERTYID aPropertyId,
|
||||
__RPC__out VARIANT* aPropertyValue) {
|
||||
RESOLVE_ROOT;
|
||||
RESOLVE_ROOT_UIA_RETURN_IF_FAIL;
|
||||
return mWeakUia->GetPropertyValue(aPropertyId, aPropertyValue);
|
||||
}
|
||||
|
||||
@@ -824,8 +834,9 @@ STDMETHODIMP
|
||||
LazyInstantiator::get_HostRawElementProvider(
|
||||
__RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider) {
|
||||
// This method is called before a UIA connection is fully established and thus
|
||||
// before we can detect the client. We must not call RESOLVE_ROOT here because
|
||||
// this might turn out to be a client we want to block.
|
||||
// before we can detect the client. We must not call
|
||||
// RESOLVE_ROOT_UIA_RETURN_IF_FAIL here because this might turn out to be a
|
||||
// client we want to block.
|
||||
if (!aRawElmProvider) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user