Home | History | Annotate | Download | only in parser
      1 // Copyright 2016 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/parser/cxfa_layoutprocessor.h"
      8 
      9 #include "third_party/base/ptr_util.h"
     10 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
     11 #include "xfa/fxfa/parser/cxfa_document.h"
     12 #include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
     13 #include "xfa/fxfa/parser/cxfa_measurement.h"
     14 #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
     15 #include "xfa/fxfa/parser/xfa_layout_itemlayout.h"
     16 #include "xfa/fxfa/parser/xfa_localemgr.h"
     17 #include "xfa/fxfa/parser/xfa_object.h"
     18 #include "xfa/fxfa/parser/xfa_utils.h"
     19 
     20 CXFA_LayoutProcessor::CXFA_LayoutProcessor(CXFA_Document* pDocument)
     21     : m_pDocument(pDocument),
     22       m_nProgressCounter(0),
     23       m_bNeeLayout(true) {}
     24 
     25 CXFA_LayoutProcessor::~CXFA_LayoutProcessor() {}
     26 
     27 CXFA_Document* CXFA_LayoutProcessor::GetDocument() const {
     28   return m_pDocument;
     29 }
     30 
     31 int32_t CXFA_LayoutProcessor::StartLayout(bool bForceRestart) {
     32   if (!bForceRestart && !IsNeedLayout())
     33     return 100;
     34 
     35   m_pRootItemLayoutProcessor.reset();
     36   m_nProgressCounter = 0;
     37   CXFA_Node* pFormPacketNode =
     38       ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Form));
     39   if (!pFormPacketNode)
     40     return -1;
     41 
     42   CXFA_Node* pFormRoot =
     43       pFormPacketNode->GetFirstChildByClass(XFA_Element::Subform);
     44   if (!pFormRoot)
     45     return -1;
     46 
     47   if (!m_pLayoutPageMgr)
     48     m_pLayoutPageMgr = pdfium::MakeUnique<CXFA_LayoutPageMgr>(this);
     49   if (!m_pLayoutPageMgr->InitLayoutPage(pFormRoot))
     50     return -1;
     51 
     52   if (!m_pLayoutPageMgr->PrepareFirstPage(pFormRoot))
     53     return -1;
     54 
     55   m_pRootItemLayoutProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
     56       pFormRoot, m_pLayoutPageMgr.get());
     57   m_nProgressCounter = 1;
     58   return 0;
     59 }
     60 
     61 int32_t CXFA_LayoutProcessor::DoLayout(IFX_Pause* pPause) {
     62   if (m_nProgressCounter < 1)
     63     return -1;
     64 
     65   XFA_ItemLayoutProcessorResult eStatus;
     66   CXFA_Node* pFormNode = m_pRootItemLayoutProcessor->GetFormNode();
     67   FX_FLOAT fPosX = pFormNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt);
     68   FX_FLOAT fPosY = pFormNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt);
     69   do {
     70     FX_FLOAT fAvailHeight = m_pLayoutPageMgr->GetAvailHeight();
     71     eStatus = m_pRootItemLayoutProcessor->DoLayout(true, fAvailHeight,
     72                                                    fAvailHeight, nullptr);
     73     if (eStatus != XFA_ItemLayoutProcessorResult::Done)
     74       m_nProgressCounter++;
     75 
     76     CXFA_ContentLayoutItem* pLayoutItem =
     77         m_pRootItemLayoutProcessor->ExtractLayoutItem();
     78     if (pLayoutItem)
     79       pLayoutItem->m_sPos = CFX_PointF(fPosX, fPosY);
     80 
     81     m_pLayoutPageMgr->SubmitContentItem(pLayoutItem, eStatus);
     82   } while (eStatus != XFA_ItemLayoutProcessorResult::Done &&
     83            (!pPause || !pPause->NeedToPauseNow()));
     84 
     85   if (eStatus == XFA_ItemLayoutProcessorResult::Done) {
     86     m_pLayoutPageMgr->FinishPaginatedPageSets();
     87     m_pLayoutPageMgr->SyncLayoutData();
     88     m_bNeeLayout = false;
     89     m_rgChangedContainers.RemoveAll();
     90   }
     91   return 100 * (eStatus == XFA_ItemLayoutProcessorResult::Done
     92                     ? m_nProgressCounter
     93                     : m_nProgressCounter - 1) /
     94          m_nProgressCounter;
     95 }
     96 
     97 bool CXFA_LayoutProcessor::IncrementLayout() {
     98   if (m_bNeeLayout) {
     99     StartLayout(true);
    100     return DoLayout(nullptr) == 100;
    101   }
    102 
    103   for (int32_t i = 0, c = m_rgChangedContainers.GetSize(); i < c; i++) {
    104     CXFA_Node* pNode = m_rgChangedContainers[i];
    105     CXFA_Node* pParentNode =
    106         pNode->GetNodeItem(XFA_NODEITEM_Parent, XFA_ObjectType::ContainerNode);
    107     if (!pParentNode)
    108       return false;
    109     if (!CXFA_ItemLayoutProcessor::IncrementRelayoutNode(this, pNode,
    110                                                          pParentNode)) {
    111       return false;
    112     }
    113   }
    114   m_rgChangedContainers.RemoveAll();
    115   return true;
    116 }
    117 
    118 int32_t CXFA_LayoutProcessor::CountPages() const {
    119   return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPageCount() : 0;
    120 }
    121 
    122 CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetPage(int32_t index) const {
    123   return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPage(index) : nullptr;
    124 }
    125 
    126 CXFA_LayoutItem* CXFA_LayoutProcessor::GetLayoutItem(CXFA_Node* pFormItem) {
    127   return static_cast<CXFA_LayoutItem*>(
    128       pFormItem->GetUserData(XFA_LAYOUTITEMKEY));
    129 }
    130 
    131 void CXFA_LayoutProcessor::AddChangedContainer(CXFA_Node* pContainer) {
    132   if (m_rgChangedContainers.Find(pContainer) < 0)
    133     m_rgChangedContainers.Add(pContainer);
    134 }
    135 
    136 CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetRootLayoutItem() const {
    137   return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetRootLayoutItem() : nullptr;
    138 }
    139 
    140 bool CXFA_LayoutProcessor::IsNeedLayout() {
    141   return m_bNeeLayout || m_rgChangedContainers.GetSize() > 0;
    142 }
    143