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