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