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