// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "xfa/fxfa/cxfa_ffpageview.h" #include <algorithm> #include <memory> #include <vector> #include "fxjs/xfa/cjx_object.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" #include "xfa/fxfa/cxfa_ffcheckbutton.h" #include "xfa/fxfa/cxfa_ffdoc.h" #include "xfa/fxfa/cxfa_ffdocview.h" #include "xfa/fxfa/cxfa_fffield.h" #include "xfa/fxfa/cxfa_ffimageedit.h" #include "xfa/fxfa/cxfa_ffpushbutton.h" #include "xfa/fxfa/cxfa_ffwidget.h" #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h" #include "xfa/fxfa/parser/cxfa_node.h" #include "xfa/fxfa/parser/cxfa_traversal.h" #include "xfa/fxfa/parser/cxfa_traverse.h" namespace { CFX_Matrix GetPageMatrix(const CFX_RectF& docPageRect, const CFX_Rect& devicePageRect, int32_t iRotate, uint32_t dwCoordinatesType) { ASSERT(iRotate >= 0 && iRotate <= 3); bool bFlipX = (dwCoordinatesType & 0x01) != 0; bool bFlipY = (dwCoordinatesType & 0x02) != 0; CFX_Matrix m((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 0); if (iRotate == 0 || iRotate == 2) { m.a *= (float)devicePageRect.width / docPageRect.width; m.d *= (float)devicePageRect.height / docPageRect.height; } else { m.a *= (float)devicePageRect.height / docPageRect.width; m.d *= (float)devicePageRect.width / docPageRect.height; } m.Rotate(iRotate * 1.57079632675f); switch (iRotate) { case 0: m.e = bFlipX ? (float)devicePageRect.right() : (float)devicePageRect.left; m.f = bFlipY ? (float)devicePageRect.bottom() : (float)devicePageRect.top; break; case 1: m.e = bFlipY ? (float)devicePageRect.left : (float)devicePageRect.right(); m.f = bFlipX ? (float)devicePageRect.bottom() : (float)devicePageRect.top; break; case 2: m.e = bFlipX ? (float)devicePageRect.left : (float)devicePageRect.right(); m.f = bFlipY ? (float)devicePageRect.top : (float)devicePageRect.bottom(); break; case 3: m.e = bFlipY ? (float)devicePageRect.right() : (float)devicePageRect.left; m.f = bFlipX ? (float)devicePageRect.top : (float)devicePageRect.bottom(); break; default: break; } return m; } bool PageWidgetFilter(CXFA_FFWidget* pWidget, uint32_t dwFilter, bool bTraversal, bool bIgnorerelevant) { CXFA_Node* pNode = pWidget->GetNode(); if (!!(dwFilter & XFA_WidgetStatus_Focused) && (!pNode || pNode->GetElementType() != XFA_Element::Field)) { return false; } uint32_t dwStatus = pWidget->GetStatus(); if (bTraversal && (dwStatus & XFA_WidgetStatus_Disabled)) return false; if (bIgnorerelevant) return !!(dwStatus & XFA_WidgetStatus_Visible); dwFilter &= (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable); return (dwFilter & dwStatus) == dwFilter; } bool IsLayoutElement(XFA_Element eElement, bool bLayoutContainer) { switch (eElement) { case XFA_Element::Draw: case XFA_Element::Field: case XFA_Element::InstanceManager: return !bLayoutContainer; case XFA_Element::Area: case XFA_Element::Subform: case XFA_Element::ExclGroup: case XFA_Element::SubformSet: case XFA_Element::PageArea: case XFA_Element::Form: return true; default: return false; } } } // namespace CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea) : CXFA_ContainerLayoutItem(pPageArea), m_pDocView(pDocView) {} CXFA_FFPageView::~CXFA_FFPageView() {} CXFA_FFDocView* CXFA_FFPageView::GetDocView() const { return m_pDocView.Get(); } CFX_RectF CXFA_FFPageView::GetPageViewRect() const { return CFX_RectF(0, 0, GetPageSize()); } CFX_Matrix CXFA_FFPageView::GetDisplayMatrix(const CFX_Rect& rtDisp, int32_t iRotate) const { return GetPageMatrix(CFX_RectF(0, 0, GetPageSize()), rtDisp, iRotate, 0); } std::unique_ptr<IXFA_WidgetIterator> CXFA_FFPageView::CreateWidgetIterator( uint32_t dwTraverseWay, uint32_t dwWidgetFilter) { switch (dwTraverseWay) { case XFA_TRAVERSEWAY_Tranvalse: return pdfium::MakeUnique<CXFA_FFTabOrderPageWidgetIterator>( this, dwWidgetFilter); case XFA_TRAVERSEWAY_Form: return pdfium::MakeUnique<CXFA_FFPageWidgetIterator>(this, dwWidgetFilter); } return nullptr; } CXFA_FFPageWidgetIterator::CXFA_FFPageWidgetIterator(CXFA_FFPageView* pPageView, uint32_t dwFilter) : m_pPageView(pPageView), m_dwFilter(dwFilter), m_sIterator(pPageView) { m_bIgnorerelevant = m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() < XFA_VERSION_205; } CXFA_FFPageWidgetIterator::~CXFA_FFPageWidgetIterator() {} void CXFA_FFPageWidgetIterator::Reset() { m_sIterator.Reset(); } CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToFirst() { m_sIterator.Reset(); for (CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent(); pLayoutItem; pLayoutItem = m_sIterator.MoveToNext()) { if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) { return hWidget; } } return nullptr; } CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToLast() { m_sIterator.SetCurrent(nullptr); return MoveToPrevious(); } CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToNext() { for (CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToNext(); pLayoutItem; pLayoutItem = m_sIterator.MoveToNext()) { if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) { return hWidget; } } return nullptr; } CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToPrevious() { for (CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToPrev(); pLayoutItem; pLayoutItem = m_sIterator.MoveToPrev()) { if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) { return hWidget; } } return nullptr; } CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetCurrentWidget() { CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent(); return pLayoutItem ? XFA_GetWidgetFromLayoutItem(pLayoutItem) : nullptr; } bool CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* hWidget) { return hWidget && m_sIterator.SetCurrent(hWidget); } CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetWidget( CXFA_LayoutItem* pLayoutItem) { CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem); if (!pWidget) return nullptr; if (!PageWidgetFilter(pWidget, m_dwFilter, false, m_bIgnorerelevant)) return nullptr; if (!pWidget->IsLoaded() && !!(pWidget->GetStatus() & XFA_WidgetStatus_Visible)) { if (!pWidget->LoadWidget()) return nullptr; } return pWidget; } void CXFA_TabParam::AppendTabParam(CXFA_TabParam* pParam) { m_Children.push_back(pParam->GetWidget()); m_Children.insert(m_Children.end(), pParam->GetChildren().begin(), pParam->GetChildren().end()); } void CXFA_TabParam::ClearChildren() { m_Children.clear(); } CXFA_FFTabOrderPageWidgetIterator::CXFA_FFTabOrderPageWidgetIterator( CXFA_FFPageView* pPageView, uint32_t dwFilter) : m_pPageView(pPageView), m_dwFilter(dwFilter), m_iCurWidget(-1) { m_bIgnorerelevant = m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() < XFA_VERSION_205; Reset(); } CXFA_FFTabOrderPageWidgetIterator::~CXFA_FFTabOrderPageWidgetIterator() {} void CXFA_FFTabOrderPageWidgetIterator::Reset() { CreateTabOrderWidgetArray(); m_iCurWidget = -1; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToFirst() { for (int32_t i = 0; i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) { if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, m_bIgnorerelevant)) { m_iCurWidget = i; return m_TabOrderWidgetArray[m_iCurWidget]; } } return nullptr; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToLast() { for (int32_t i = pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) - 1; i >= 0; i--) { if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, m_bIgnorerelevant)) { m_iCurWidget = i; return m_TabOrderWidgetArray[m_iCurWidget]; } } return nullptr; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToNext() { for (int32_t i = m_iCurWidget + 1; i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) { if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, m_bIgnorerelevant)) { m_iCurWidget = i; return m_TabOrderWidgetArray[m_iCurWidget]; } } m_iCurWidget = -1; return nullptr; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToPrevious() { for (int32_t i = m_iCurWidget - 1; i >= 0; i--) { if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, m_bIgnorerelevant)) { m_iCurWidget = i; return m_TabOrderWidgetArray[m_iCurWidget]; } } m_iCurWidget = -1; return nullptr; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget() { return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget] : nullptr; } bool CXFA_FFTabOrderPageWidgetIterator::SetCurrentWidget( CXFA_FFWidget* hWidget) { auto it = std::find(m_TabOrderWidgetArray.begin(), m_TabOrderWidgetArray.end(), hWidget); if (it == m_TabOrderWidgetArray.end()) return false; m_iCurWidget = it - m_TabOrderWidgetArray.begin(); return true; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetTraverseWidget( CXFA_FFWidget* pWidget) { CXFA_Traversal* pTraversal = pWidget->GetNode()->GetChild<CXFA_Traversal>( 0, XFA_Element::Traversal, false); if (pTraversal) { CXFA_Traverse* pTraverse = pTraversal->GetChild<CXFA_Traverse>(0, XFA_Element::Traverse, false); if (pTraverse) { Optional<WideString> traverseWidgetName = pTraverse->JSObject()->TryAttribute(XFA_Attribute::Ref, true); if (traverseWidgetName) return FindWidgetByName(*traverseWidgetName, pWidget); } } return nullptr; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::FindWidgetByName( const WideString& wsWidgetName, CXFA_FFWidget* pRefWidget) { return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget); } void CXFA_FFTabOrderPageWidgetIterator::CreateTabOrderWidgetArray() { m_TabOrderWidgetArray.clear(); std::vector<CXFA_FFWidget*> SpaceOrderWidgetArray; CreateSpaceOrderWidgetArray(&SpaceOrderWidgetArray); if (SpaceOrderWidgetArray.empty()) return; int32_t nWidgetCount = pdfium::CollectionSize<int32_t>(SpaceOrderWidgetArray); CXFA_FFWidget* hWidget = SpaceOrderWidgetArray[0]; while (pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) < nWidgetCount) { if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) { m_TabOrderWidgetArray.push_back(hWidget); CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc(); if (pWidgetAcc->GetUIType() == XFA_Element::ExclGroup) { auto it = std::find(SpaceOrderWidgetArray.begin(), SpaceOrderWidgetArray.end(), hWidget); int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end() ? it - SpaceOrderWidgetArray.begin() + 1 : 0; while (true) { CXFA_FFWidget* radio = SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount]; if (radio->GetNode()->GetExclGroupIfExists() != pWidgetAcc->GetNode()) break; if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) m_TabOrderWidgetArray.push_back(radio); iWidgetIndex++; } } if (CXFA_FFWidget* hTraverseWidget = GetTraverseWidget(hWidget)) { hWidget = hTraverseWidget; continue; } } auto it = std::find(SpaceOrderWidgetArray.begin(), SpaceOrderWidgetArray.end(), hWidget); int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end() ? it - SpaceOrderWidgetArray.begin() + 1 : 0; hWidget = SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount]; } } void CXFA_FFTabOrderPageWidgetIterator::OrderContainer( CXFA_LayoutItemIterator* sIterator, CXFA_LayoutItem* pContainerItem, CXFA_TabParam* pContainer, bool& bCurrentItem, bool& bContentArea, bool bMarsterPage) { std::vector<std::unique_ptr<CXFA_TabParam>> tabParams; CXFA_LayoutItem* pSearchItem = sIterator->MoveToNext(); while (pSearchItem) { if (!pSearchItem->IsContentLayoutItem()) { bContentArea = true; pSearchItem = sIterator->MoveToNext(); continue; } if (bMarsterPage && bContentArea) { break; } if (bMarsterPage || bContentArea) { CXFA_FFWidget* hWidget = GetWidget(pSearchItem); if (!hWidget) { pSearchItem = sIterator->MoveToNext(); continue; } if (pContainerItem && (pSearchItem->GetParent() != pContainerItem)) { bCurrentItem = true; break; } tabParams.push_back(pdfium::MakeUnique<CXFA_TabParam>(hWidget)); if (IsLayoutElement(pSearchItem->GetFormNode()->GetElementType(), true)) { OrderContainer(sIterator, pSearchItem, tabParams.back().get(), bCurrentItem, bContentArea, bMarsterPage); } } if (bCurrentItem) { pSearchItem = sIterator->GetCurrent(); bCurrentItem = false; } else { pSearchItem = sIterator->MoveToNext(); } } std::sort(tabParams.begin(), tabParams.end(), [](const std::unique_ptr<CXFA_TabParam>& arg1, const std::unique_ptr<CXFA_TabParam>& arg2) { const CFX_RectF& rt1 = arg1->GetWidget()->GetWidgetRect(); const CFX_RectF& rt2 = arg2->GetWidget()->GetWidgetRect(); if (rt1.top - rt2.top >= XFA_FLOAT_PERCISION) return rt1.top < rt2.top; return rt1.left < rt2.left; }); for (const auto& pParam : tabParams) pContainer->AppendTabParam(pParam.get()); } void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray( std::vector<CXFA_FFWidget*>* WidgetArray) { CXFA_LayoutItemIterator sIterator(m_pPageView); auto pParam = pdfium::MakeUnique<CXFA_TabParam>(nullptr); bool bCurrentItem = false; bool bContentArea = false; OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea); WidgetArray->insert(WidgetArray->end(), pParam->GetChildren().begin(), pParam->GetChildren().end()); sIterator.Reset(); bCurrentItem = false; bContentArea = false; pParam->ClearChildren(); OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea, true); WidgetArray->insert(WidgetArray->end(), pParam->GetChildren().begin(), pParam->GetChildren().end()); } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetWidget( CXFA_LayoutItem* pLayoutItem) { if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) { if (!pWidget->IsLoaded() && (pWidget->GetStatus() & XFA_WidgetStatus_Visible)) { pWidget->LoadWidget(); } return pWidget; } return nullptr; } CXFA_TabParam::CXFA_TabParam(CXFA_FFWidget* pWidget) : m_pWidget(pWidget) {} CXFA_TabParam::~CXFA_TabParam() {}