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