1 // Copyright 2014 PDFium Authors. All rights reserved.
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 "core/fxcrt/fx_ext.h"
13 #include "third_party/base/ptr_util.h"
14 #include "third_party/base/stl_util.h"
15 #include "xfa/fwl/cfwl_app.h"
16 #include "xfa/fwl/cfwl_eventtarget.h"
17 #include "xfa/fwl/cfwl_form.h"
18 #include "xfa/fwl/cfwl_messagekey.h"
19 #include "xfa/fwl/cfwl_messagekillfocus.h"
20 #include "xfa/fwl/cfwl_messagemouse.h"
21 #include "xfa/fwl/cfwl_messagemousewheel.h"
22 #include "xfa/fwl/cfwl_messagesetfocus.h"
23 #include "xfa/fwl/cfwl_noteloop.h"
24 #include "xfa/fwl/cfwl_widgetmgr.h"
25 
CFWL_NoteDriver()26 CFWL_NoteDriver::CFWL_NoteDriver()
27     : m_pHover(nullptr),
28       m_pFocus(nullptr),
29       m_pGrab(nullptr),
30       m_pNoteLoop(pdfium::MakeUnique<CFWL_NoteLoop>()) {
31   PushNoteLoop(m_pNoteLoop.get());
32 }
33 
~CFWL_NoteDriver()34 CFWL_NoteDriver::~CFWL_NoteDriver() {
35   ClearEventTargets(true);
36 }
37 
SendEvent(CFWL_Event * pNote)38 void CFWL_NoteDriver::SendEvent(CFWL_Event* pNote) {
39   if (m_eventTargets.empty())
40     return;
41 
42   for (const auto& pair : m_eventTargets) {
43     CFWL_EventTarget* pEventTarget = pair.second;
44     if (pEventTarget && !pEventTarget->IsInvalid())
45       pEventTarget->ProcessEvent(pNote);
46   }
47 }
48 
RegisterEventTarget(CFWL_Widget * pListener,CFWL_Widget * pEventSource)49 void CFWL_NoteDriver::RegisterEventTarget(CFWL_Widget* pListener,
50                                           CFWL_Widget* pEventSource) {
51   uint32_t key = pListener->GetEventKey();
52   if (key == 0) {
53     do {
54       key = rand();
55     } while (key == 0 || pdfium::ContainsKey(m_eventTargets, key));
56     pListener->SetEventKey(key);
57   }
58   if (!m_eventTargets[key])
59     m_eventTargets[key] = new CFWL_EventTarget(pListener);
60 
61   m_eventTargets[key]->SetEventSource(pEventSource);
62 }
63 
UnregisterEventTarget(CFWL_Widget * pListener)64 void CFWL_NoteDriver::UnregisterEventTarget(CFWL_Widget* pListener) {
65   uint32_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->FlagInvalid();
72 }
73 
PushNoteLoop(CFWL_NoteLoop * pNoteLoop)74 void CFWL_NoteDriver::PushNoteLoop(CFWL_NoteLoop* pNoteLoop) {
75   m_NoteLoopQueue.push_back(pNoteLoop);
76 }
77 
PopNoteLoop()78 CFWL_NoteLoop* CFWL_NoteDriver::PopNoteLoop() {
79   if (m_NoteLoopQueue.empty())
80     return nullptr;
81 
82   CFWL_NoteLoop* p = m_NoteLoopQueue.back();
83   m_NoteLoopQueue.pop_back();
84   return p;
85 }
86 
SetFocus(CFWL_Widget * pFocus)87 bool CFWL_NoteDriver::SetFocus(CFWL_Widget* pFocus) {
88   if (m_pFocus == pFocus)
89     return true;
90 
91   CFWL_Widget* pPrev = m_pFocus;
92   m_pFocus = pFocus;
93   if (pPrev) {
94     if (IFWL_WidgetDelegate* pDelegate = pPrev->GetDelegate()) {
95       CFWL_MessageKillFocus ms(pPrev, pPrev);
96       pDelegate->OnProcessMessage(&ms);
97     }
98   }
99   if (pFocus) {
100     CFWL_Widget* pWidget =
101         pFocus->GetOwnerApp()->GetWidgetMgr()->GetSystemFormWidget(pFocus);
102     CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
103     if (pForm)
104       pForm->SetSubFocus(pFocus);
105 
106     if (IFWL_WidgetDelegate* pDelegate = pFocus->GetDelegate()) {
107       CFWL_MessageSetFocus ms(nullptr, pFocus);
108       pDelegate->OnProcessMessage(&ms);
109     }
110   }
111   return true;
112 }
113 
Run()114 void CFWL_NoteDriver::Run() {
115 #if (_FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_WIN32_DESKTOP_ || \
116      _FX_OS_ == _FX_WIN64_)
117   for (;;) {
118     CFWL_NoteLoop* pTopLoop = GetTopLoop();
119     if (!pTopLoop || !pTopLoop->ContinueModal())
120       break;
121     UnqueueMessageAndProcess(pTopLoop);
122   }
123 #endif
124 }
125 
NotifyTargetHide(CFWL_Widget * pNoteTarget)126 void CFWL_NoteDriver::NotifyTargetHide(CFWL_Widget* pNoteTarget) {
127   if (m_pFocus == pNoteTarget)
128     m_pFocus = nullptr;
129   if (m_pHover == pNoteTarget)
130     m_pHover = nullptr;
131   if (m_pGrab == pNoteTarget)
132     m_pGrab = nullptr;
133 }
134 
NotifyTargetDestroy(CFWL_Widget * pNoteTarget)135 void CFWL_NoteDriver::NotifyTargetDestroy(CFWL_Widget* pNoteTarget) {
136   if (m_pFocus == pNoteTarget)
137     m_pFocus = nullptr;
138   if (m_pHover == pNoteTarget)
139     m_pHover = nullptr;
140   if (m_pGrab == pNoteTarget)
141     m_pGrab = nullptr;
142 
143   UnregisterEventTarget(pNoteTarget);
144 
145   for (CFWL_Widget* pWidget : m_Forms) {
146     CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
147     if (!pForm)
148       continue;
149 
150     CFWL_Widget* pSubFocus = pForm->GetSubFocus();
151     if (!pSubFocus)
152       return;
153 
154     if (pSubFocus == pNoteTarget)
155       pForm->SetSubFocus(nullptr);
156   }
157 }
158 
RegisterForm(CFWL_Widget * pForm)159 void CFWL_NoteDriver::RegisterForm(CFWL_Widget* pForm) {
160   if (!pForm || pdfium::ContainsValue(m_Forms, pForm))
161     return;
162 
163   m_Forms.push_back(pForm);
164   if (m_Forms.size() == 1 && !m_NoteLoopQueue.empty() && m_NoteLoopQueue[0])
165     m_NoteLoopQueue[0]->SetMainForm(pForm);
166 }
167 
UnRegisterForm(CFWL_Widget * pForm)168 void CFWL_NoteDriver::UnRegisterForm(CFWL_Widget* pForm) {
169   auto iter = std::find(m_Forms.begin(), m_Forms.end(), pForm);
170   if (iter != m_Forms.end())
171     m_Forms.erase(iter);
172 }
173 
QueueMessage(std::unique_ptr<CFWL_Message> pMessage)174 void CFWL_NoteDriver::QueueMessage(std::unique_ptr<CFWL_Message> pMessage) {
175   m_NoteQueue.push_back(std::move(pMessage));
176 }
177 
UnqueueMessageAndProcess(CFWL_NoteLoop * pNoteLoop)178 void CFWL_NoteDriver::UnqueueMessageAndProcess(CFWL_NoteLoop* pNoteLoop) {
179   if (m_NoteQueue.empty())
180     return;
181 
182   std::unique_ptr<CFWL_Message> pMessage = std::move(m_NoteQueue.front());
183   m_NoteQueue.pop_front();
184   if (!IsValidMessage(pMessage.get()))
185     return;
186 
187   ProcessMessage(std::move(pMessage));
188 }
189 
GetTopLoop() const190 CFWL_NoteLoop* CFWL_NoteDriver::GetTopLoop() const {
191   return !m_NoteLoopQueue.empty() ? m_NoteLoopQueue.back() : nullptr;
192 }
193 
ProcessMessage(std::unique_ptr<CFWL_Message> pMessage)194 void CFWL_NoteDriver::ProcessMessage(std::unique_ptr<CFWL_Message> pMessage) {
195   CFWL_WidgetMgr* pWidgetMgr =
196       pMessage->m_pDstTarget->GetOwnerApp()->GetWidgetMgr();
197   CFWL_Widget* pMessageForm = pWidgetMgr->IsFormDisabled()
198                                   ? pMessage->m_pDstTarget
199                                   : GetMessageForm(pMessage->m_pDstTarget);
200   if (!pMessageForm)
201     return;
202 
203   if (!DispatchMessage(pMessage.get(), pMessageForm))
204     return;
205 
206   if (pMessage->GetType() == CFWL_Message::Type::Mouse)
207     MouseSecondary(pMessage.get());
208 }
209 
DispatchMessage(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)210 bool CFWL_NoteDriver::DispatchMessage(CFWL_Message* pMessage,
211                                       CFWL_Widget* pMessageForm) {
212   switch (pMessage->GetType()) {
213     case CFWL_Message::Type::SetFocus: {
214       if (!DoSetFocus(pMessage, pMessageForm))
215         return false;
216       break;
217     }
218     case CFWL_Message::Type::KillFocus: {
219       if (!DoKillFocus(pMessage, pMessageForm))
220         return false;
221       break;
222     }
223     case CFWL_Message::Type::Key: {
224       if (!DoKey(pMessage, pMessageForm))
225         return false;
226       break;
227     }
228     case CFWL_Message::Type::Mouse: {
229       if (!DoMouse(pMessage, pMessageForm))
230         return false;
231       break;
232     }
233     case CFWL_Message::Type::MouseWheel: {
234       if (!DoWheel(pMessage, pMessageForm))
235         return false;
236       break;
237     }
238     default:
239       break;
240   }
241   if (IFWL_WidgetDelegate* pDelegate = pMessage->m_pDstTarget->GetDelegate())
242     pDelegate->OnProcessMessage(pMessage);
243 
244   return true;
245 }
246 
DoSetFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)247 bool CFWL_NoteDriver::DoSetFocus(CFWL_Message* pMessage,
248                                  CFWL_Widget* pMessageForm) {
249   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
250   if (pWidgetMgr->IsFormDisabled()) {
251     m_pFocus = pMessage->m_pDstTarget;
252     return true;
253   }
254 
255   CFWL_Widget* pWidget = pMessage->m_pDstTarget;
256   if (!pWidget)
257     return false;
258 
259   CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
260   CFWL_Widget* pSubFocus = pForm->GetSubFocus();
261   if (pSubFocus && ((pSubFocus->GetStates() & FWL_WGTSTATE_Focused) == 0)) {
262     pMessage->m_pDstTarget = pSubFocus;
263     if (m_pFocus != pMessage->m_pDstTarget) {
264       m_pFocus = pMessage->m_pDstTarget;
265       return true;
266     }
267   }
268   return false;
269 }
270 
DoKillFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)271 bool CFWL_NoteDriver::DoKillFocus(CFWL_Message* pMessage,
272                                   CFWL_Widget* pMessageForm) {
273   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
274   if (pWidgetMgr->IsFormDisabled()) {
275     if (m_pFocus == pMessage->m_pDstTarget)
276       m_pFocus = nullptr;
277     return true;
278   }
279 
280   CFWL_Form* pForm = static_cast<CFWL_Form*>(pMessage->m_pDstTarget);
281   if (!pForm)
282     return false;
283 
284   CFWL_Widget* pSubFocus = pForm->GetSubFocus();
285   if (pSubFocus && (pSubFocus->GetStates() & FWL_WGTSTATE_Focused)) {
286     pMessage->m_pDstTarget = pSubFocus;
287     if (m_pFocus == pMessage->m_pDstTarget) {
288       m_pFocus = nullptr;
289       return true;
290     }
291   }
292   return false;
293 }
294 
DoKey(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)295 bool CFWL_NoteDriver::DoKey(CFWL_Message* pMessage, CFWL_Widget* pMessageForm) {
296   CFWL_MessageKey* pMsg = static_cast<CFWL_MessageKey*>(pMessage);
297 #if (_FX_OS_ != _FX_MACOSX_)
298   if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
299       pMsg->m_dwKeyCode == FWL_VKEY_Tab) {
300     CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
301     CFWL_Widget* pForm = GetMessageForm(pMsg->m_pDstTarget);
302     CFWL_Widget* pFocus = m_pFocus;
303     if (m_pFocus && pWidgetMgr->GetSystemFormWidget(m_pFocus) != pForm)
304       pFocus = nullptr;
305 
306     bool bFind = false;
307     CFWL_Widget* pNextTabStop = pWidgetMgr->NextTab(pForm, pFocus, bFind);
308     if (!pNextTabStop) {
309       bFind = false;
310       pNextTabStop = pWidgetMgr->NextTab(pForm, nullptr, bFind);
311     }
312     if (pNextTabStop == pFocus)
313       return true;
314     if (pNextTabStop)
315       SetFocus(pNextTabStop);
316     return true;
317   }
318 #endif
319 
320   if (!m_pFocus) {
321     if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
322         pMsg->m_dwKeyCode == FWL_VKEY_Return) {
323       CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
324       CFWL_Widget* defButton = pWidgetMgr->GetDefaultButton(pMessageForm);
325       if (defButton) {
326         pMsg->m_pDstTarget = defButton;
327         return true;
328       }
329     }
330     return false;
331   }
332   pMsg->m_pDstTarget = m_pFocus;
333   return true;
334 }
335 
DoMouse(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)336 bool CFWL_NoteDriver::DoMouse(CFWL_Message* pMessage,
337                               CFWL_Widget* pMessageForm) {
338   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
339   if (pMsg->m_dwCmd == FWL_MouseCommand::Leave ||
340       pMsg->m_dwCmd == FWL_MouseCommand::Hover ||
341       pMsg->m_dwCmd == FWL_MouseCommand::Enter) {
342     return !!pMsg->m_pDstTarget;
343   }
344   if (pMsg->m_pDstTarget != pMessageForm)
345     pMsg->m_pos = pMsg->m_pDstTarget->TransformTo(pMessageForm, pMsg->m_pos);
346   if (!DoMouseEx(pMsg, pMessageForm))
347     pMsg->m_pDstTarget = pMessageForm;
348   return true;
349 }
350 
DoWheel(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)351 bool CFWL_NoteDriver::DoWheel(CFWL_Message* pMessage,
352                               CFWL_Widget* pMessageForm) {
353   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
354   if (!pWidgetMgr)
355     return false;
356 
357   CFWL_MessageMouseWheel* pMsg = static_cast<CFWL_MessageMouseWheel*>(pMessage);
358   CFWL_Widget* pDst = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
359   if (!pDst)
360     return false;
361 
362   pMsg->m_pos = pMessageForm->TransformTo(pDst, pMsg->m_pos);
363   pMsg->m_pDstTarget = pDst;
364   return true;
365 }
366 
DoMouseEx(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)367 bool CFWL_NoteDriver::DoMouseEx(CFWL_Message* pMessage,
368                                 CFWL_Widget* pMessageForm) {
369   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
370   if (!pWidgetMgr)
371     return false;
372   CFWL_Widget* pTarget = nullptr;
373   if (m_pGrab)
374     pTarget = m_pGrab;
375 
376   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
377   if (!pTarget)
378     pTarget = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
379   if (!pTarget)
380     return false;
381   if (pTarget && pMessageForm != pTarget)
382     pMsg->m_pos = pMessageForm->TransformTo(pTarget, pMsg->m_pos);
383 
384   pMsg->m_pDstTarget = pTarget;
385   return true;
386 }
387 
MouseSecondary(CFWL_Message * pMessage)388 void CFWL_NoteDriver::MouseSecondary(CFWL_Message* pMessage) {
389   CFWL_Widget* pTarget = pMessage->m_pDstTarget;
390   if (pTarget == m_pHover)
391     return;
392 
393   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
394   if (m_pHover) {
395     CFWL_MessageMouse msLeave(nullptr, m_pHover);
396     msLeave.m_pos = pTarget->TransformTo(m_pHover, pMsg->m_pos);
397     msLeave.m_dwFlags = 0;
398     msLeave.m_dwCmd = FWL_MouseCommand::Leave;
399     DispatchMessage(&msLeave, nullptr);
400   }
401   if (pTarget->GetClassID() == FWL_Type::Form) {
402     m_pHover = nullptr;
403     return;
404   }
405   m_pHover = pTarget;
406 
407   CFWL_MessageMouse msHover(nullptr, pTarget);
408   msHover.m_pos = pMsg->m_pos;
409   msHover.m_dwFlags = 0;
410   msHover.m_dwCmd = FWL_MouseCommand::Hover;
411   DispatchMessage(&msHover, nullptr);
412 }
413 
IsValidMessage(CFWL_Message * pMessage)414 bool CFWL_NoteDriver::IsValidMessage(CFWL_Message* pMessage) {
415   for (CFWL_NoteLoop* pNoteLoop : m_NoteLoopQueue) {
416     CFWL_Widget* pForm = pNoteLoop->GetForm();
417     if (pForm && pForm == pMessage->m_pDstTarget)
418       return true;
419   }
420   for (CFWL_Widget* pWidget : m_Forms) {
421     CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
422     if (pForm == pMessage->m_pDstTarget)
423       return true;
424   }
425   return false;
426 }
427 
GetMessageForm(CFWL_Widget * pDstTarget)428 CFWL_Widget* CFWL_NoteDriver::GetMessageForm(CFWL_Widget* pDstTarget) {
429   if (m_NoteLoopQueue.empty())
430     return nullptr;
431 
432   CFWL_Widget* pMessageForm = nullptr;
433   if (m_NoteLoopQueue.size() > 1)
434     pMessageForm = m_NoteLoopQueue.back()->GetForm();
435   else if (!pdfium::ContainsValue(m_Forms, pDstTarget))
436     pMessageForm = pDstTarget;
437 
438   if (!pMessageForm && pDstTarget) {
439     CFWL_WidgetMgr* pWidgetMgr = pDstTarget->GetOwnerApp()->GetWidgetMgr();
440     if (!pWidgetMgr)
441       return nullptr;
442 
443     pMessageForm = pWidgetMgr->GetSystemFormWidget(pDstTarget);
444   }
445   return pMessageForm;
446 }
447 
ClearEventTargets(bool bRemoveAll)448 void CFWL_NoteDriver::ClearEventTargets(bool bRemoveAll) {
449   auto it = m_eventTargets.begin();
450   while (it != m_eventTargets.end()) {
451     auto old = it++;
452     if (old->second && (bRemoveAll || old->second->IsInvalid())) {
453       delete old->second;
454       m_eventTargets.erase(old);
455     }
456   }
457 }
458