// 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/include/xfa_ffpageview.h" #include "xfa/fde/fde_render.h" #include "xfa/fxfa/app/xfa_ffcheckbutton.h" #include "xfa/fxfa/app/xfa_ffchoicelist.h" #include "xfa/fxfa/app/xfa_fffield.h" #include "xfa/fxfa/app/xfa_ffimageedit.h" #include "xfa/fxfa/app/xfa_ffpushbutton.h" #include "xfa/fxfa/app/xfa_fftextedit.h" #include "xfa/fxfa/app/xfa_fwladapter.h" #include "xfa/fxfa/include/xfa_ffdoc.h" #include "xfa/fxfa/include/xfa_ffdocview.h" #include "xfa/fxfa/include/xfa_ffwidget.h" namespace { void GetPageMatrix(CFX_Matrix& pageMatrix, const CFX_RectF& docPageRect, const CFX_Rect& devicePageRect, int32_t iRotate, uint32_t dwCoordinatesType) { ASSERT(iRotate >= 0 && iRotate <= 3); FX_BOOL bFlipX = (dwCoordinatesType & 0x01) != 0; FX_BOOL bFlipY = (dwCoordinatesType & 0x02) != 0; CFX_Matrix m; m.Set((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 0); if (iRotate == 0 || iRotate == 2) { m.a *= (FX_FLOAT)devicePageRect.width / docPageRect.width; m.d *= (FX_FLOAT)devicePageRect.height / docPageRect.height; } else { m.a *= (FX_FLOAT)devicePageRect.height / docPageRect.width; m.d *= (FX_FLOAT)devicePageRect.width / docPageRect.height; } m.Rotate(iRotate * 1.57079632675f); switch (iRotate) { case 0: m.e = bFlipX ? (FX_FLOAT)devicePageRect.right() : (FX_FLOAT)devicePageRect.left; m.f = bFlipY ? (FX_FLOAT)devicePageRect.bottom() : (FX_FLOAT)devicePageRect.top; break; case 1: m.e = bFlipY ? (FX_FLOAT)devicePageRect.left : (FX_FLOAT)devicePageRect.right(); m.f = bFlipX ? (FX_FLOAT)devicePageRect.bottom() : (FX_FLOAT)devicePageRect.top; break; case 2: m.e = bFlipX ? (FX_FLOAT)devicePageRect.left : (FX_FLOAT)devicePageRect.right(); m.f = bFlipY ? (FX_FLOAT)devicePageRect.top : (FX_FLOAT)devicePageRect.bottom(); break; case 3: m.e = bFlipY ? (FX_FLOAT)devicePageRect.right() : (FX_FLOAT)devicePageRect.left; m.f = bFlipX ? (FX_FLOAT)devicePageRect.top : (FX_FLOAT)devicePageRect.bottom(); break; default: break; } pageMatrix = m; } bool PageWidgetFilter(CXFA_FFWidget* pWidget, uint32_t dwFilter, FX_BOOL bTraversal, FX_BOOL bIgnorerelevant) { CXFA_WidgetAcc* pWidgetAcc = pWidget->GetDataAcc(); if (!!(dwFilter & XFA_WidgetStatus_Focused) && pWidgetAcc->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; } void CXFA_FFPageView::GetPageViewRect(CFX_RectF& rtPage) const { CFX_SizeF sz; GetPageSize(sz); rtPage.Set(0, 0, sz); } void CXFA_FFPageView::GetDisplayMatrix(CFX_Matrix& mt, const CFX_Rect& rtDisp, int32_t iRotate) const { CFX_SizeF sz; GetPageSize(sz); CFX_RectF fdePage; fdePage.Set(0, 0, sz.x, sz.y); GetPageMatrix(mt, fdePage, rtDisp, iRotate, 0); } IXFA_WidgetIterator* CXFA_FFPageView::CreateWidgetIterator( uint32_t dwTraverseWay, uint32_t dwWidgetFilter) { switch (dwTraverseWay) { case XFA_TRAVERSEWAY_Tranvalse: return new CXFA_FFTabOrderPageWidgetIterator(this, dwWidgetFilter); case XFA_TRAVERSEWAY_Form: return new CXFA_FFPageWidgetIterator(this, dwWidgetFilter); } return nullptr; } CXFA_FFPageWidgetIterator::CXFA_FFPageWidgetIterator(CXFA_FFPageView* pPageView, uint32_t dwFilter) { m_pPageView = pPageView; m_dwFilter = dwFilter; m_sIterator.Init(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; } FX_BOOL CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* hWidget) { return hWidget && m_sIterator.SetCurrent(hWidget); } CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetWidget( CXFA_LayoutItem* pLayoutItem) { if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) { if (!PageWidgetFilter(pWidget, m_dwFilter, FALSE, m_bIgnorerelevant)) { return nullptr; } if (!pWidget->IsLoaded() && (pWidget->GetStatus() & XFA_WidgetStatus_Visible) != 0) { pWidget->LoadWidget(); } return pWidget; } return nullptr; } 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() { if (m_TabOrderWidgetArray.GetSize() > 0) { for (int32_t i = 0; i < m_TabOrderWidgetArray.GetSize(); 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() { if (m_TabOrderWidgetArray.GetSize() > 0) { for (int32_t i = m_TabOrderWidgetArray.GetSize() - 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 < m_TabOrderWidgetArray.GetSize(); 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() { if (m_iCurWidget >= 0) { return m_TabOrderWidgetArray[m_iCurWidget]; } return nullptr; } FX_BOOL CXFA_FFTabOrderPageWidgetIterator::SetCurrentWidget( CXFA_FFWidget* hWidget) { int32_t iWidgetIndex = m_TabOrderWidgetArray.Find(hWidget); if (iWidgetIndex >= 0) { m_iCurWidget = iWidgetIndex; return TRUE; } return FALSE; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetTraverseWidget( CXFA_FFWidget* pWidget) { CXFA_WidgetAcc* pAcc = pWidget->GetDataAcc(); CXFA_Node* pTraversal = pAcc->GetNode()->GetChild(0, XFA_Element::Traversal); if (pTraversal) { CXFA_Node* pTraverse = pTraversal->GetChild(0, XFA_Element::Traverse); if (pTraverse) { CFX_WideString wsTraverseWidgetName; if (pTraverse->GetAttribute(XFA_ATTRIBUTE_Ref, wsTraverseWidgetName)) { return FindWidgetByName(wsTraverseWidgetName, pWidget); } } } return nullptr; } CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::FindWidgetByName( const CFX_WideString& wsWidgetName, CXFA_FFWidget* pRefWidget) { return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget); } void CXFA_FFTabOrderPageWidgetIterator::CreateTabOrderWidgetArray() { m_TabOrderWidgetArray.RemoveAll(); CXFA_WidgetArray SpaceOrderWidgetArray; CreateSpaceOrderWidgetArray(SpaceOrderWidgetArray); int32_t nWidgetCount = SpaceOrderWidgetArray.GetSize(); if (nWidgetCount < 1) { return; } CXFA_FFWidget* hWidget = SpaceOrderWidgetArray[0]; for (; m_TabOrderWidgetArray.GetSize() < nWidgetCount;) { if (m_TabOrderWidgetArray.Find(hWidget) < 0) { m_TabOrderWidgetArray.Add(hWidget); CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc(); if (pWidgetAcc->GetUIType() == XFA_Element::ExclGroup) { int32_t iWidgetIndex = SpaceOrderWidgetArray.Find(hWidget) + 1; while (TRUE) { CXFA_FFWidget* pRadio = SpaceOrderWidgetArray[(iWidgetIndex) % nWidgetCount]; if (pRadio->GetDataAcc()->GetExclGroup() != pWidgetAcc) { break; } if (m_TabOrderWidgetArray.Find(hWidget) < 0) { m_TabOrderWidgetArray.Add(pRadio); } iWidgetIndex++; } } if (CXFA_FFWidget* hTraverseWidget = GetTraverseWidget(hWidget)) { hWidget = hTraverseWidget; continue; } } int32_t iWidgetIndex = SpaceOrderWidgetArray.Find(hWidget); hWidget = SpaceOrderWidgetArray[(iWidgetIndex + 1) % nWidgetCount]; } } static int32_t XFA_TabOrderWidgetComparator(const void* phWidget1, const void* phWidget2) { CXFA_FFWidget* pWidget1 = (*(CXFA_TabParam**)phWidget1)->m_pWidget; CXFA_FFWidget* pWidget2 = (*(CXFA_TabParam**)phWidget2)->m_pWidget; CFX_RectF rt1, rt2; pWidget1->GetWidgetRect(rt1); pWidget2->GetWidgetRect(rt2); FX_FLOAT x1 = rt1.left, y1 = rt1.top, x2 = rt2.left, y2 = rt2.top; if (y1 < y2 || (y1 - y2 < XFA_FLOAT_PERCISION && x1 < x2)) { return -1; } return 1; } void CXFA_FFTabOrderPageWidgetIterator::OrderContainer( CXFA_LayoutItemIterator* sIterator, CXFA_LayoutItem* pContainerItem, CXFA_TabParam* pContainer, FX_BOOL& bCurrentItem, FX_BOOL& bContentArea, FX_BOOL bMarsterPage) { CFX_ArrayTemplate 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; } CXFA_TabParam* pParam = new CXFA_TabParam; pParam->m_pWidget = hWidget; tabParams.Add(pParam); if (IsLayoutElement(pSearchItem->GetFormNode()->GetElementType(), true)) { OrderContainer(sIterator, pSearchItem, pParam, bCurrentItem, bContentArea, bMarsterPage); } } if (bCurrentItem) { pSearchItem = sIterator->GetCurrent(); bCurrentItem = FALSE; } else { pSearchItem = sIterator->MoveToNext(); } } int32_t iChildren = tabParams.GetSize(); if (iChildren > 1) { FXSYS_qsort(tabParams.GetData(), iChildren, sizeof(void*), XFA_TabOrderWidgetComparator); } for (int32_t iStart = 0; iStart < iChildren; iStart++) { CXFA_TabParam* pParam = tabParams[iStart]; pContainer->m_Children.Add(pParam->m_pWidget); if (pParam->m_Children.GetSize() > 0) { pContainer->m_Children.Append(pParam->m_Children); } delete pParam; } tabParams.RemoveAll(); } void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray( CXFA_WidgetArray& WidgetArray) { CXFA_LayoutItemIterator sIterator; sIterator.Init(m_pPageView); CXFA_TabParam* pParam = new CXFA_TabParam; FX_BOOL bCurrentItem = FALSE; FX_BOOL bContentArea = FALSE; OrderContainer(&sIterator, nullptr, pParam, bCurrentItem, bContentArea); if (pParam->m_Children.GetSize() > 0) { WidgetArray.Append(pParam->m_Children); } sIterator.Reset(); bCurrentItem = FALSE; bContentArea = FALSE; pParam->m_Children.RemoveAll(); OrderContainer(&sIterator, nullptr, pParam, bCurrentItem, bContentArea, TRUE); if (pParam->m_Children.GetSize() > 0) { WidgetArray.Append(pParam->m_Children); } delete pParam; } 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() : m_pWidget(nullptr) {} CXFA_TabParam::~CXFA_TabParam() {}