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_widgetmgr.h"
8 
9 #include <utility>
10 
11 #include "build/build_config.h"
12 #include "third_party/base/ptr_util.h"
13 #include "xfa/fwl/cfwl_app.h"
14 #include "xfa/fwl/cfwl_message.h"
15 #include "xfa/fwl/cfwl_notedriver.h"
16 
CFWL_WidgetMgr(AdapterIface * pAdapterNative)17 CFWL_WidgetMgr::CFWL_WidgetMgr(AdapterIface* pAdapterNative)
18     : m_pAdapter(pAdapterNative) {
19   m_mapWidgetItem[nullptr] = pdfium::MakeUnique<Item>();
20 }
21 
22 CFWL_WidgetMgr::~CFWL_WidgetMgr() = default;
23 
24 // static
NextTab(CFWL_Widget * parent,CFWL_Widget * focus)25 CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent, CFWL_Widget* focus) {
26   CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr();
27   CFWL_Widget* child = pMgr->GetFirstChildWidget(parent);
28   while (child) {
29     CFWL_Widget* bRet = NextTab(child, focus);
30     if (bRet)
31       return bRet;
32 
33     child = pMgr->GetNextSiblingWidget(child);
34   }
35   return nullptr;
36 }
37 
GetParentWidget(const CFWL_Widget * pWidget) const38 CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(const CFWL_Widget* pWidget) const {
39   Item* pItem = GetWidgetMgrItem(pWidget);
40   return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr;
41 }
42 
GetOwnerWidget(const CFWL_Widget * pWidget) const43 CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(const CFWL_Widget* pWidget) const {
44   Item* pItem = GetWidgetMgrItem(pWidget);
45   return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr;
46 }
47 
GetFirstSiblingWidget(CFWL_Widget * pWidget) const48 CFWL_Widget* CFWL_WidgetMgr::GetFirstSiblingWidget(CFWL_Widget* pWidget) const {
49   Item* pItem = GetWidgetMgrItem(pWidget);
50   if (!pItem)
51     return nullptr;
52 
53   pItem = pItem->pPrevious;
54   while (pItem && pItem->pPrevious)
55     pItem = pItem->pPrevious;
56   return pItem ? pItem->pWidget : nullptr;
57 }
58 
GetPriorSiblingWidget(CFWL_Widget * pWidget) const59 CFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(CFWL_Widget* pWidget) const {
60   Item* pItem = GetWidgetMgrItem(pWidget);
61   return pItem && pItem->pPrevious ? pItem->pPrevious->pWidget : nullptr;
62 }
63 
GetNextSiblingWidget(CFWL_Widget * pWidget) const64 CFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(CFWL_Widget* pWidget) const {
65   Item* pItem = GetWidgetMgrItem(pWidget);
66   return pItem && pItem->pNext ? pItem->pNext->pWidget : nullptr;
67 }
68 
GetFirstChildWidget(CFWL_Widget * pWidget) const69 CFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(CFWL_Widget* pWidget) const {
70   Item* pItem = GetWidgetMgrItem(pWidget);
71   return pItem && pItem->pChild ? pItem->pChild->pWidget : nullptr;
72 }
73 
GetLastChildWidget(CFWL_Widget * pWidget) const74 CFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(CFWL_Widget* pWidget) const {
75   Item* pItem = GetWidgetMgrItem(pWidget);
76   if (!pItem)
77     return nullptr;
78 
79   pItem = pItem->pChild;
80   while (pItem && pItem->pNext)
81     pItem = pItem->pNext;
82   return pItem ? pItem->pWidget : nullptr;
83 }
84 
GetSystemFormWidget(CFWL_Widget * pWidget) const85 CFWL_Widget* CFWL_WidgetMgr::GetSystemFormWidget(CFWL_Widget* pWidget) const {
86   Item* pItem = GetWidgetMgrItem(pWidget);
87   while (pItem) {
88     if (IsAbleNative(pItem->pWidget))
89       return pItem->pWidget;
90     pItem = pItem->pParent;
91   }
92   return nullptr;
93 }
94 
AppendWidget(CFWL_Widget * pWidget)95 void CFWL_WidgetMgr::AppendWidget(CFWL_Widget* pWidget) {
96   Item* pItem = GetWidgetMgrItem(pWidget);
97   if (!pItem)
98     return;
99   if (!pItem->pParent)
100     return;
101 
102   Item* pChild = pItem->pParent->pChild;
103   int32_t i = 0;
104   while (pChild) {
105     if (pChild == pItem) {
106       if (pChild->pPrevious)
107         pChild->pPrevious->pNext = pChild->pNext;
108       if (pChild->pNext)
109         pChild->pNext->pPrevious = pChild->pPrevious;
110       if (pItem->pParent->pChild == pItem)
111         pItem->pParent->pChild = pItem->pNext;
112 
113       pItem->pNext = nullptr;
114       pItem->pPrevious = nullptr;
115       break;
116     }
117     if (!pChild->pNext)
118       break;
119 
120     pChild = pChild->pNext;
121     ++i;
122   }
123 
124   pChild = pItem->pParent->pChild;
125   if (pChild) {
126     while (pChild->pNext)
127       pChild = pChild->pNext;
128 
129     pChild->pNext = pItem;
130     pItem->pPrevious = pChild;
131   } else {
132     pItem->pParent->pChild = pItem;
133     pItem->pPrevious = nullptr;
134   }
135   pItem->pNext = nullptr;
136 }
137 
RepaintWidget(CFWL_Widget * pWidget,const CFX_RectF & rect)138 void CFWL_WidgetMgr::RepaintWidget(CFWL_Widget* pWidget,
139                                    const CFX_RectF& rect) {
140   CFWL_Widget* pNative = pWidget;
141   CFX_RectF transformedRect = rect;
142   CFWL_Widget* pOuter = pWidget->GetOuter();
143   while (pOuter) {
144     CFX_RectF rtTemp = pNative->GetWidgetRect();
145     transformedRect.left += rtTemp.left;
146     transformedRect.top += rtTemp.top;
147     pNative = pOuter;
148     pOuter = pOuter->GetOuter();
149   }
150   AddRedrawCounts(pNative);
151   m_pAdapter->RepaintWidget(pNative);
152 }
153 
InsertWidget(CFWL_Widget * pParent,CFWL_Widget * pChild)154 void CFWL_WidgetMgr::InsertWidget(CFWL_Widget* pParent, CFWL_Widget* pChild) {
155   Item* pParentItem = GetWidgetMgrItem(pParent);
156   if (!pParentItem) {
157     auto item = pdfium::MakeUnique<Item>(pParent);
158     pParentItem = item.get();
159     m_mapWidgetItem[pParent] = std::move(item);
160 
161     pParentItem->pParent = GetWidgetMgrItem(nullptr);
162     AppendWidget(pParent);
163   }
164 
165   Item* pItem = GetWidgetMgrItem(pChild);
166   if (!pItem) {
167     auto item = pdfium::MakeUnique<Item>(pChild);
168     pItem = item.get();
169     m_mapWidgetItem[pChild] = std::move(item);
170   }
171   if (pItem->pParent && pItem->pParent != pParentItem) {
172     if (pItem->pPrevious)
173       pItem->pPrevious->pNext = pItem->pNext;
174     if (pItem->pNext)
175       pItem->pNext->pPrevious = pItem->pPrevious;
176     if (pItem->pParent->pChild == pItem)
177       pItem->pParent->pChild = pItem->pNext;
178   }
179   pItem->pParent = pParentItem;
180   AppendWidget(pChild);
181 }
182 
RemoveWidget(CFWL_Widget * pWidget)183 void CFWL_WidgetMgr::RemoveWidget(CFWL_Widget* pWidget) {
184   Item* pItem = GetWidgetMgrItem(pWidget);
185   if (!pItem)
186     return;
187   if (pItem->pPrevious)
188     pItem->pPrevious->pNext = pItem->pNext;
189   if (pItem->pNext)
190     pItem->pNext->pPrevious = pItem->pPrevious;
191   if (pItem->pParent && pItem->pParent->pChild == pItem)
192     pItem->pParent->pChild = pItem->pNext;
193 
194   Item* pChild = pItem->pChild;
195   while (pChild) {
196     Item* pNext = pChild->pNext;
197     RemoveWidget(pChild->pWidget);
198     pChild = pNext;
199   }
200   m_mapWidgetItem.erase(pWidget);
201 }
202 
SetOwner(CFWL_Widget * pOwner,CFWL_Widget * pOwned)203 void CFWL_WidgetMgr::SetOwner(CFWL_Widget* pOwner, CFWL_Widget* pOwned) {
204   Item* pParentItem = GetWidgetMgrItem(pOwner);
205   if (!pParentItem) {
206     auto item = pdfium::MakeUnique<Item>(pOwner);
207     pParentItem = item.get();
208     m_mapWidgetItem[pOwner] = std::move(item);
209 
210     pParentItem->pParent = GetWidgetMgrItem(nullptr);
211     AppendWidget(pOwner);
212   }
213 
214   Item* pItem = GetWidgetMgrItem(pOwned);
215   if (!pItem) {
216     auto item = pdfium::MakeUnique<Item>(pOwned);
217     pItem = item.get();
218     m_mapWidgetItem[pOwned] = std::move(item);
219   }
220   pItem->pOwner = pParentItem;
221 }
SetParent(CFWL_Widget * pParent,CFWL_Widget * pChild)222 void CFWL_WidgetMgr::SetParent(CFWL_Widget* pParent, CFWL_Widget* pChild) {
223   Item* pParentItem = GetWidgetMgrItem(pParent);
224   Item* pItem = GetWidgetMgrItem(pChild);
225   if (!pItem)
226     return;
227   if (pItem->pParent && pItem->pParent != pParentItem) {
228     if (pItem->pPrevious)
229       pItem->pPrevious->pNext = pItem->pNext;
230     if (pItem->pNext)
231       pItem->pNext->pPrevious = pItem->pPrevious;
232     if (pItem->pParent->pChild == pItem)
233       pItem->pParent->pChild = pItem->pNext;
234 
235     pItem->pNext = nullptr;
236     pItem->pPrevious = nullptr;
237   }
238   pItem->pParent = pParentItem;
239   AppendWidget(pChild);
240 }
241 
GetWidgetAtPoint(CFWL_Widget * parent,const CFX_PointF & point) const242 CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent,
243                                               const CFX_PointF& point) const {
244   if (!parent)
245     return nullptr;
246 
247   CFWL_Widget* child = GetLastChildWidget(parent);
248   while (child) {
249     if (child->IsVisible()) {
250       CFX_PointF pos = parent->GetMatrix().GetInverse().Transform(point);
251       CFX_RectF bounds = child->GetWidgetRect();
252       if (bounds.Contains(pos)) {
253         pos -= bounds.TopLeft();
254         return GetWidgetAtPoint(child, pos);
255       }
256     }
257     child = GetPriorSiblingWidget(child);
258   }
259   return parent;
260 }
261 
GetDefaultButton(CFWL_Widget * pParent) const262 CFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(CFWL_Widget* pParent) const {
263   if ((pParent->GetClassID() == FWL_Type::PushButton) &&
264       (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
265     return pParent;
266   }
267 
268   CFWL_Widget* child =
269       pParent->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pParent);
270   while (child) {
271     if ((child->GetClassID() == FWL_Type::PushButton) &&
272         (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
273       return child;
274     }
275     if (CFWL_Widget* find = GetDefaultButton(child))
276       return find;
277 
278     child = child->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(child);
279   }
280   return nullptr;
281 }
282 
AddRedrawCounts(CFWL_Widget * pWidget)283 void CFWL_WidgetMgr::AddRedrawCounts(CFWL_Widget* pWidget) {
284   GetWidgetMgrItem(pWidget)->iRedrawCounter++;
285 }
286 
ResetRedrawCounts(CFWL_Widget * pWidget)287 void CFWL_WidgetMgr::ResetRedrawCounts(CFWL_Widget* pWidget) {
288   GetWidgetMgrItem(pWidget)->iRedrawCounter = 0;
289 }
290 
GetWidgetMgrItem(const CFWL_Widget * pWidget) const291 CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem(
292     const CFWL_Widget* pWidget) const {
293   auto it = m_mapWidgetItem.find(pWidget);
294   return it != m_mapWidgetItem.end() ? it->second.get() : nullptr;
295 }
296 
IsAbleNative(CFWL_Widget * pWidget) const297 bool CFWL_WidgetMgr::IsAbleNative(CFWL_Widget* pWidget) const {
298   if (!pWidget || !pWidget->IsForm())
299     return false;
300 
301   return pWidget->IsOverLapper() || pWidget->IsPopup();
302 }
303 
GetAdapterPopupPos(CFWL_Widget * pWidget,float fMinHeight,float fMaxHeight,const CFX_RectF & rtAnchor,CFX_RectF * pPopupRect) const304 void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget,
305                                         float fMinHeight,
306                                         float fMaxHeight,
307                                         const CFX_RectF& rtAnchor,
308                                         CFX_RectF* pPopupRect) const {
309   m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor,
310                           pPopupRect);
311 }
312 
OnProcessMessageToForm(std::unique_ptr<CFWL_Message> pMessage)313 void CFWL_WidgetMgr::OnProcessMessageToForm(
314     std::unique_ptr<CFWL_Message> pMessage) {
315   CFWL_Widget* pDstWidget = pMessage->GetDstTarget();
316   if (!pDstWidget)
317     return;
318 
319   CFWL_NoteDriver* pNoteDriver = pDstWidget->GetOwnerApp()->GetNoteDriver();
320   pNoteDriver->ProcessMessage(std::move(pMessage));
321 }
322 
OnDrawWidget(CFWL_Widget * pWidget,CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)323 void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget,
324                                   CXFA_Graphics* pGraphics,
325                                   const CFX_Matrix& matrix) {
326   if (!pWidget || !pGraphics)
327     return;
328 
329   CFX_RectF clipCopy(0, 0, pWidget->GetWidgetRect().Size());
330   CFX_RectF clipBounds;
331 
332   pWidget->GetDelegate()->OnDrawWidget(pGraphics, matrix);
333   clipBounds = pGraphics->GetClipRect();
334   clipCopy = clipBounds;
335 
336   if (!clipBounds.IsEmpty())
337     DrawChild(pWidget, clipBounds, pGraphics, &matrix);
338 
339   GetWidgetMgrItem(pWidget)->iRedrawCounter = 0;
340   ResetRedrawCounts(pWidget);
341 }
342 
DrawChild(CFWL_Widget * parent,const CFX_RectF & rtClip,CXFA_Graphics * pGraphics,const CFX_Matrix * pMatrix)343 void CFWL_WidgetMgr::DrawChild(CFWL_Widget* parent,
344                                const CFX_RectF& rtClip,
345                                CXFA_Graphics* pGraphics,
346                                const CFX_Matrix* pMatrix) {
347   if (!parent)
348     return;
349 
350   CFWL_Widget* pNextChild = GetFirstChildWidget(parent);
351   while (pNextChild) {
352     CFWL_Widget* child = pNextChild;
353     pNextChild = GetNextSiblingWidget(child);
354     if (!child->IsVisible())
355       continue;
356 
357     CFX_RectF rtWidget = child->GetWidgetRect();
358     if (rtWidget.IsEmpty())
359       continue;
360 
361     CFX_Matrix widgetMatrix;
362     CFX_RectF clipBounds(rtWidget);
363     if (pMatrix)
364       widgetMatrix.Concat(*pMatrix);
365 
366     widgetMatrix.TranslatePrepend(rtWidget.left, rtWidget.top);
367 
368     if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate())
369       pDelegate->OnDrawWidget(pGraphics, widgetMatrix);
370 
371     DrawChild(child, clipBounds, pGraphics, &widgetMatrix);
372   }
373 }
374 
Item()375 CFWL_WidgetMgr::Item::Item() : CFWL_WidgetMgr::Item(nullptr) {}
376 
Item(CFWL_Widget * widget)377 CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget)
378     : pParent(nullptr),
379       pOwner(nullptr),
380       pChild(nullptr),
381       pPrevious(nullptr),
382       pNext(nullptr),
383       pWidget(widget),
384       iRedrawCounter(0) {}
385 
~Item()386 CFWL_WidgetMgr::Item::~Item() {}
387