Home | History | Annotate | Download | only in fxfa
      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 
     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 
     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 
     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 
    112 CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea)
    113     : CXFA_ContainerLayoutItem(pPageArea), m_pDocView(pDocView) {}
    114 
    115 CXFA_FFPageView::~CXFA_FFPageView() {}
    116 
    117 CXFA_FFDocView* CXFA_FFPageView::GetDocView() const {
    118   return m_pDocView.Get();
    119 }
    120 
    121 CFX_RectF CXFA_FFPageView::GetPageViewRect() const {
    122   return CFX_RectF(0, 0, GetPageSize());
    123 }
    124 
    125 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 
    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 
    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 
    152 CXFA_FFPageWidgetIterator::~CXFA_FFPageWidgetIterator() {}
    153 
    154 void CXFA_FFPageWidgetIterator::Reset() {
    155   m_sIterator.Reset();
    156 }
    157 
    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 
    169 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToLast() {
    170   m_sIterator.SetCurrent(nullptr);
    171   return MoveToPrevious();
    172 }
    173 
    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 
    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 
    194 CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetCurrentWidget() {
    195   CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent();
    196   return pLayoutItem ? XFA_GetWidgetFromLayoutItem(pLayoutItem) : nullptr;
    197 }
    198 
    199 bool CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* hWidget) {
    200   return hWidget && m_sIterator.SetCurrent(hWidget);
    201 }
    202 
    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 
    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 
    226 void CXFA_TabParam::ClearChildren() {
    227   m_Children.clear();
    228 }
    229 
    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 
    240 CXFA_FFTabOrderPageWidgetIterator::~CXFA_FFTabOrderPageWidgetIterator() {}
    241 
    242 void CXFA_FFTabOrderPageWidgetIterator::Reset() {
    243   CreateTabOrderWidgetArray();
    244   m_iCurWidget = -1;
    245 }
    246 
    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 
    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 
    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 
    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 
    296 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget() {
    297   return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget] : nullptr;
    298 }
    299 
    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 
    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 }
    327 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::FindWidgetByName(
    328     const WideString& wsWidgetName,
    329     CXFA_FFWidget* pRefWidget) {
    330   return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget);
    331 }
    332 
    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 
    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 
    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 
    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 
    465 CXFA_TabParam::CXFA_TabParam(CXFA_FFWidget* pWidget) : m_pWidget(pWidget) {}
    466 
    467 CXFA_TabParam::~CXFA_TabParam() {}
    468