1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fwl/cfwl_notedriver.h"
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "build/build_config.h"
13 #include "core/fxcrt/fx_extension.h"
14 #include "fxjs/gc/container_trace.h"
15 #include "xfa/fwl/cfwl_app.h"
16 #include "xfa/fwl/cfwl_event.h"
17 #include "xfa/fwl/cfwl_messagekey.h"
18 #include "xfa/fwl/cfwl_messagekillfocus.h"
19 #include "xfa/fwl/cfwl_messagemouse.h"
20 #include "xfa/fwl/cfwl_messagemousewheel.h"
21 #include "xfa/fwl/cfwl_messagesetfocus.h"
22 #include "xfa/fwl/cfwl_widgetmgr.h"
23 #include "xfa/fwl/fwl_widgetdef.h"
24
25 namespace {
26
27 uint64_t g_next_listener_key = 1;
28
29 } // namespace
30
CFWL_NoteDriver(CFWL_App * pApp)31 CFWL_NoteDriver::CFWL_NoteDriver(CFWL_App* pApp) : m_pApp(pApp) {}
32
33 CFWL_NoteDriver::~CFWL_NoteDriver() = default;
34
Trace(cppgc::Visitor * visitor) const35 void CFWL_NoteDriver::Trace(cppgc::Visitor* visitor) const {
36 visitor->Trace(m_pApp);
37 ContainerTrace(visitor, m_eventTargets);
38 visitor->Trace(m_pHover);
39 visitor->Trace(m_pFocus);
40 visitor->Trace(m_pGrab);
41 }
42
SendEvent(CFWL_Event * pNote)43 void CFWL_NoteDriver::SendEvent(CFWL_Event* pNote) {
44 for (const auto& pair : m_eventTargets) {
45 if (pair.second->IsValid())
46 pair.second->ProcessEvent(pNote);
47 }
48 }
49
RegisterEventTarget(CFWL_Widget * pListener,CFWL_Widget * pEventSource)50 void CFWL_NoteDriver::RegisterEventTarget(CFWL_Widget* pListener,
51 CFWL_Widget* pEventSource) {
52 uint64_t key = pListener->GetEventKey();
53 if (key == 0) {
54 key = g_next_listener_key++;
55 pListener->SetEventKey(key);
56 }
57 if (!m_eventTargets[key]) {
58 m_eventTargets[key] = cppgc::MakeGarbageCollected<Target>(
59 m_pApp->GetHeap()->GetAllocationHandle(), pListener);
60 }
61 m_eventTargets[key]->SetEventSource(pEventSource);
62 }
63
UnregisterEventTarget(CFWL_Widget * pListener)64 void CFWL_NoteDriver::UnregisterEventTarget(CFWL_Widget* pListener) {
65 uint64_t key = pListener->GetEventKey();
66 if (key == 0)
67 return;
68
69 auto it = m_eventTargets.find(key);
70 if (it != m_eventTargets.end())
71 it->second->Invalidate();
72 }
73
NotifyTargetHide(CFWL_Widget * pNoteTarget)74 void CFWL_NoteDriver::NotifyTargetHide(CFWL_Widget* pNoteTarget) {
75 if (m_pFocus == pNoteTarget)
76 m_pFocus = nullptr;
77 if (m_pHover == pNoteTarget)
78 m_pHover = nullptr;
79 if (m_pGrab == pNoteTarget)
80 m_pGrab = nullptr;
81 }
82
NotifyTargetDestroy(CFWL_Widget * pNoteTarget)83 void CFWL_NoteDriver::NotifyTargetDestroy(CFWL_Widget* pNoteTarget) {
84 if (m_pFocus == pNoteTarget)
85 m_pFocus = nullptr;
86 if (m_pHover == pNoteTarget)
87 m_pHover = nullptr;
88 if (m_pGrab == pNoteTarget)
89 m_pGrab = nullptr;
90
91 UnregisterEventTarget(pNoteTarget);
92 }
93
ProcessMessage(CFWL_Message * pMessage)94 void CFWL_NoteDriver::ProcessMessage(CFWL_Message* pMessage) {
95 CFWL_Widget* pMessageForm = pMessage->GetDstTarget();
96 if (!pMessageForm)
97 return;
98
99 if (!DispatchMessage(pMessage, pMessageForm))
100 return;
101
102 if (pMessage->GetType() == CFWL_Message::Type::kMouse)
103 MouseSecondary(pMessage);
104 }
105
DispatchMessage(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)106 bool CFWL_NoteDriver::DispatchMessage(CFWL_Message* pMessage,
107 CFWL_Widget* pMessageForm) {
108 switch (pMessage->GetType()) {
109 case CFWL_Message::Type::kSetFocus: {
110 if (!DoSetFocus(pMessage, pMessageForm))
111 return false;
112 break;
113 }
114 case CFWL_Message::Type::kKillFocus: {
115 if (!DoKillFocus(pMessage, pMessageForm))
116 return false;
117 break;
118 }
119 case CFWL_Message::Type::kKey: {
120 if (!DoKey(pMessage, pMessageForm))
121 return false;
122 break;
123 }
124 case CFWL_Message::Type::kMouse: {
125 if (!DoMouse(pMessage, pMessageForm))
126 return false;
127 break;
128 }
129 case CFWL_Message::Type::kMouseWheel: {
130 if (!DoWheel(pMessage, pMessageForm))
131 return false;
132 break;
133 }
134 }
135 IFWL_WidgetDelegate* pDelegate = pMessage->GetDstTarget()->GetDelegate();
136 if (pDelegate)
137 pDelegate->OnProcessMessage(pMessage);
138
139 return true;
140 }
141
DoSetFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)142 bool CFWL_NoteDriver::DoSetFocus(CFWL_Message* pMessage,
143 CFWL_Widget* pMessageForm) {
144 m_pFocus = pMessage->GetDstTarget();
145 return true;
146 }
147
DoKillFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)148 bool CFWL_NoteDriver::DoKillFocus(CFWL_Message* pMessage,
149 CFWL_Widget* pMessageForm) {
150 if (m_pFocus == pMessage->GetDstTarget())
151 m_pFocus = nullptr;
152 return true;
153 }
154
DoKey(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)155 bool CFWL_NoteDriver::DoKey(CFWL_Message* pMessage, CFWL_Widget* pMessageForm) {
156 CFWL_MessageKey* pMsg = static_cast<CFWL_MessageKey*>(pMessage);
157 #if !BUILDFLAG(IS_APPLE)
158 if (pMsg->m_dwCmd == CFWL_MessageKey::KeyCommand::kKeyDown &&
159 pMsg->m_dwKeyCodeOrChar == XFA_FWL_VKEY_Tab) {
160 return true;
161 }
162 #endif
163
164 if (m_pFocus) {
165 pMsg->SetDstTarget(m_pFocus.Get());
166 return true;
167 }
168
169 if (pMsg->m_dwCmd == CFWL_MessageKey::KeyCommand::kKeyDown &&
170 pMsg->m_dwKeyCodeOrChar == XFA_FWL_VKEY_Return) {
171 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetFWLApp()->GetWidgetMgr();
172 CFWL_Widget* pDefButton = pWidgetMgr->GetDefaultButton(pMessageForm);
173 if (pDefButton) {
174 pMsg->SetDstTarget(pDefButton);
175 return true;
176 }
177 }
178 return false;
179 }
180
DoMouse(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)181 bool CFWL_NoteDriver::DoMouse(CFWL_Message* pMessage,
182 CFWL_Widget* pMessageForm) {
183 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
184 if (pMsg->m_dwCmd == CFWL_MessageMouse::MouseCommand::kLeave ||
185 pMsg->m_dwCmd == CFWL_MessageMouse::MouseCommand::kHover ||
186 pMsg->m_dwCmd == CFWL_MessageMouse::MouseCommand::kEnter) {
187 return !!pMsg->GetDstTarget();
188 }
189 if (pMsg->GetDstTarget() != pMessageForm)
190 pMsg->m_pos = pMsg->GetDstTarget()->TransformTo(pMessageForm, pMsg->m_pos);
191 if (!DoMouseEx(pMsg, pMessageForm))
192 pMsg->SetDstTarget(pMessageForm);
193 return true;
194 }
195
DoWheel(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)196 bool CFWL_NoteDriver::DoWheel(CFWL_Message* pMessage,
197 CFWL_Widget* pMessageForm) {
198 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetFWLApp()->GetWidgetMgr();
199 CFWL_MessageMouseWheel* pMsg = static_cast<CFWL_MessageMouseWheel*>(pMessage);
200 CFWL_Widget* pDst = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->pos());
201 if (!pDst)
202 return false;
203
204 pMsg->set_pos(pMessageForm->TransformTo(pDst, pMsg->pos()));
205 pMsg->SetDstTarget(pDst);
206 return true;
207 }
208
DoMouseEx(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)209 bool CFWL_NoteDriver::DoMouseEx(CFWL_Message* pMessage,
210 CFWL_Widget* pMessageForm) {
211 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetFWLApp()->GetWidgetMgr();
212 CFWL_Widget* pTarget = nullptr;
213 if (m_pGrab)
214 pTarget = m_pGrab.Get();
215
216 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
217 if (!pTarget)
218 pTarget = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
219 if (!pTarget)
220 return false;
221 if (pTarget && pMessageForm != pTarget)
222 pMsg->m_pos = pMessageForm->TransformTo(pTarget, pMsg->m_pos);
223
224 pMsg->SetDstTarget(pTarget);
225 return true;
226 }
227
MouseSecondary(CFWL_Message * pMessage)228 void CFWL_NoteDriver::MouseSecondary(CFWL_Message* pMessage) {
229 CFWL_Widget* pTarget = pMessage->GetDstTarget();
230 if (pTarget == m_pHover)
231 return;
232
233 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
234 if (m_pHover) {
235 CFWL_MessageMouse msLeave(
236 m_pHover.Get(), CFWL_MessageMouse::MouseCommand::kLeave,
237 Mask<XFA_FWL_KeyFlag>(),
238 pTarget->TransformTo(m_pHover.Get(), pMsg->m_pos));
239 DispatchMessage(&msLeave, nullptr);
240 }
241 if (pTarget->GetClassID() == FWL_Type::Form) {
242 m_pHover = nullptr;
243 return;
244 }
245 m_pHover = pTarget;
246
247 CFWL_MessageMouse msHover(pTarget, CFWL_MessageMouse::MouseCommand::kHover,
248 Mask<XFA_FWL_KeyFlag>(), pMsg->m_pos);
249 DispatchMessage(&msHover, nullptr);
250 }
251
Target(CFWL_Widget * pListener)252 CFWL_NoteDriver::Target::Target(CFWL_Widget* pListener)
253 : m_pListener(pListener) {}
254
255 CFWL_NoteDriver::Target::~Target() = default;
256
Trace(cppgc::Visitor * visitor) const257 void CFWL_NoteDriver::Target::Trace(cppgc::Visitor* visitor) const {
258 visitor->Trace(m_pListener);
259 for (auto& widget : m_widgets)
260 visitor->Trace(widget);
261 }
262
SetEventSource(CFWL_Widget * pSource)263 void CFWL_NoteDriver::Target::SetEventSource(CFWL_Widget* pSource) {
264 if (pSource)
265 m_widgets.insert(pSource);
266 }
267
ProcessEvent(CFWL_Event * pEvent)268 bool CFWL_NoteDriver::Target::ProcessEvent(CFWL_Event* pEvent) {
269 IFWL_WidgetDelegate* pDelegate = m_pListener->GetDelegate();
270 if (!pDelegate)
271 return false;
272 if (!m_widgets.empty() && m_widgets.count(pEvent->GetSrcTarget()) == 0)
273 return false;
274 pDelegate->OnProcessEvent(pEvent);
275 return true;
276 }
277