Home | History | Annotate | Download | only in app
      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 
     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 
     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 
     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 
    118 CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea)
    119     : CXFA_ContainerLayoutItem(pPageArea), m_pDocView(pDocView) {}
    120 
    121 CXFA_FFPageView::~CXFA_FFPageView() {}
    122 
    123 CXFA_FFDocView* CXFA_FFPageView::GetDocView() const {
    124   return m_pDocView;
    125 }
    126 
    127 CFX_RectF CXFA_FFPageView::GetPageViewRect() const {
    128   return CFX_RectF(0, 0, GetPageSize());
    129 }
    130 
    131 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 
    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 
    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 }
    157 CXFA_FFPageWidgetIterator::~CXFA_FFPageWidgetIterator() {}
    158 void CXFA_FFPageWidgetIterator::Reset() {
    159   m_sIterator.Reset();
    160 }
    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 }
    171 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToLast() {
    172   m_sIterator.SetCurrent(nullptr);
    173   return MoveToPrevious();
    174 }
    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 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 CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetCurrentWidget() {
    194   CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent();
    195   return pLayoutItem ? XFA_GetWidgetFromLayoutItem(pLayoutItem) : nullptr;
    196 }
    197 bool CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* hWidget) {
    198   return hWidget && m_sIterator.SetCurrent(hWidget);
    199 }
    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 
    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 
    225 CXFA_FFTabOrderPageWidgetIterator::~CXFA_FFTabOrderPageWidgetIterator() {}
    226 
    227 void CXFA_FFTabOrderPageWidgetIterator::Reset() {
    228   CreateTabOrderWidgetArray();
    229   m_iCurWidget = -1;
    230 }
    231 
    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 
    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 
    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 
    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 
    281 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget() {
    282   return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget] : nullptr;
    283 }
    284 
    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 
    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 }
    311 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::FindWidgetByName(
    312     const CFX_WideString& wsWidgetName,
    313     CXFA_FFWidget* pRefWidget) {
    314   return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget);
    315 }
    316 
    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 
    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 
    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 }
    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 
    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 
    466 CXFA_TabParam::CXFA_TabParam() : m_pWidget(nullptr) {}
    467 
    468 CXFA_TabParam::~CXFA_TabParam() {}
    469