Bug 1419362 part 3: Accessible HandlerProvider: Implement a method to retrieve all text, hyperlinks and attributes at once. r?MarcoZ, r?aklotz
This allows the handler to fetch all text information in a single cross-process call when appropriate.
Normally, it would be a minimum of 3 calls, plus one call for each additional attribute run.
MozReview-Commit-ID: K5x9bAWiWWJ
--- a/accessible/ipc/win/HandlerProvider.cpp
+++ b/accessible/ipc/win/HandlerProvider.cpp
@@ -17,21 +17,23 @@
#include "HandlerData_i.c"
#include "mozilla/Assertions.h"
#include "mozilla/a11y/AccessibleWrap.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Move.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 "nsThreadUtils.h"
+#include "nsTArray.h"
#include <memory.h>
namespace mozilla {
namespace a11y {
HandlerProvider::HandlerProvider(REFIID aIid,
mscom::InterceptorTargetPtr<IUnknown> aTarget)
@@ -562,11 +564,123 @@ HandlerProvider::Refresh(DynamicIA2Data*
this, &HandlerProvider::BuildDynamicIA2Data,
aOutData)) {
return E_FAIL;
}
return S_OK;
}
+template<typename Interface>
+HRESULT
+HandlerProvider::ToWrappedObject(Interface** aObj)
+{
+ mscom::STAUniquePtr<Interface> inObj(*aObj);
+ RefPtr<HandlerProvider> hprov = new HandlerProvider(__uuidof(Interface),
+ mscom::ToInterceptorTargetPtr(inObj));
+ HRESULT hr = mscom::MainThreadHandoff::WrapInterface(Move(inObj), hprov,
+ aObj);
+ if (FAILED(hr)) {
+ *aObj = nullptr;
+ }
+ 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());
+ MOZ_ASSERT(mTargetUnk);
+
+ 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 start;
+ BSTR attribs;
+ // The (exclusive) end of the last run is the start of the next run.
+ hr = ht->get_attributes(end, &start, &end, &attribs);
+ if (FAILED(hr)) {
+ 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());
+
+ HRESULT hr;
+ if (!mscom::InvokeOnMainThread("HandlerProvider::GetAllTextInfoMainThread",
+ this,
+ &HandlerProvider::GetAllTextInfoMainThread,
+ aText, aHyperlinks, aNHyperlinks,
+ aAttribRuns, aNAttribRuns, &hr)) {
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
} // namespace a11y
} // namespace mozilla
--- a/accessible/ipc/win/HandlerProvider.h
+++ b/accessible/ipc/win/HandlerProvider.h
@@ -50,16 +50,21 @@ public:
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;
private:
~HandlerProvider() = default;
void SetHandlerControlOnMainThread(DWORD aPid,
mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
void GetAndSerializePayload(const MutexAutoLock&,
NotNull<mscom::IInterceptor*> aInterceptor);
@@ -67,16 +72,28 @@ private:
StaticIA2Data* aOutData);
void BuildDynamicIA2Data(DynamicIA2Data* aOutIA2Data);
void BuildInitialIA2Data(NotNull<mscom::IInterceptor*> aInterceptor,
StaticIA2Data* aOutStaticData,
DynamicIA2Data* aOutDynamicData);
static void CleanupStaticIA2Data(StaticIA2Data& aData);
static void CleanupDynamicIA2Data(DynamicIA2Data& aData);
bool IsTargetInterfaceCacheable();
+ // 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);
Atomic<uint32_t> mRefCnt;
Mutex mMutex; // Protects mSerializer
const IID mTargetUnkIid;
mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only
UniquePtr<mscom::StructToStream> mSerializer;
RefPtr<IUnknown> mFastMarshalUnk;
};
--- a/accessible/ipc/win/handler/HandlerData.idl
+++ b/accessible/ipc/win/handler/HandlerData.idl
@@ -147,16 +147,21 @@ interface IHandlerControl : IUnknown
[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);
}
[uuid(1e545f07-f108-4912-9471-546827a80983)]
library AccessibleHandlerTypeLib
{
/**
* This definition is required in order for the handler implementation to
* support IDispatch (aka Automation). This is used by interpreted language