From 0ee7073299a024a93d5ec794bb9abc72c28e3a59 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 13 Apr 2017 20:35:32 -0600 Subject: [PATCH] Bug 1322532: Platform a11y changes to enable handler-based live regions; r=tbsaunde MozReview-Commit-ID: nNPvBy3ZGO --HG-- extra : rebase_source : d8a797c9ddfb3d8ab4f13c9f2f261fba04320beb extra : histedit_source : cc4f0bd8ba26cc88bcf9907f684e5d6c240d354f --- accessible/ipc/DocAccessibleParent.cpp | 15 ++++++ accessible/ipc/DocAccessibleParent.h | 7 +++ accessible/ipc/win/DocAccessibleChild.cpp | 7 +++ accessible/windows/msaa/AccessibleWrap.cpp | 58 ++++++++++++++++++++++ accessible/windows/msaa/AccessibleWrap.h | 2 + accessible/windows/msaa/Platform.cpp | 8 +++ 6 files changed, 97 insertions(+) diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index 61204940e383..2746fe204fdd 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -338,6 +338,21 @@ DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID, return IPC_OK(); } +#if defined(XP_WIN) + +mozilla::ipc::IPCResult +DocAccessibleParent::RecvSyncTextChangeEvent(const uint64_t& aID, + const nsString& aStr, + const int32_t& aStart, + const uint32_t& aLen, + const bool& aIsInsert, + const bool& aFromUser) +{ + return RecvTextChangeEvent(aID, aStr, aStart, aLen, aIsInsert, aFromUser); +} + +#endif // defined(XP_WIN) + mozilla::ipc::IPCResult DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index e866891f79e0..67b455cd8ea3 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -88,6 +88,13 @@ public: const bool& aIsInsert, const bool& aFromUser) override; +#if defined(XP_WIN) + virtual mozilla::ipc::IPCResult RecvSyncTextChangeEvent(const uint64_t& aID, const nsString& aStr, + const int32_t& aStart, const uint32_t& aLen, + const bool& aIsInsert, + const bool& aFromUser) override; +#endif // defined(XP_WIN) + virtual mozilla::ipc::IPCResult RecvSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, const uint32_t& aType) override; diff --git a/accessible/ipc/win/DocAccessibleChild.cpp b/accessible/ipc/win/DocAccessibleChild.cpp index e932036acb67..9165f3ca9b92 100644 --- a/accessible/ipc/win/DocAccessibleChild.cpp +++ b/accessible/ipc/win/DocAccessibleChild.cpp @@ -190,6 +190,13 @@ DocAccessibleChild::SendTextChangeEvent(const uint64_t& aID, const bool& aFromUser) { if (IsConstructedInParentProcess()) { + if (aStr.Contains(L'\xfffc')) { + // The AT is going to need to reenter content while the event is being + // dispatched synchronously. + return PDocAccessibleChild::SendSyncTextChangeEvent(aID, aStr, aStart, + aLen, aIsInsert, + aFromUser); + } return PDocAccessibleChild::SendTextChangeEvent(aID, aStr, aStart, aLen, aIsInsert, aFromUser); } diff --git a/accessible/windows/msaa/AccessibleWrap.cpp b/accessible/windows/msaa/AccessibleWrap.cpp index e31f1f4ca189..fc329cbf7347 100644 --- a/accessible/windows/msaa/AccessibleWrap.cpp +++ b/accessible/windows/msaa/AccessibleWrap.cpp @@ -43,6 +43,7 @@ #include "nsArrayUtils.h" #include "mozilla/Preferences.h" #include "nsIXULRuntime.h" +#include "mozilla/mscom/AsyncInvoker.h" #include "oleacc.h" @@ -1627,3 +1628,60 @@ AccessibleWrap::SetHandlerControl(DWORD aPid, RefPtr aCtrl) sHandlerControllers->AppendElement(Move(ctrlData)); } + +bool +AccessibleWrap::DispatchTextChangeToHandler(bool aIsInsert, + const nsString& aText, + int32_t aStart, uint32_t aLen) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + if (!sHandlerControllers || sHandlerControllers->IsEmpty()) { + return false; + } + + HWND hwnd = GetHWNDFor(this); + MOZ_ASSERT(hwnd); + if (!hwnd) { + return false; + } + + long msaaId = GetChildIDFor(this); + + DWORD ourPid = ::GetCurrentProcessId(); + + // The handler ends up calling NotifyWinEvent, which should only be done once + // since it broadcasts the same event to every process who is subscribed. + // OTOH, if our chrome process contains a handler, we should prefer to + // broadcast the event from that process, as we want any DLLs injected by ATs + // to receive the event synchronously. Otherwise we simply choose the first + // handler in the list, for the lack of a better heuristic. + + nsTArray::index_type ctrlIndex = + sHandlerControllers->IndexOf(ourPid); + + if (ctrlIndex == nsTArray::NoIndex) { + ctrlIndex = 0; + } + + HandlerControllerData& controller = sHandlerControllers->ElementAt(ctrlIndex); + MOZ_ASSERT(controller.mPid); + MOZ_ASSERT(controller.mCtrl); + + VARIANT_BOOL isInsert = aIsInsert ? VARIANT_TRUE : VARIANT_FALSE; + + IA2TextSegment textSegment{::SysAllocStringLen(aText.get(), aText.Length()), + aStart, static_cast(aLen)}; + + ASYNC_INVOKER_FOR(IHandlerControl) invoker(controller.mCtrl, + Some(controller.mIsProxy)); + + HRESULT hr = ASYNC_INVOKE(invoker, OnTextChange, PtrToLong(hwnd), msaaId, + isInsert, &textSegment); + + ::SysFreeString(textSegment.text); + + return SUCCEEDED(hr); +} + diff --git a/accessible/windows/msaa/AccessibleWrap.h b/accessible/windows/msaa/AccessibleWrap.h index 5830ec9ff240..602a074cc7cb 100644 --- a/accessible/windows/msaa/AccessibleWrap.h +++ b/accessible/windows/msaa/AccessibleWrap.h @@ -192,6 +192,8 @@ public: // construction, destruction static void SetHandlerControl(DWORD aPid, RefPtr aCtrl); + bool DispatchTextChangeToHandler(bool aIsInsert, const nsString& aText, + int32_t aStart, uint32_t aLen); protected: virtual ~AccessibleWrap(); diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp index 0d4fc394e59e..63f6111c1f3f 100644 --- a/accessible/windows/msaa/Platform.cpp +++ b/accessible/windows/msaa/Platform.cpp @@ -132,6 +132,14 @@ a11y::ProxyTextChangeEvent(ProxyAccessible* aText, const nsString& aStr, return; } + static const bool useHandler = + Preferences::GetBool("accessibility.handler.enabled", false); + + if (useHandler) { + wrapper->DispatchTextChangeToHandler(aInsert, aStr, aStart, aLen); + return; + } + auto text = static_cast(wrapper->AsHyperText()); if (text) { ia2AccessibleText::UpdateTextChangeData(text, aInsert, aStr, aStart, aLen);