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 "build/build_config.h"
13 #include "core/fxcrt/fx_extension.h"
14 #include "third_party/base/ptr_util.h"
15 #include "third_party/base/stl_util.h"
16 #include "xfa/fwl/cfwl_app.h"
17 #include "xfa/fwl/cfwl_eventtarget.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_widgetmgr.h"
24 #include "xfa/fwl/fwl_widgetdef.h"
25 
26 CFWL_NoteDriver::CFWL_NoteDriver() = default;
27 
28 CFWL_NoteDriver::~CFWL_NoteDriver() = default;
29 
SendEvent(CFWL_Event * pNote)30 void CFWL_NoteDriver::SendEvent(CFWL_Event* pNote) {
31   for (const auto& pair : m_eventTargets) {
32     if (pair.second->IsValid())
33       pair.second->ProcessEvent(pNote);
34   }
35 }
36 
RegisterEventTarget(CFWL_Widget * pListener,CFWL_Widget * pEventSource)37 void CFWL_NoteDriver::RegisterEventTarget(CFWL_Widget* pListener,
38                                           CFWL_Widget* pEventSource) {
39   uint32_t key = pListener->GetEventKey();
40   if (key == 0) {
41     do {
42       key = rand();
43     } while (key == 0 || pdfium::ContainsKey(m_eventTargets, key));
44     pListener->SetEventKey(key);
45   }
46   if (!m_eventTargets[key])
47     m_eventTargets[key] = pdfium::MakeUnique<CFWL_EventTarget>(pListener);
48 
49   m_eventTargets[key]->SetEventSource(pEventSource);
50 }
51 
UnregisterEventTarget(CFWL_Widget * pListener)52 void CFWL_NoteDriver::UnregisterEventTarget(CFWL_Widget* pListener) {
53   uint32_t key = pListener->GetEventKey();
54   if (key == 0)
55     return;
56 
57   auto it = m_eventTargets.find(key);
58   if (it != m_eventTargets.end())
59     it->second->FlagInvalid();
60 }
61 
SetFocus(CFWL_Widget * pFocus)62 bool CFWL_NoteDriver::SetFocus(CFWL_Widget* pFocus) {
63   if (m_pFocus == pFocus)
64     return true;
65 
66   CFWL_Widget* pPrev = m_pFocus.Get();
67   m_pFocus = pFocus;
68   if (pPrev) {
69     if (IFWL_WidgetDelegate* pDelegate = pPrev->GetDelegate()) {
70       CFWL_MessageKillFocus ms(pPrev, pPrev);
71       pDelegate->OnProcessMessage(&ms);
72     }
73   }
74   if (pFocus) {
75     if (IFWL_WidgetDelegate* pDelegate = pFocus->GetDelegate()) {
76       CFWL_MessageSetFocus ms(nullptr, pFocus);
77       pDelegate->OnProcessMessage(&ms);
78     }
79   }
80   return true;
81 }
82 
NotifyTargetHide(CFWL_Widget * pNoteTarget)83 void CFWL_NoteDriver::NotifyTargetHide(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 
NotifyTargetDestroy(CFWL_Widget * pNoteTarget)92 void CFWL_NoteDriver::NotifyTargetDestroy(CFWL_Widget* pNoteTarget) {
93   if (m_pFocus == pNoteTarget)
94     m_pFocus = nullptr;
95   if (m_pHover == pNoteTarget)
96     m_pHover = nullptr;
97   if (m_pGrab == pNoteTarget)
98     m_pGrab = nullptr;
99 
100   UnregisterEventTarget(pNoteTarget);
101 }
102 
ProcessMessage(std::unique_ptr<CFWL_Message> pMessage)103 void CFWL_NoteDriver::ProcessMessage(std::unique_ptr<CFWL_Message> pMessage) {
104   CFWL_Widget* pMessageForm = pMessage->GetDstTarget();
105   if (!pMessageForm)
106     return;
107 
108   if (!DispatchMessage(pMessage.get(), pMessageForm))
109     return;
110 
111   if (pMessage->GetType() == CFWL_Message::Type::Mouse)
112     MouseSecondary(pMessage.get());
113 }
114 
DispatchMessage(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)115 bool CFWL_NoteDriver::DispatchMessage(CFWL_Message* pMessage,
116                                       CFWL_Widget* pMessageForm) {
117   switch (pMessage->GetType()) {
118     case CFWL_Message::Type::SetFocus: {
119       if (!DoSetFocus(pMessage, pMessageForm))
120         return false;
121       break;
122     }
123     case CFWL_Message::Type::KillFocus: {
124       if (!DoKillFocus(pMessage, pMessageForm))
125         return false;
126       break;
127     }
128     case CFWL_Message::Type::Key: {
129       if (!DoKey(pMessage, pMessageForm))
130         return false;
131       break;
132     }
133     case CFWL_Message::Type::Mouse: {
134       if (!DoMouse(pMessage, pMessageForm))
135         return false;
136       break;
137     }
138     case CFWL_Message::Type::MouseWheel: {
139       if (!DoWheel(pMessage, pMessageForm))
140         return false;
141       break;
142     }
143     default:
144       break;
145   }
146   IFWL_WidgetDelegate* pDelegate = pMessage->GetDstTarget()->GetDelegate();
147   if (pDelegate)
148     pDelegate->OnProcessMessage(pMessage);
149 
150   return true;
151 }
152 
DoSetFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)153 bool CFWL_NoteDriver::DoSetFocus(CFWL_Message* pMessage,
154                                  CFWL_Widget* pMessageForm) {
155   m_pFocus = pMessage->GetDstTarget();
156   return true;
157 }
158 
DoKillFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)159 bool CFWL_NoteDriver::DoKillFocus(CFWL_Message* pMessage,
160                                   CFWL_Widget* pMessageForm) {
161   if (m_pFocus == pMessage->GetDstTarget())
162     m_pFocus = nullptr;
163   return true;
164 }
165 
DoKey(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)166 bool CFWL_NoteDriver::DoKey(CFWL_Message* pMessage, CFWL_Widget* pMessageForm) {
167   CFWL_MessageKey* pMsg = static_cast<CFWL_MessageKey*>(pMessage);
168 #if !defined(OS_MACOSX)
169   if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
170       pMsg->m_dwKeyCode == XFA_FWL_VKEY_Tab) {
171     CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
172     CFWL_Widget* pForm = GetMessageForm(pMsg->GetDstTarget());
173     CFWL_Widget* pFocus = m_pFocus.Get();
174     if (m_pFocus && pWidgetMgr->GetSystemFormWidget(m_pFocus.Get()) != pForm)
175       pFocus = nullptr;
176 
177     CFWL_Widget* pNextTabStop = nullptr;
178     if (pForm) {
179       pNextTabStop = CFWL_WidgetMgr::NextTab(pForm, pFocus);
180       if (!pNextTabStop)
181         pNextTabStop = CFWL_WidgetMgr::NextTab(pForm, nullptr);
182     }
183     if (pNextTabStop == pFocus)
184       return true;
185     if (pNextTabStop)
186       SetFocus(pNextTabStop);
187     return true;
188   }
189 #endif
190 
191   if (m_pFocus) {
192     pMsg->SetDstTarget(m_pFocus.Get());
193     return true;
194   }
195 
196   if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
197       pMsg->m_dwKeyCode == XFA_FWL_VKEY_Return) {
198     CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
199     CFWL_Widget* pDefButton = pWidgetMgr->GetDefaultButton(pMessageForm);
200     if (pDefButton) {
201       pMsg->SetDstTarget(pDefButton);
202       return true;
203     }
204   }
205   return false;
206 }
207 
DoMouse(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)208 bool CFWL_NoteDriver::DoMouse(CFWL_Message* pMessage,
209                               CFWL_Widget* pMessageForm) {
210   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
211   if (pMsg->m_dwCmd == FWL_MouseCommand::Leave ||
212       pMsg->m_dwCmd == FWL_MouseCommand::Hover ||
213       pMsg->m_dwCmd == FWL_MouseCommand::Enter) {
214     return !!pMsg->GetDstTarget();
215   }
216   if (pMsg->GetDstTarget() != pMessageForm)
217     pMsg->m_pos = pMsg->GetDstTarget()->TransformTo(pMessageForm, pMsg->m_pos);
218   if (!DoMouseEx(pMsg, pMessageForm))
219     pMsg->SetDstTarget(pMessageForm);
220   return true;
221 }
222 
DoWheel(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)223 bool CFWL_NoteDriver::DoWheel(CFWL_Message* pMessage,
224                               CFWL_Widget* pMessageForm) {
225   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
226   CFWL_MessageMouseWheel* pMsg = static_cast<CFWL_MessageMouseWheel*>(pMessage);
227   CFWL_Widget* pDst = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
228   if (!pDst)
229     return false;
230 
231   pMsg->m_pos = pMessageForm->TransformTo(pDst, pMsg->m_pos);
232   pMsg->SetDstTarget(pDst);
233   return true;
234 }
235 
DoMouseEx(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)236 bool CFWL_NoteDriver::DoMouseEx(CFWL_Message* pMessage,
237                                 CFWL_Widget* pMessageForm) {
238   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
239   CFWL_Widget* pTarget = nullptr;
240   if (m_pGrab)
241     pTarget = m_pGrab.Get();
242 
243   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
244   if (!pTarget)
245     pTarget = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
246   if (!pTarget)
247     return false;
248   if (pTarget && pMessageForm != pTarget)
249     pMsg->m_pos = pMessageForm->TransformTo(pTarget, pMsg->m_pos);
250 
251   pMsg->SetDstTarget(pTarget);
252   return true;
253 }
254 
MouseSecondary(CFWL_Message * pMessage)255 void CFWL_NoteDriver::MouseSecondary(CFWL_Message* pMessage) {
256   CFWL_Widget* pTarget = pMessage->GetDstTarget();
257   if (pTarget == m_pHover)
258     return;
259 
260   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
261   if (m_pHover) {
262     CFWL_MessageMouse msLeave(
263         m_pHover.Get(), FWL_MouseCommand::Leave, 0,
264         pTarget->TransformTo(m_pHover.Get(), pMsg->m_pos));
265     DispatchMessage(&msLeave, nullptr);
266   }
267   if (pTarget->GetClassID() == FWL_Type::Form) {
268     m_pHover = nullptr;
269     return;
270   }
271   m_pHover = pTarget;
272 
273   CFWL_MessageMouse msHover(pTarget, FWL_MouseCommand::Hover, 0, pMsg->m_pos);
274   DispatchMessage(&msHover, nullptr);
275 }
276 
GetMessageForm(CFWL_Widget * pDstTarget)277 CFWL_Widget* CFWL_NoteDriver::GetMessageForm(CFWL_Widget* pDstTarget) {
278   if (!pDstTarget)
279     return nullptr;
280 
281   CFWL_WidgetMgr* pWidgetMgr = pDstTarget->GetOwnerApp()->GetWidgetMgr();
282   return pWidgetMgr->GetSystemFormWidget(pDstTarget);
283 }
284 
ClearEventTargets()285 void CFWL_NoteDriver::ClearEventTargets() {
286   auto it = m_eventTargets.begin();
287   while (it != m_eventTargets.end()) {
288     auto old = it++;
289     if (!old->second->IsValid())
290       m_eventTargets.erase(old);
291   }
292 }
293