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 "build/build_config.h"
10 #include "third_party/base/check.h"
11 #include "xfa/fwl/cfwl_app.h"
12 #include "xfa/fwl/cfwl_message.h"
13 #include "xfa/fwl/cfwl_notedriver.h"
14
CFWL_WidgetMgr(AdapterIface * pAdapter,CFWL_App * pApp)15 CFWL_WidgetMgr::CFWL_WidgetMgr(AdapterIface* pAdapter, CFWL_App* pApp)
16 : m_pAdapter(pAdapter), m_pApp(pApp) {
17 DCHECK(m_pAdapter);
18 m_mapWidgetItem[nullptr] = cppgc::MakeGarbageCollected<Item>(
19 pApp->GetHeap()->GetAllocationHandle(), nullptr);
20 }
21
22 CFWL_WidgetMgr::~CFWL_WidgetMgr() = default;
23
Trace(cppgc::Visitor * visitor) const24 void CFWL_WidgetMgr::Trace(cppgc::Visitor* visitor) const {
25 visitor->Trace(m_pApp);
26 visitor->Trace(m_pAdapter);
27 for (auto& item : m_mapWidgetItem)
28 visitor->Trace(item.second);
29 }
30
GetParentWidget(const CFWL_Widget * pWidget) const31 CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(const CFWL_Widget* pWidget) const {
32 Item* pItem = GetWidgetMgrItem(pWidget);
33 if (!pItem)
34 return nullptr;
35
36 Item* pParent = pItem->GetParent();
37 return pParent ? pParent->pWidget : nullptr;
38 }
39
GetPriorSiblingWidget(CFWL_Widget * pWidget) const40 CFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(CFWL_Widget* pWidget) const {
41 Item* pItem = GetWidgetMgrItem(pWidget);
42 if (!pItem)
43 return nullptr;
44
45 Item* pSibling = pItem->GetPrevSibling();
46 return pSibling ? pSibling->pWidget : nullptr;
47 }
48
GetNextSiblingWidget(CFWL_Widget * pWidget) const49 CFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(CFWL_Widget* pWidget) const {
50 Item* pItem = GetWidgetMgrItem(pWidget);
51 if (!pItem)
52 return nullptr;
53
54 Item* pSibling = pItem->GetNextSibling();
55 return pSibling ? pSibling->pWidget : nullptr;
56 }
57
GetFirstChildWidget(CFWL_Widget * pWidget) const58 CFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(CFWL_Widget* pWidget) const {
59 Item* pItem = GetWidgetMgrItem(pWidget);
60 if (!pItem)
61 return nullptr;
62
63 Item* pChild = pItem->GetFirstChild();
64 return pChild ? pChild->pWidget : nullptr;
65 }
66
GetLastChildWidget(CFWL_Widget * pWidget) const67 CFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(CFWL_Widget* pWidget) const {
68 Item* pItem = GetWidgetMgrItem(pWidget);
69 if (!pItem)
70 return nullptr;
71
72 Item* pChild = pItem->GetLastChild();
73 return pChild ? pChild->pWidget : nullptr;
74 }
75
RepaintWidget(CFWL_Widget * pWidget,const CFX_RectF & rect)76 void CFWL_WidgetMgr::RepaintWidget(CFWL_Widget* pWidget,
77 const CFX_RectF& rect) {
78 CFWL_Widget* pNative = pWidget;
79 CFX_RectF transformedRect = rect;
80 CFWL_Widget* pOuter = pWidget->GetOuter();
81 while (pOuter) {
82 CFX_RectF rtTemp = pNative->GetWidgetRect();
83 transformedRect.left += rtTemp.left;
84 transformedRect.top += rtTemp.top;
85 pNative = pOuter;
86 pOuter = pOuter->GetOuter();
87 }
88 m_pAdapter->RepaintWidget(pNative);
89 }
90
InsertWidget(CFWL_Widget * pParent,CFWL_Widget * pChild)91 void CFWL_WidgetMgr::InsertWidget(CFWL_Widget* pParent, CFWL_Widget* pChild) {
92 Item* pParentItem = GetWidgetMgrItem(pParent);
93 if (!pParentItem) {
94 pParentItem = CreateWidgetMgrItem(pParent);
95 GetWidgetMgrRootItem()->AppendLastChild(pParentItem);
96 }
97 Item* pChildItem = GetWidgetMgrItem(pChild);
98 if (!pChildItem)
99 pChildItem = CreateWidgetMgrItem(pChild);
100 pParentItem->AppendLastChild(pChildItem);
101 }
102
RemoveWidget(CFWL_Widget * pWidget)103 void CFWL_WidgetMgr::RemoveWidget(CFWL_Widget* pWidget) {
104 DCHECK(pWidget);
105 Item* pItem = GetWidgetMgrItem(pWidget);
106 if (!pItem)
107 return;
108
109 while (pItem->GetFirstChild())
110 RemoveWidget(pItem->GetFirstChild()->pWidget);
111
112 pItem->RemoveSelfIfParented();
113 m_mapWidgetItem.erase(pWidget);
114 }
115
GetWidgetAtPoint(CFWL_Widget * parent,const CFX_PointF & point) const116 CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent,
117 const CFX_PointF& point) const {
118 if (!parent)
119 return nullptr;
120
121 CFWL_Widget* child = GetLastChildWidget(parent);
122 while (child) {
123 if (child->IsVisible()) {
124 CFX_PointF pos = parent->GetMatrix().GetInverse().Transform(point);
125 CFX_RectF bounds = child->GetWidgetRect();
126 if (bounds.Contains(pos)) {
127 pos -= bounds.TopLeft();
128 return GetWidgetAtPoint(child, pos);
129 }
130 }
131 child = GetPriorSiblingWidget(child);
132 }
133 return parent;
134 }
135
GetDefaultButton(CFWL_Widget * pParent) const136 CFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(CFWL_Widget* pParent) const {
137 if ((pParent->GetClassID() == FWL_Type::PushButton) &&
138 (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
139 return pParent;
140 }
141
142 CFWL_Widget* child = GetFirstChildWidget(pParent);
143 while (child) {
144 if ((child->GetClassID() == FWL_Type::PushButton) &&
145 (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
146 return child;
147 }
148 if (CFWL_Widget* find = GetDefaultButton(child))
149 return find;
150
151 child = GetNextSiblingWidget(child);
152 }
153 return nullptr;
154 }
155
GetWidgetMgrRootItem() const156 CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrRootItem() const {
157 return GetWidgetMgrItem(nullptr);
158 }
159
GetWidgetMgrItem(const CFWL_Widget * pWidget) const160 CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem(
161 const CFWL_Widget* pWidget) const {
162 auto it = m_mapWidgetItem.find(pWidget);
163 return it != m_mapWidgetItem.end() ? it->second : nullptr;
164 }
165
CreateWidgetMgrItem(CFWL_Widget * pWidget)166 CFWL_WidgetMgr::Item* CFWL_WidgetMgr::CreateWidgetMgrItem(
167 CFWL_Widget* pWidget) {
168 auto* pItem = cppgc::MakeGarbageCollected<Item>(
169 m_pApp->GetHeap()->GetAllocationHandle(), pWidget);
170 m_mapWidgetItem[pWidget] = pItem;
171 return pItem;
172 }
173
GetAdapterPopupPos(CFWL_Widget * pWidget,float fMinHeight,float fMaxHeight,const CFX_RectF & rtAnchor,CFX_RectF * pPopupRect) const174 void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget,
175 float fMinHeight,
176 float fMaxHeight,
177 const CFX_RectF& rtAnchor,
178 CFX_RectF* pPopupRect) const {
179 m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor,
180 pPopupRect);
181 }
182
OnProcessMessageToForm(CFWL_Message * pMessage)183 void CFWL_WidgetMgr::OnProcessMessageToForm(CFWL_Message* pMessage) {
184 CFWL_Widget* pDstWidget = pMessage->GetDstTarget();
185 if (!pDstWidget)
186 return;
187
188 CFWL_NoteDriver* pNoteDriver = pDstWidget->GetFWLApp()->GetNoteDriver();
189 pNoteDriver->ProcessMessage(pMessage);
190 }
191
OnDrawWidget(CFWL_Widget * pWidget,CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)192 void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget,
193 CFGAS_GEGraphics* pGraphics,
194 const CFX_Matrix& matrix) {
195 if (!pWidget || !pGraphics)
196 return;
197
198 pWidget->GetDelegate()->OnDrawWidget(pGraphics, matrix);
199
200 CFX_RectF clipBounds = pGraphics->GetClipRect();
201 if (!clipBounds.IsEmpty())
202 DrawChildren(pWidget, clipBounds, pGraphics, &matrix);
203 }
204
DrawChildren(CFWL_Widget * parent,const CFX_RectF & rtClip,CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)205 void CFWL_WidgetMgr::DrawChildren(CFWL_Widget* parent,
206 const CFX_RectF& rtClip,
207 CFGAS_GEGraphics* pGraphics,
208 const CFX_Matrix* pMatrix) {
209 if (!parent)
210 return;
211
212 CFWL_Widget* pNextChild = GetFirstChildWidget(parent);
213 while (pNextChild) {
214 CFWL_Widget* child = pNextChild;
215 pNextChild = GetNextSiblingWidget(child);
216 if (!child->IsVisible())
217 continue;
218
219 CFX_RectF rtWidget = child->GetWidgetRect();
220 if (rtWidget.IsEmpty())
221 continue;
222
223 CFX_Matrix widgetMatrix;
224 CFX_RectF clipBounds(rtWidget);
225 if (pMatrix)
226 widgetMatrix.Concat(*pMatrix);
227
228 widgetMatrix.TranslatePrepend(rtWidget.left, rtWidget.top);
229
230 if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate())
231 pDelegate->OnDrawWidget(pGraphics, widgetMatrix);
232
233 DrawChildren(child, clipBounds, pGraphics, &widgetMatrix);
234 }
235 }
236
Item(CFWL_Widget * widget)237 CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget) : pWidget(widget) {}
238
239 CFWL_WidgetMgr::Item::~Item() = default;
240
Trace(cppgc::Visitor * visitor) const241 void CFWL_WidgetMgr::Item::Trace(cppgc::Visitor* visitor) const {
242 GCedTreeNode<Item>::Trace(visitor);
243 visitor->Trace(pWidget);
244 }
245