1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_a11y_HandlerProvider_h
8 #define mozilla_a11y_HandlerProvider_h
9 
10 #include "mozilla/a11y/AccessibleHandler.h"
11 #include "mozilla/a11y/HandlerDataCleanup.h"
12 #include "mozilla/AlreadyAddRefed.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/mscom/IHandlerProvider.h"
15 #include "mozilla/mscom/Ptr.h"
16 #include "mozilla/mscom/StructStream.h"
17 #include "mozilla/Mutex.h"
18 #include "mozilla/UniquePtr.h"
19 #include "HandlerData.h"
20 
21 struct NEWEST_IA2_INTERFACE;
22 
23 namespace mozilla {
24 
25 namespace mscom {
26 
27 class StructToStream;
28 
29 }  // namespace mscom
30 
31 namespace a11y {
32 
33 class HandlerProvider final : public IGeckoBackChannel,
34                               public mscom::IHandlerProvider {
35  public:
36   HandlerProvider(REFIID aIid, mscom::InterceptorTargetPtr<IUnknown> aTarget);
37 
38   // IUnknown
39   STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
40   STDMETHODIMP_(ULONG) AddRef() override;
41   STDMETHODIMP_(ULONG) Release() override;
42 
43   // IHandlerProvider
44   STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
45   STDMETHODIMP GetHandlerPayloadSize(NotNull<mscom::IInterceptor*> aInterceptor,
46                                      NotNull<DWORD*> aOutPayloadSize) override;
47   STDMETHODIMP WriteHandlerPayload(NotNull<mscom::IInterceptor*> aInterceptor,
48                                    NotNull<IStream*> aStream) override;
49   STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
50   STDMETHODIMP DisconnectHandlerRemotes() override;
51   STDMETHODIMP IsInterfaceMaybeSupported(REFIID aIid) override;
52   STDMETHODIMP_(REFIID)
53   GetEffectiveOutParamIid(REFIID aCallIid, ULONG aCallMethod) override;
54   STDMETHODIMP NewInstance(
55       REFIID aIid, mscom::InterceptorTargetPtr<IUnknown> aTarget,
56       NotNull<mscom::IHandlerProvider**> aOutNewPayload) override;
57 
58   // IGeckoBackChannel
59   STDMETHODIMP put_HandlerControl(long aPid, IHandlerControl* aCtrl) override;
60   STDMETHODIMP Refresh(DynamicIA2Data* aOutData) override;
61   STDMETHODIMP get_AllTextInfo(BSTR* aText, IAccessibleHyperlink*** aHyperlinks,
62                                long* aNHyperlinks, IA2TextSegment** aAttribRuns,
63                                long* aNAttribRuns) override;
64   STDMETHODIMP get_RelationsInfo(IARelationData** aRelations,
65                                  long* aNRelations) override;
66   STDMETHODIMP get_AllChildren(AccChildData** aChildren,
67                                ULONG* aNChildren) override;
68 
69  private:
70   ~HandlerProvider() = default;
71 
72   void SetHandlerControlOnMainThread(
73       DWORD aPid, mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
74   void GetAndSerializePayload(const MutexAutoLock&,
75                               NotNull<mscom::IInterceptor*> aInterceptor);
76   void BuildStaticIA2Data(NotNull<mscom::IInterceptor*> aInterceptor,
77                           StaticIA2Data* aOutData);
78   /**
79    * Pass true for aMarshaledByCom if this struct is being directly marshaled as
80    * an out parameter of a COM method, currently only
81    * IGeckoBackChannel::Refresh.
82    * When aMarshaledByCom is false, this means the struct is being marshaled
83    * by RPC encoding functions. This means we must allocate memory differently,
84    * even though we're using this as part of a COM handler payload.
85    */
86   void BuildDynamicIA2Data(DynamicIA2Data* aOutIA2Data,
87                            bool aMarshaledByCom = false);
88   void BuildInitialIA2Data(NotNull<mscom::IInterceptor*> aInterceptor,
89                            StaticIA2Data* aOutStaticData,
90                            DynamicIA2Data* aOutDynamicData);
91   bool IsTargetInterfaceCacheable();
92 
93   /**
94    * Build the payload for later marshaling.
95    * This is intended to be used during a bulk fetch operation and must only be
96    * called from the main thread.
97    */
98   void PrebuildPayload(NotNull<mscom::IInterceptor*> aInterceptor);
99 
100   // Replace a raw object from the main thread with a wrapped, intercepted
101   // object suitable for calling from the MTA.
102   // The reference to the original object is adopted; i.e. you should not
103   // separately release it.
104   // This is intended for objects returned from method calls on the main thread.
105   template <typename Interface>
106   HRESULT ToWrappedObject(Interface** aObj);
107   void GetAllTextInfoMainThread(BSTR* aText,
108                                 IAccessibleHyperlink*** aHyperlinks,
109                                 long* aNHyperlinks,
110                                 IA2TextSegment** aAttribRuns,
111                                 long* aNAttribRuns, HRESULT* result);
112   void GetRelationsInfoMainThread(IARelationData** aRelations,
113                                   long* aNRelations, HRESULT* result);
114   void GetAllChildrenMainThread(AccChildData** aChildren, ULONG* aNChildren,
115                                 HRESULT* result);
116 
117   Atomic<uint32_t> mRefCnt;
118   Mutex mMutex;  // Protects mSerializer
119   const IID mTargetUnkIid;
120   mscom::InterceptorTargetPtr<IUnknown>
121       mTargetUnk;  // Constant, main thread only
122   UniquePtr<mscom::StructToStream> mSerializer;
123   RefPtr<IUnknown> mFastMarshalUnk;
124 
125   struct IA2PayloadDeleter {
operatorIA2PayloadDeleter126     void operator()(IA2Payload* aPayload) {
127       // When CoMarshalInterface writes interfaces out to a stream, it AddRefs.
128       // Therefore, we must release our references after this.
129       ReleaseStaticIA2DataInterfaces(aPayload->mStaticData);
130       CleanupDynamicIA2Data(aPayload->mDynamicData);
131       delete aPayload;
132     }
133   };
134   using IA2PayloadPtr = UniquePtr<IA2Payload, IA2PayloadDeleter>;
135 
136   // Used when the payload is built prior to marshaling the object by a bulk
137   // fetch operation. See prebuildPayload().
138   IA2PayloadPtr mPayload;
139   Mutex mPayloadMutex;  // Protects mPayload
140 };
141 
142 }  // namespace a11y
143 }  // namespace mozilla
144 
145 #endif  // mozilla_a11y_HandlerProvider_h
146