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/fxfa/cxfa_ffpageview.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12 
13 #include "fxjs/xfa/cjx_object.h"
14 #include "third_party/base/ptr_util.h"
15 #include "third_party/base/stl_util.h"
16 #include "xfa/fxfa/cxfa_ffcheckbutton.h"
17 #include "xfa/fxfa/cxfa_ffdoc.h"
18 #include "xfa/fxfa/cxfa_ffdocview.h"
19 #include "xfa/fxfa/cxfa_fffield.h"
20 #include "xfa/fxfa/cxfa_ffimageedit.h"
21 #include "xfa/fxfa/cxfa_ffpushbutton.h"
22 #include "xfa/fxfa/cxfa_ffwidget.h"
23 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
24 #include "xfa/fxfa/parser/cxfa_node.h"
25 #include "xfa/fxfa/parser/cxfa_traversal.h"
26 #include "xfa/fxfa/parser/cxfa_traverse.h"
27 
28 namespace {
29 
GetPageMatrix(const CFX_RectF & docPageRect,const CFX_Rect & devicePageRect,int32_t iRotate,uint32_t dwCoordinatesType)30 CFX_Matrix GetPageMatrix(const CFX_RectF& docPageRect,
31                          const CFX_Rect& devicePageRect,
32                          int32_t iRotate,
33                          uint32_t dwCoordinatesType) {
34   ASSERT(iRotate >= 0 && iRotate <= 3);
35 
36   bool bFlipX = (dwCoordinatesType & 0x01) != 0;
37   bool bFlipY = (dwCoordinatesType & 0x02) != 0;
38   CFX_Matrix m((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 0);
39   if (iRotate == 0 || iRotate == 2) {
40     m.a *= (float)devicePageRect.width / docPageRect.width;
41     m.d *= (float)devicePageRect.height / docPageRect.height;
42   } else {
43     m.a *= (float)devicePageRect.height / docPageRect.width;
44     m.d *= (float)devicePageRect.width / docPageRect.height;
45   }
46   m.Rotate(iRotate * 1.57079632675f);
47   switch (iRotate) {
48     case 0:
49       m.e = bFlipX ? (float)devicePageRect.right() : (float)devicePageRect.left;
50       m.f = bFlipY ? (float)devicePageRect.bottom() : (float)devicePageRect.top;
51       break;
52     case 1:
53       m.e = bFlipY ? (float)devicePageRect.left : (float)devicePageRect.right();
54       m.f = bFlipX ? (float)devicePageRect.bottom() : (float)devicePageRect.top;
55       break;
56     case 2:
57       m.e = bFlipX ? (float)devicePageRect.left : (float)devicePageRect.right();
58       m.f = bFlipY ? (float)devicePageRect.top : (float)devicePageRect.bottom();
59       break;
60     case 3:
61       m.e = bFlipY ? (float)devicePageRect.right() : (float)devicePageRect.left;
62       m.f = bFlipX ? (float)devicePageRect.top : (float)devicePageRect.bottom();
63       break;
64     default:
65       break;
66   }
67   return m;
68 }
69 
PageWidgetFilter(CXFA_FFWidget * pWidget,uint32_t dwFilter,bool bTraversal,bool bIgnorerelevant)70 bool PageWidgetFilter(CXFA_FFWidget* pWidget,
71                       uint32_t dwFilter,
72                       bool bTraversal,
73                       bool bIgnorerelevant) {
74   CXFA_Node* pNode = pWidget->GetNode();
75 
76   if (!!(dwFilter & XFA_WidgetStatus_Focused) &&
77       (!pNode || pNode->GetElementType() != XFA_Element::Field)) {
78     return false;
79   }
80 
81   uint32_t dwStatus = pWidget->GetStatus();
82   if (bTraversal && (dwStatus & XFA_WidgetStatus_Disabled))
83     return false;
84   if (bIgnorerelevant)
85     return !!(dwStatus & XFA_WidgetStatus_Visible);
86 
87   dwFilter &= (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable |
88                XFA_WidgetStatus_Printable);
89   return (dwFilter & dwStatus) == dwFilter;
90 }
91 
IsLayoutElement(XFA_Element eElement,bool bLayoutContainer)92 bool IsLayoutElement(XFA_Element eElement, bool bLayoutContainer) {
93   switch (eElement) {
94     case XFA_Element::Draw:
95     case XFA_Element::Field:
96     case XFA_Element::InstanceManager:
97       return !bLayoutContainer;
98     case XFA_Element::Area:
99     case XFA_Element::Subform:
100     case XFA_Element::ExclGroup:
101     case XFA_Element::SubformSet:
102     case XFA_Element::PageArea:
103     case XFA_Element::Form:
104       return true;
105     default:
106       return false;
107   }
108 }
109 
110 }  // namespace
111 
CXFA_FFPageView(CXFA_FFDocView * pDocView,CXFA_Node * pPageArea)112 CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea)
113     : CXFA_ContainerLayoutItem(pPageArea), m_pDocView(pDocView) {}
114 
~CXFA_FFPageView()115 CXFA_FFPageView::~CXFA_FFPageView() {}
116 
GetDocView() const117 CXFA_FFDocView* CXFA_FFPageView::GetDocView() const {
118   return m_pDocView.Get();
119 }
120 
GetPageViewRect() const121 CFX_RectF CXFA_FFPageView::GetPageViewRect() const {
122   return CFX_RectF(0, 0, GetPageSize());
123 }
124 
GetDisplayMatrix(const CFX_Rect & rtDisp,int32_t iRotate) const125 CFX_Matrix CXFA_FFPageView::GetDisplayMatrix(const CFX_Rect& rtDisp,
126                                              int32_t iRotate) const {
127   return GetPageMatrix(CFX_RectF(0, 0, GetPageSize()), rtDisp, iRotate, 0);
128 }
129 
CreateWidgetIterator(uint32_t dwTraverseWay,uint32_t dwWidgetFilter)130 std::unique_ptr<IXFA_WidgetIterator> CXFA_FFPageView::CreateWidgetIterator(
131     uint32_t dwTraverseWay,
132     uint32_t dwWidgetFilter) {
133   switch (dwTraverseWay) {
134     case XFA_TRAVERSEWAY_Tranvalse:
135       return pdfium::MakeUnique<CXFA_FFTabOrderPageWidgetIterator>(
136           this, dwWidgetFilter);
137     case XFA_TRAVERSEWAY_Form:
138       return pdfium::MakeUnique<CXFA_FFPageWidgetIterator>(this,
139                                                            dwWidgetFilter);
140   }
141   return nullptr;
142 }
143 
CXFA_FFPageWidgetIterator(CXFA_FFPageView * pPageView,uint32_t dwFilter)144 CXFA_FFPageWidgetIterator::CXFA_FFPageWidgetIterator(CXFA_FFPageView* pPageView,
145                                                      uint32_t dwFilter)
146     : m_pPageView(pPageView), m_dwFilter(dwFilter), m_sIterator(pPageView) {
147   m_bIgnorerelevant =
148       m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() <
149       XFA_VERSION_205;
150 }
151 
~CXFA_FFPageWidgetIterator()152 CXFA_FFPageWidgetIterator::~CXFA_FFPageWidgetIterator() {}
153 
Reset()154 void CXFA_FFPageWidgetIterator::Reset() {
155   m_sIterator.Reset();
156 }
157 
MoveToFirst()158 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToFirst() {
159   m_sIterator.Reset();
160   for (CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent(); pLayoutItem;
161        pLayoutItem = m_sIterator.MoveToNext()) {
162     if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) {
163       return hWidget;
164     }
165   }
166   return nullptr;
167 }
168 
MoveToLast()169 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToLast() {
170   m_sIterator.SetCurrent(nullptr);
171   return MoveToPrevious();
172 }
173 
MoveToNext()174 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToNext() {
175   for (CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToNext(); pLayoutItem;
176        pLayoutItem = m_sIterator.MoveToNext()) {
177     if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) {
178       return hWidget;
179     }
180   }
181   return nullptr;
182 }
183 
MoveToPrevious()184 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToPrevious() {
185   for (CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToPrev(); pLayoutItem;
186        pLayoutItem = m_sIterator.MoveToPrev()) {
187     if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) {
188       return hWidget;
189     }
190   }
191   return nullptr;
192 }
193 
GetCurrentWidget()194 CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetCurrentWidget() {
195   CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent();
196   return pLayoutItem ? XFA_GetWidgetFromLayoutItem(pLayoutItem) : nullptr;
197 }
198 
SetCurrentWidget(CXFA_FFWidget * hWidget)199 bool CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* hWidget) {
200   return hWidget && m_sIterator.SetCurrent(hWidget);
201 }
202 
GetWidget(CXFA_LayoutItem * pLayoutItem)203 CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetWidget(
204     CXFA_LayoutItem* pLayoutItem) {
205   CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem);
206   if (!pWidget)
207     return nullptr;
208 
209   if (!PageWidgetFilter(pWidget, m_dwFilter, false, m_bIgnorerelevant))
210     return nullptr;
211 
212   if (!pWidget->IsLoaded() &&
213       !!(pWidget->GetStatus() & XFA_WidgetStatus_Visible)) {
214     if (!pWidget->LoadWidget())
215       return nullptr;
216   }
217   return pWidget;
218 }
219 
AppendTabParam(CXFA_TabParam * pParam)220 void CXFA_TabParam::AppendTabParam(CXFA_TabParam* pParam) {
221   m_Children.push_back(pParam->GetWidget());
222   m_Children.insert(m_Children.end(), pParam->GetChildren().begin(),
223                     pParam->GetChildren().end());
224 }
225 
ClearChildren()226 void CXFA_TabParam::ClearChildren() {
227   m_Children.clear();
228 }
229 
CXFA_FFTabOrderPageWidgetIterator(CXFA_FFPageView * pPageView,uint32_t dwFilter)230 CXFA_FFTabOrderPageWidgetIterator::CXFA_FFTabOrderPageWidgetIterator(
231     CXFA_FFPageView* pPageView,
232     uint32_t dwFilter)
233     : m_pPageView(pPageView), m_dwFilter(dwFilter), m_iCurWidget(-1) {
234   m_bIgnorerelevant =
235       m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() <
236       XFA_VERSION_205;
237   Reset();
238 }
239 
~CXFA_FFTabOrderPageWidgetIterator()240 CXFA_FFTabOrderPageWidgetIterator::~CXFA_FFTabOrderPageWidgetIterator() {}
241 
Reset()242 void CXFA_FFTabOrderPageWidgetIterator::Reset() {
243   CreateTabOrderWidgetArray();
244   m_iCurWidget = -1;
245 }
246 
MoveToFirst()247 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToFirst() {
248   for (int32_t i = 0;
249        i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) {
250     if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
251                          m_bIgnorerelevant)) {
252       m_iCurWidget = i;
253       return m_TabOrderWidgetArray[m_iCurWidget];
254     }
255   }
256   return nullptr;
257 }
258 
MoveToLast()259 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToLast() {
260   for (int32_t i = pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) - 1;
261        i >= 0; i--) {
262     if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
263                          m_bIgnorerelevant)) {
264       m_iCurWidget = i;
265       return m_TabOrderWidgetArray[m_iCurWidget];
266     }
267   }
268   return nullptr;
269 }
270 
MoveToNext()271 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToNext() {
272   for (int32_t i = m_iCurWidget + 1;
273        i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) {
274     if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
275                          m_bIgnorerelevant)) {
276       m_iCurWidget = i;
277       return m_TabOrderWidgetArray[m_iCurWidget];
278     }
279   }
280   m_iCurWidget = -1;
281   return nullptr;
282 }
283 
MoveToPrevious()284 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToPrevious() {
285   for (int32_t i = m_iCurWidget - 1; i >= 0; i--) {
286     if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
287                          m_bIgnorerelevant)) {
288       m_iCurWidget = i;
289       return m_TabOrderWidgetArray[m_iCurWidget];
290     }
291   }
292   m_iCurWidget = -1;
293   return nullptr;
294 }
295 
GetCurrentWidget()296 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget() {
297   return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget] : nullptr;
298 }
299 
SetCurrentWidget(CXFA_FFWidget * hWidget)300 bool CXFA_FFTabOrderPageWidgetIterator::SetCurrentWidget(
301     CXFA_FFWidget* hWidget) {
302   auto it = std::find(m_TabOrderWidgetArray.begin(),
303                       m_TabOrderWidgetArray.end(), hWidget);
304   if (it == m_TabOrderWidgetArray.end())
305     return false;
306 
307   m_iCurWidget = it - m_TabOrderWidgetArray.begin();
308   return true;
309 }
310 
GetTraverseWidget(CXFA_FFWidget * pWidget)311 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetTraverseWidget(
312     CXFA_FFWidget* pWidget) {
313   CXFA_Traversal* pTraversal = pWidget->GetNode()->GetChild<CXFA_Traversal>(
314       0, XFA_Element::Traversal, false);
315   if (pTraversal) {
316     CXFA_Traverse* pTraverse =
317         pTraversal->GetChild<CXFA_Traverse>(0, XFA_Element::Traverse, false);
318     if (pTraverse) {
319       Optional<WideString> traverseWidgetName =
320           pTraverse->JSObject()->TryAttribute(XFA_Attribute::Ref, true);
321       if (traverseWidgetName)
322         return FindWidgetByName(*traverseWidgetName, pWidget);
323     }
324   }
325   return nullptr;
326 }
FindWidgetByName(const WideString & wsWidgetName,CXFA_FFWidget * pRefWidget)327 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::FindWidgetByName(
328     const WideString& wsWidgetName,
329     CXFA_FFWidget* pRefWidget) {
330   return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget);
331 }
332 
CreateTabOrderWidgetArray()333 void CXFA_FFTabOrderPageWidgetIterator::CreateTabOrderWidgetArray() {
334   m_TabOrderWidgetArray.clear();
335 
336   std::vector<CXFA_FFWidget*> SpaceOrderWidgetArray;
337   CreateSpaceOrderWidgetArray(&SpaceOrderWidgetArray);
338   if (SpaceOrderWidgetArray.empty())
339     return;
340 
341   int32_t nWidgetCount = pdfium::CollectionSize<int32_t>(SpaceOrderWidgetArray);
342   CXFA_FFWidget* hWidget = SpaceOrderWidgetArray[0];
343   while (pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) <
344          nWidgetCount) {
345     if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) {
346       m_TabOrderWidgetArray.push_back(hWidget);
347       CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc();
348       if (pWidgetAcc->GetUIType() == XFA_Element::ExclGroup) {
349         auto it = std::find(SpaceOrderWidgetArray.begin(),
350                             SpaceOrderWidgetArray.end(), hWidget);
351         int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end()
352                                    ? it - SpaceOrderWidgetArray.begin() + 1
353                                    : 0;
354         while (true) {
355           CXFA_FFWidget* radio =
356               SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount];
357           if (radio->GetNode()->GetExclGroupIfExists() != pWidgetAcc->GetNode())
358             break;
359           if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget))
360             m_TabOrderWidgetArray.push_back(radio);
361 
362           iWidgetIndex++;
363         }
364       }
365       if (CXFA_FFWidget* hTraverseWidget = GetTraverseWidget(hWidget)) {
366         hWidget = hTraverseWidget;
367         continue;
368       }
369     }
370     auto it = std::find(SpaceOrderWidgetArray.begin(),
371                         SpaceOrderWidgetArray.end(), hWidget);
372     int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end()
373                                ? it - SpaceOrderWidgetArray.begin() + 1
374                                : 0;
375     hWidget = SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount];
376   }
377 }
378 
OrderContainer(CXFA_LayoutItemIterator * sIterator,CXFA_LayoutItem * pContainerItem,CXFA_TabParam * pContainer,bool & bCurrentItem,bool & bContentArea,bool bMarsterPage)379 void CXFA_FFTabOrderPageWidgetIterator::OrderContainer(
380     CXFA_LayoutItemIterator* sIterator,
381     CXFA_LayoutItem* pContainerItem,
382     CXFA_TabParam* pContainer,
383     bool& bCurrentItem,
384     bool& bContentArea,
385     bool bMarsterPage) {
386   std::vector<std::unique_ptr<CXFA_TabParam>> tabParams;
387   CXFA_LayoutItem* pSearchItem = sIterator->MoveToNext();
388   while (pSearchItem) {
389     if (!pSearchItem->IsContentLayoutItem()) {
390       bContentArea = true;
391       pSearchItem = sIterator->MoveToNext();
392       continue;
393     }
394     if (bMarsterPage && bContentArea) {
395       break;
396     }
397     if (bMarsterPage || bContentArea) {
398       CXFA_FFWidget* hWidget = GetWidget(pSearchItem);
399       if (!hWidget) {
400         pSearchItem = sIterator->MoveToNext();
401         continue;
402       }
403       if (pContainerItem && (pSearchItem->GetParent() != pContainerItem)) {
404         bCurrentItem = true;
405         break;
406       }
407       tabParams.push_back(pdfium::MakeUnique<CXFA_TabParam>(hWidget));
408       if (IsLayoutElement(pSearchItem->GetFormNode()->GetElementType(), true)) {
409         OrderContainer(sIterator, pSearchItem, tabParams.back().get(),
410                        bCurrentItem, bContentArea, bMarsterPage);
411       }
412     }
413     if (bCurrentItem) {
414       pSearchItem = sIterator->GetCurrent();
415       bCurrentItem = false;
416     } else {
417       pSearchItem = sIterator->MoveToNext();
418     }
419   }
420   std::sort(tabParams.begin(), tabParams.end(),
421             [](const std::unique_ptr<CXFA_TabParam>& arg1,
422                const std::unique_ptr<CXFA_TabParam>& arg2) {
423               const CFX_RectF& rt1 = arg1->GetWidget()->GetWidgetRect();
424               const CFX_RectF& rt2 = arg2->GetWidget()->GetWidgetRect();
425               if (rt1.top - rt2.top >= XFA_FLOAT_PERCISION)
426                 return rt1.top < rt2.top;
427               return rt1.left < rt2.left;
428             });
429   for (const auto& pParam : tabParams)
430     pContainer->AppendTabParam(pParam.get());
431 }
432 
CreateSpaceOrderWidgetArray(std::vector<CXFA_FFWidget * > * WidgetArray)433 void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray(
434     std::vector<CXFA_FFWidget*>* WidgetArray) {
435   CXFA_LayoutItemIterator sIterator(m_pPageView);
436   auto pParam = pdfium::MakeUnique<CXFA_TabParam>(nullptr);
437   bool bCurrentItem = false;
438   bool bContentArea = false;
439   OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea);
440   WidgetArray->insert(WidgetArray->end(), pParam->GetChildren().begin(),
441                       pParam->GetChildren().end());
442 
443   sIterator.Reset();
444   bCurrentItem = false;
445   bContentArea = false;
446   pParam->ClearChildren();
447   OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea,
448                  true);
449   WidgetArray->insert(WidgetArray->end(), pParam->GetChildren().begin(),
450                       pParam->GetChildren().end());
451 }
452 
GetWidget(CXFA_LayoutItem * pLayoutItem)453 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetWidget(
454     CXFA_LayoutItem* pLayoutItem) {
455   if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) {
456     if (!pWidget->IsLoaded() &&
457         (pWidget->GetStatus() & XFA_WidgetStatus_Visible)) {
458       pWidget->LoadWidget();
459     }
460     return pWidget;
461   }
462   return nullptr;
463 }
464 
CXFA_TabParam(CXFA_FFWidget * pWidget)465 CXFA_TabParam::CXFA_TabParam(CXFA_FFWidget* pWidget) : m_pWidget(pWidget) {}
466 
~CXFA_TabParam()467 CXFA_TabParam::~CXFA_TabParam() {}
468