зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1416986 part 2: Include interfaces the client is likely to request in the accessible handler payload. r=aklotz
Now that virtual buffers have to render across processes, we want to eliminate as many cross-process calls as possible. This includes QueryInterface calls, since buffers query for several interfaces on every node they visit. To avoid these cross-process QI calls, we include interfaces clients are likely to request in the handler payload. This way, they get marshaled in the single call used to retrieve the object. This patch does the following: 1. Passes the interceptor when building the payload. We need this so we can get interceptors for other interfaces. 2. Splits the payload into two main parts: a static part and a dynamic part. The (new) static part contains the interface pointers. The dynamic part contains the rest. This is necessary because the refresh call cannot pass the interceptor, but the interceptor is needed to build the static part. Also, re-building the static part is pointless when refreshing. 3. Includes the interface pointers in the payload (BuildStaticIA2Data). The pointers also have to be cleaned up after marshaling. 4. Releases the interface pointers in the handler after the payload is received. We do this because they're aggregated by the proxy manager as they're unmarshaled. MozReview-Commit-ID: 6VRLMNScgwW --HG-- extra : rebase_source : 249589643b7a69e870962ea55a44849bf03a2693
This commit is contained in:
Родитель
980e6321f7
Коммит
aebc388fb6
|
@ -21,6 +21,7 @@
|
|||
#include "mozilla/Move.h"
|
||||
#include "mozilla/mscom/AgileReference.h"
|
||||
#include "mozilla/mscom/FastMarshaler.h"
|
||||
#include "mozilla/mscom/Interceptor.h"
|
||||
#include "mozilla/mscom/MainThreadInvoker.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/StructStream.h"
|
||||
|
@ -97,7 +98,8 @@ HandlerProvider::GetHandler(NotNull<CLSID*> aHandlerClsid)
|
|||
}
|
||||
|
||||
void
|
||||
HandlerProvider::GetAndSerializePayload(const MutexAutoLock&)
|
||||
HandlerProvider::GetAndSerializePayload(const MutexAutoLock&,
|
||||
NotNull<mscom::IInterceptor*> aInterceptor)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
|
@ -107,10 +109,11 @@ HandlerProvider::GetAndSerializePayload(const MutexAutoLock&)
|
|||
|
||||
IA2Payload payload{};
|
||||
|
||||
if (!mscom::InvokeOnMainThread("HandlerProvider::BuildIA2Data",
|
||||
this, &HandlerProvider::BuildIA2Data,
|
||||
&payload.mData) ||
|
||||
!payload.mData.mUniqueId) {
|
||||
if (!mscom::InvokeOnMainThread("HandlerProvider::BuildInitialIA2Data",
|
||||
this, &HandlerProvider::BuildInitialIA2Data,
|
||||
aInterceptor,
|
||||
&payload.mStaticData, &payload.mDynamicData) ||
|
||||
!payload.mDynamicData.mUniqueId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -124,9 +127,10 @@ HandlerProvider::GetAndSerializePayload(const MutexAutoLock&)
|
|||
|
||||
mSerializer = MakeUnique<mscom::StructToStream>(payload, &IA2Payload_Encode);
|
||||
|
||||
// Now that we have serialized payload, we should free any BSTRs that were
|
||||
// allocated in BuildIA2Data.
|
||||
ClearIA2Data(payload.mData);
|
||||
// Now that we have serialized payload, we should clean up any
|
||||
// BSTRs, interfaces, etc. fetched in BuildInitialIA2Data.
|
||||
CleanupStaticIA2Data(payload.mStaticData);
|
||||
CleanupDynamicIA2Data(payload.mDynamicData);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
@ -142,7 +146,7 @@ HandlerProvider::GetHandlerPayloadSize(NotNull<mscom::IInterceptor*> aIntercepto
|
|||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
GetAndSerializePayload(lock);
|
||||
GetAndSerializePayload(lock, aInterceptor);
|
||||
|
||||
if (!mSerializer || !(*mSerializer)) {
|
||||
// Failed payload serialization is non-fatal
|
||||
|
@ -182,7 +186,72 @@ private:
|
|||
};
|
||||
|
||||
void
|
||||
HandlerProvider::BuildIA2Data(IA2Data* aOutIA2Data)
|
||||
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 CleanupStaticIA2Data!
|
||||
|
||||
// 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_IEnumVARIANT,
|
||||
(void**)&aOutData->mIEnumVARIANT);
|
||||
if (FAILED(hr)) {
|
||||
aOutData->mIEnumVARIANT = nullptr;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MOZ_ASSERT(aOutIA2Data);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -203,7 +272,7 @@ HandlerProvider::BuildIA2Data(IA2Data* aOutIA2Data)
|
|||
};
|
||||
|
||||
auto cleanup = [this, aOutIA2Data]() -> void {
|
||||
ClearIA2Data(*aOutIA2Data);
|
||||
CleanupDynamicIA2Data(*aOutIA2Data);
|
||||
};
|
||||
|
||||
ExecuteWhen<decltype(hasFailed), decltype(cleanup)> onFail(hasFailed, cleanup);
|
||||
|
@ -291,10 +360,57 @@ HandlerProvider::BuildIA2Data(IA2Data* aOutIA2Data)
|
|||
}
|
||||
|
||||
void
|
||||
HandlerProvider::ClearIA2Data(IA2Data& aData)
|
||||
HandlerProvider::CleanupStaticIA2Data(StaticIA2Data& aData)
|
||||
{
|
||||
// When CoMarshalInterface writes interfaces out to a stream, it AddRefs.
|
||||
// Therefore, we must release our references after this.
|
||||
if (aData.mIA2) {
|
||||
aData.mIA2->Release();
|
||||
}
|
||||
if (aData.mIEnumVARIANT) {
|
||||
aData.mIEnumVARIANT->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();
|
||||
}
|
||||
ZeroMemory(&aData, sizeof(StaticIA2Data));
|
||||
}
|
||||
|
||||
void
|
||||
HandlerProvider::CleanupDynamicIA2Data(DynamicIA2Data& aData)
|
||||
{
|
||||
::VariantClear(&aData.mRole);
|
||||
ZeroMemory(&aData, sizeof(IA2Data));
|
||||
ZeroMemory(&aData, sizeof(DynamicIA2Data));
|
||||
}
|
||||
|
||||
void
|
||||
HandlerProvider::BuildInitialIA2Data(
|
||||
NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
StaticIA2Data* aOutStaticData,
|
||||
DynamicIA2Data* aOutDynamicData)
|
||||
{
|
||||
BuildStaticIA2Data(aInterceptor, aOutStaticData);
|
||||
if (!aOutStaticData->mIA2) {
|
||||
return;
|
||||
}
|
||||
BuildDynamicIA2Data(aOutDynamicData);
|
||||
if (!aOutDynamicData->mUniqueId) {
|
||||
// Building dynamic data failed, which means building the payload failed.
|
||||
// However, we've already built static data, so we must clean this up.
|
||||
CleanupStaticIA2Data(*aOutStaticData);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -407,12 +523,12 @@ HandlerProvider::put_HandlerControl(long aPid, IHandlerControl* aCtrl)
|
|||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::Refresh(IA2Data* aOutData)
|
||||
HandlerProvider::Refresh(DynamicIA2Data* aOutData)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!mscom::InvokeOnMainThread("HandlerProvider::BuildIA2Data",
|
||||
this, &HandlerProvider::BuildIA2Data,
|
||||
if (!mscom::InvokeOnMainThread("HandlerProvider::BuildDynamicIA2Data",
|
||||
this, &HandlerProvider::BuildDynamicIA2Data,
|
||||
aOutData)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
|
|
@ -54,16 +54,23 @@ public:
|
|||
|
||||
// IGeckoBackChannel
|
||||
STDMETHODIMP put_HandlerControl(long aPid, IHandlerControl* aCtrl) override;
|
||||
STDMETHODIMP Refresh(IA2Data* aOutData) override;
|
||||
STDMETHODIMP Refresh(DynamicIA2Data* aOutData) override;
|
||||
|
||||
private:
|
||||
~HandlerProvider() = default;
|
||||
|
||||
void SetHandlerControlOnMainThread(DWORD aPid,
|
||||
mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
|
||||
void GetAndSerializePayload(const MutexAutoLock&);
|
||||
void BuildIA2Data(IA2Data* aOutIA2Data);
|
||||
static void ClearIA2Data(IA2Data& aData);
|
||||
void GetAndSerializePayload(const MutexAutoLock&,
|
||||
NotNull<mscom::IInterceptor*> aInterceptor);
|
||||
void BuildStaticIA2Data(NotNull<mscom::IInterceptor*> aInterceptor,
|
||||
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();
|
||||
|
||||
Atomic<uint32_t> mRefCnt;
|
||||
|
|
|
@ -147,7 +147,7 @@ AccessibleHandler::MaybeUpdateCachedData()
|
|||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mCachedData.mGeckoBackChannel->Refresh(&mCachedData.mData);
|
||||
return mCachedData.mGeckoBackChannel->Refresh(&mCachedData.mDynamicData);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
@ -245,6 +245,34 @@ AccessibleHandler::ReadHandlerPayload(IStream* aStream, REFIID aIid)
|
|||
return E_FAIL;
|
||||
}
|
||||
|
||||
// These interfaces have been aggregated into the proxy manager.
|
||||
// The proxy manager will resolve these interfaces now on QI,
|
||||
// so we can release these pointers.
|
||||
// Note that if pointers to other objects (in contrast to
|
||||
// interfaces of *this* object) are added in future, we should not release
|
||||
// those pointers.
|
||||
if (mCachedData.mStaticData.mIA2) {
|
||||
mCachedData.mStaticData.mIA2->Release();
|
||||
}
|
||||
if (mCachedData.mStaticData.mIEnumVARIANT) {
|
||||
mCachedData.mStaticData.mIEnumVARIANT->Release();
|
||||
}
|
||||
if (mCachedData.mStaticData.mIAHypertext) {
|
||||
mCachedData.mStaticData.mIAHypertext->Release();
|
||||
}
|
||||
if (mCachedData.mStaticData.mIAHyperlink) {
|
||||
mCachedData.mStaticData.mIAHyperlink->Release();
|
||||
}
|
||||
if (mCachedData.mStaticData.mIATable) {
|
||||
mCachedData.mStaticData.mIATable->Release();
|
||||
}
|
||||
if (mCachedData.mStaticData.mIATable2) {
|
||||
mCachedData.mStaticData.mIATable2->Release();
|
||||
}
|
||||
if (mCachedData.mStaticData.mIATableCell) {
|
||||
mCachedData.mStaticData.mIATableCell->Release();
|
||||
}
|
||||
|
||||
if (!mCachedData.mGeckoBackChannel) {
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -411,12 +439,12 @@ CopyBSTR(BSTR aSrc)
|
|||
|
||||
#define GET_FIELD(member, assignTo) \
|
||||
{ \
|
||||
assignTo = mCachedData.mData.member; \
|
||||
assignTo = mCachedData.mDynamicData.member; \
|
||||
}
|
||||
|
||||
#define GET_BSTR(member, assignTo) \
|
||||
{ \
|
||||
assignTo = CopyBSTR(mCachedData.mData.member); \
|
||||
assignTo = CopyBSTR(mCachedData.mDynamicData.member); \
|
||||
}
|
||||
|
||||
/*** IAccessible ***/
|
||||
|
@ -547,7 +575,7 @@ AccessibleHandler::get_accRole(VARIANT varChild, VARIANT *pvarRole)
|
|||
}
|
||||
|
||||
BEGIN_CACHE_ACCESS;
|
||||
return ::VariantCopy(pvarRole, &mCachedData.mData.mRole);
|
||||
return ::VariantCopy(pvarRole, &mCachedData.mDynamicData.mRole);
|
||||
}
|
||||
|
||||
|
||||
|
@ -919,7 +947,7 @@ AccessibleHandler::get_uniqueID(long* uniqueID)
|
|||
}
|
||||
return mIA2PassThru->get_uniqueID(uniqueID);
|
||||
}
|
||||
*uniqueID = mCachedData.mData.mUniqueId;
|
||||
*uniqueID = mCachedData.mDynamicData.mUniqueId;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,29 @@
|
|||
#include "mozilla-config.h"
|
||||
#include "AccessibleHandler.h"
|
||||
|
||||
import "oaidl.idl";
|
||||
import "ocidl.idl";
|
||||
import "ServProv.idl";
|
||||
|
||||
import "AccessibleText.idl";
|
||||
import "Accessible2_3.idl";
|
||||
import "AccessibleHypertext2.idl";
|
||||
import "AccessibleHyperlink.idl";
|
||||
import "AccessibleTable.idl";
|
||||
import "AccessibleTable2.idl";
|
||||
import "AccessibleTableCell.idl";
|
||||
|
||||
typedef struct _IA2Data
|
||||
typedef struct _StaticIA2Data
|
||||
{
|
||||
NEWEST_IA2_INTERFACE* mIA2;
|
||||
IEnumVARIANT* mIEnumVARIANT;
|
||||
IAccessibleHypertext2* mIAHypertext;
|
||||
IAccessibleHyperlink* mIAHyperlink;
|
||||
IAccessibleTable* mIATable;
|
||||
IAccessibleTable2* mIATable2;
|
||||
IAccessibleTableCell* mIATableCell;
|
||||
} StaticIA2Data;
|
||||
|
||||
typedef struct _DynamicIA2Data
|
||||
{
|
||||
VARIANT mRole;
|
||||
long mState;
|
||||
|
@ -32,7 +49,7 @@ typedef struct _IA2Data
|
|||
BSTR mAttributes;
|
||||
IA2Locale mIA2Locale;
|
||||
long mUniqueId;
|
||||
} IA2Data;
|
||||
} DynamicIA2Data;
|
||||
|
||||
interface IGeckoBackChannel;
|
||||
|
||||
|
@ -100,7 +117,8 @@ interface HandlerData
|
|||
{
|
||||
typedef struct _IA2Payload
|
||||
{
|
||||
IA2Data mData;
|
||||
StaticIA2Data mStaticData;
|
||||
DynamicIA2Data mDynamicData;
|
||||
IGeckoBackChannel* mGeckoBackChannel;
|
||||
} IA2Payload;
|
||||
}
|
||||
|
@ -123,7 +141,7 @@ interface IHandlerControl : IUnknown
|
|||
interface IGeckoBackChannel : IUnknown
|
||||
{
|
||||
[propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl);
|
||||
HRESULT Refresh([out] IA2Data* aOutData);
|
||||
HRESULT Refresh([out] DynamicIA2Data* aOutData);
|
||||
}
|
||||
|
||||
[uuid(1e545f07-f108-4912-9471-546827a80983)]
|
||||
|
|
Загрузка…
Ссылка в новой задаче