Bug 1826326 [wpt PR 39360] - Get rid of ResourceWarnings produced by the tests, a...
[gecko.git] / widget / windows / InkCollector.cpp
blob2fcd2ea77d87746bf576bd69a833f20da9f6994d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=2 sw=2 et tw=78:
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 */
8 #include "InkCollector.h"
9 #include "nsDebug.h"
10 #include "nsISupportsUtils.h"
12 // Msinkaut_i.c and Msinkaut.h should both be included
13 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms695519.aspx
14 #include <msinkaut_i.c>
16 mozilla::StaticAutoPtr<InkCollector> InkCollector::sInkCollector;
18 InkCollector::~InkCollector() {
19 Shutdown();
20 MOZ_ASSERT(!mCookie && !mEnabled && !mComInitialized && !mMarshaller &&
21 !mInkCollector && !mConnectionPoint && !mInkCollectorEvent);
24 void InkCollector::Initialize() {
25 // Possibly, we can use mConnectionPoint for checking,
26 // But if errors exist (perhaps COM object is unavailable),
27 // Initialize() will be called more times.
28 static bool sInkCollectorCreated = false;
29 if (sInkCollectorCreated) {
30 return;
32 sInkCollectorCreated = true;
34 // COM could get uninitialized due to previous initialization.
35 mComInitialized = SUCCEEDED(::CoInitialize(nullptr));
37 // Set up instance of InkCollectorEvent.
38 mInkCollectorEvent = new InkCollectorEvent();
40 // Set up a free threaded marshaler.
41 if (FAILED(::CoCreateFreeThreadedMarshaler(mInkCollectorEvent,
42 getter_AddRefs(mMarshaller)))) {
43 return;
46 // Create the ink collector.
47 if (FAILED(::CoCreateInstance(CLSID_InkCollector, NULL, CLSCTX_INPROC_SERVER,
48 IID_IInkCollector,
49 getter_AddRefs(mInkCollector)))) {
50 return;
53 // Set up connection between sink and InkCollector.
54 RefPtr<IConnectionPointContainer> connPointContainer;
56 // Get the connection point container.
57 if (SUCCEEDED(mInkCollector->QueryInterface(
58 IID_IConnectionPointContainer, getter_AddRefs(connPointContainer)))) {
59 // Find the connection point for Ink Collector events.
60 if (SUCCEEDED(connPointContainer->FindConnectionPoint(
61 __uuidof(_IInkCollectorEvents),
62 getter_AddRefs(mConnectionPoint)))) {
63 // Hook up sink to connection point.
64 if (SUCCEEDED(mConnectionPoint->Advise(mInkCollectorEvent, &mCookie))) {
65 OnInitialize();
71 void InkCollector::Shutdown() {
72 Enable(false);
73 if (mConnectionPoint) {
74 // Remove the connection of the sink to the Ink Collector.
75 mConnectionPoint->Unadvise(mCookie);
76 mCookie = 0;
77 mConnectionPoint = nullptr;
79 mInkCollector = nullptr;
80 mMarshaller = nullptr;
81 mInkCollectorEvent = nullptr;
83 // Let uninitialization get handled in a place where it got inited.
84 if (mComInitialized) {
85 CoUninitialize();
86 mComInitialized = false;
90 void InkCollector::OnInitialize() {
91 // Suppress all events to do not allow performance decreasing.
92 // https://msdn.microsoft.com/en-us/library/ms820347.aspx
93 mInkCollector->SetEventInterest(InkCollectorEventInterest::ICEI_AllEvents,
94 VARIANT_FALSE);
96 // Sets a value that indicates whether an object or control has interest in a
97 // specified event.
98 mInkCollector->SetEventInterest(
99 InkCollectorEventInterest::ICEI_CursorOutOfRange, VARIANT_TRUE);
101 // If the MousePointer property is set to IMP_Custom and the MouseIcon
102 // property is NULL, Then the ink collector no longer handles mouse cursor
103 // settings.
104 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms700686.aspx
105 mInkCollector->put_MouseIcon(nullptr);
106 mInkCollector->put_MousePointer(InkMousePointer::IMP_Custom);
108 // This mode allows an ink collector to collect ink from any tablet attached
109 // to the Tablet PC. The Boolean value that indicates whether to use the mouse
110 // as an input device. If TRUE, the mouse is used for input.
111 // https://msdn.microsoft.com/en-us/library/ms820346.aspx
112 mInkCollector->SetAllTabletsMode(VARIANT_FALSE);
114 // Sets the value that specifies whether ink is rendered as it is drawn.
115 // VARIANT_TRUE to render ink as it is drawn on the display.
116 // VARIANT_FALSE to not have the ink appear on the display as strokes are
117 // made.
118 // https://msdn.microsoft.com/en-us/library/windows/desktop/dd314598.aspx
119 mInkCollector->put_DynamicRendering(VARIANT_FALSE);
121 // Set AutoRedraw to false to prevent repainting the ink when the window is
122 // invalidated.
123 mInkCollector->put_AutoRedraw(VARIANT_FALSE);
126 // Sets a value that specifies whether the InkCollector object collects pen
127 // input. This property must be set to FALSE before setting or calling specific
128 // properties and methods of the object.
129 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms701721.aspx
130 void InkCollector::Enable(bool aNewState) {
131 if (aNewState != mEnabled) {
132 if (mInkCollector) {
133 if (SUCCEEDED(mInkCollector->put_Enabled(aNewState ? VARIANT_TRUE
134 : VARIANT_FALSE))) {
135 mEnabled = aNewState;
136 } else {
137 NS_WARNING("InkCollector did not change status successfully");
139 } else {
140 NS_WARNING("InkCollector should be exist");
145 HWND InkCollector::GetTarget() { return mTargetWindow; }
147 void InkCollector::SetTarget(HWND aTargetWindow) {
148 NS_ASSERTION(aTargetWindow, "aTargetWindow should be exist");
149 if (aTargetWindow && (aTargetWindow != mTargetWindow)) {
150 Initialize();
151 if (mInkCollector) {
152 Enable(false);
153 if (SUCCEEDED(mInkCollector->put_hWnd((LONG_PTR)aTargetWindow))) {
154 mTargetWindow = aTargetWindow;
155 } else {
156 NS_WARNING("InkCollector did not change window property successfully");
158 Enable(true);
163 void InkCollector::ClearTarget() {
164 if (mTargetWindow && mInkCollector) {
165 Enable(false);
166 if (SUCCEEDED(mInkCollector->put_hWnd(0))) {
167 mTargetWindow = 0;
168 } else {
169 NS_WARNING("InkCollector did not clear window property successfully");
174 uint16_t InkCollector::GetPointerId() { return mPointerId; }
176 void InkCollector::SetPointerId(uint16_t aPointerId) {
177 mPointerId = aPointerId;
180 void InkCollector::ClearPointerId() { mPointerId = 0; }
182 // The display and the digitizer have quite different properties.
183 // The display has CursorMustTouch, the mouse pointer alway touches the display
184 // surface. The digitizer lists Integrated and HardProximity. When the stylus is
185 // in the proximity of the tablet its movements are also detected. An external
186 // tablet will only list HardProximity.
187 bool InkCollectorEvent::IsHardProximityTablet(IInkTablet* aTablet) const {
188 if (aTablet) {
189 TabletHardwareCapabilities caps;
190 if (SUCCEEDED(aTablet->get_HardwareCapabilities(&caps))) {
191 return (TabletHardwareCapabilities::THWC_HardProximity & caps);
194 return false;
197 HRESULT __stdcall InkCollectorEvent::QueryInterface(REFIID aRiid,
198 void** aObject) {
199 // Validate the input
200 if (!aObject) {
201 return E_POINTER;
203 HRESULT result = E_NOINTERFACE;
204 // This object supports IUnknown/IDispatch/IInkCollectorEvents
205 if ((IID_IUnknown == aRiid) || (IID_IDispatch == aRiid) ||
206 (DIID__IInkCollectorEvents == aRiid)) {
207 *aObject = this;
208 // AddRef should be called when we give info about interface
209 NS_ADDREF_THIS();
210 result = S_OK;
212 return result;
215 HRESULT InkCollectorEvent::Invoke(DISPID aDispIdMember, REFIID /*aRiid*/,
216 LCID /*aId*/, WORD /*wFlags*/,
217 DISPPARAMS* aDispParams,
218 VARIANT* /*aVarResult*/,
219 EXCEPINFO* /*aExcepInfo*/,
220 UINT* /*aArgErr*/) {
221 switch (aDispIdMember) {
222 case DISPID_ICECursorOutOfRange: {
223 if (aDispParams && aDispParams->cArgs) {
224 CursorOutOfRange(
225 static_cast<IInkCursor*>(aDispParams->rgvarg[0].pdispVal));
227 break;
230 return S_OK;
233 void InkCollectorEvent::CursorOutOfRange(IInkCursor* aCursor) const {
234 IInkTablet* curTablet = nullptr;
235 if (FAILED(aCursor->get_Tablet(&curTablet))) {
236 return;
238 // All events should be suppressed except
239 // from tablets with hard proximity.
240 if (!IsHardProximityTablet(curTablet)) {
241 return;
243 // Notify current target window.
244 if (HWND targetWindow = InkCollector::sInkCollector->GetTarget()) {
245 ::SendMessage(targetWindow, MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER, 0, 0);