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/layout/cxfa_layoutprocessor.h"
8 
9 #include "fxjs/xfa/cjx_object.h"
10 #include "third_party/base/ptr_util.h"
11 #include "third_party/base/stl_util.h"
12 #include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
13 #include "xfa/fxfa/layout/cxfa_contentlayoutprocessor.h"
14 #include "xfa/fxfa/layout/cxfa_viewlayoutprocessor.h"
15 #include "xfa/fxfa/parser/cxfa_document.h"
16 #include "xfa/fxfa/parser/cxfa_localemgr.h"
17 #include "xfa/fxfa/parser/cxfa_measurement.h"
18 #include "xfa/fxfa/parser/cxfa_node.h"
19 #include "xfa/fxfa/parser/cxfa_subform.h"
20 #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
21 #include "xfa/fxfa/parser/xfa_utils.h"
22 
23 // static
FromDocument(const CXFA_Document * pXFADoc)24 CXFA_LayoutProcessor* CXFA_LayoutProcessor::FromDocument(
25     const CXFA_Document* pXFADoc) {
26   return static_cast<CXFA_LayoutProcessor*>(pXFADoc->GetLayoutProcessor());
27 }
28 
29 CXFA_LayoutProcessor::CXFA_LayoutProcessor() = default;
30 
31 CXFA_LayoutProcessor::~CXFA_LayoutProcessor() = default;
32 
SetForceRelayout(bool bForceRestart)33 void CXFA_LayoutProcessor::SetForceRelayout(bool bForceRestart) {
34   m_bNeedLayout = bForceRestart;
35 }
36 
StartLayout(bool bForceRestart)37 int32_t CXFA_LayoutProcessor::StartLayout(bool bForceRestart) {
38   if (!bForceRestart && !NeedLayout())
39     return 100;
40 
41   m_pContentLayoutProcessor.reset();
42   m_nProgressCounter = 0;
43   CXFA_Node* pFormPacketNode =
44       ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Form));
45   if (!pFormPacketNode)
46     return -1;
47 
48   CXFA_Subform* pFormRoot =
49       pFormPacketNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
50   if (!pFormRoot)
51     return -1;
52 
53   if (!m_pViewLayoutProcessor)
54     m_pViewLayoutProcessor = pdfium::MakeUnique<CXFA_ViewLayoutProcessor>(this);
55   if (!m_pViewLayoutProcessor->InitLayoutPage(pFormRoot))
56     return -1;
57 
58   if (!m_pViewLayoutProcessor->PrepareFirstPage(pFormRoot))
59     return -1;
60 
61   m_pContentLayoutProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
62       pFormRoot, m_pViewLayoutProcessor.get());
63   m_nProgressCounter = 1;
64   return 0;
65 }
66 
DoLayout()67 int32_t CXFA_LayoutProcessor::DoLayout() {
68   if (m_nProgressCounter < 1)
69     return -1;
70 
71   CXFA_ContentLayoutProcessor::Result eStatus;
72   CXFA_Node* pFormNode = m_pContentLayoutProcessor->GetFormNode();
73   float fPosX =
74       pFormNode->JSObject()->GetMeasureInUnit(XFA_Attribute::X, XFA_Unit::Pt);
75   float fPosY =
76       pFormNode->JSObject()->GetMeasureInUnit(XFA_Attribute::Y, XFA_Unit::Pt);
77   do {
78     float fAvailHeight = m_pViewLayoutProcessor->GetAvailHeight();
79     eStatus =
80         m_pContentLayoutProcessor->DoLayout(true, fAvailHeight, fAvailHeight);
81     if (eStatus != CXFA_ContentLayoutProcessor::Result::kDone)
82       m_nProgressCounter++;
83 
84     RetainPtr<CXFA_ContentLayoutItem> pLayoutItem =
85         m_pContentLayoutProcessor->ExtractLayoutItem();
86     if (pLayoutItem)
87       pLayoutItem->m_sPos = CFX_PointF(fPosX, fPosY);
88 
89     m_pViewLayoutProcessor->SubmitContentItem(pLayoutItem, eStatus);
90   } while (eStatus != CXFA_ContentLayoutProcessor::Result::kDone);
91 
92   if (eStatus == CXFA_ContentLayoutProcessor::Result::kDone) {
93     m_pViewLayoutProcessor->FinishPaginatedPageSets();
94     m_pViewLayoutProcessor->SyncLayoutData();
95     m_bNeedLayout = false;
96     m_rgChangedContainers.clear();
97   }
98   return 100 *
99          (eStatus == CXFA_ContentLayoutProcessor::Result::kDone
100               ? m_nProgressCounter
101               : m_nProgressCounter - 1) /
102          m_nProgressCounter;
103 }
104 
IncrementLayout()105 bool CXFA_LayoutProcessor::IncrementLayout() {
106   if (m_bNeedLayout) {
107     StartLayout(true);
108     return DoLayout() == 100;
109   }
110   return m_rgChangedContainers.empty();
111 }
112 
CountPages() const113 int32_t CXFA_LayoutProcessor::CountPages() const {
114   return m_pViewLayoutProcessor ? m_pViewLayoutProcessor->GetPageCount() : 0;
115 }
116 
GetPage(int32_t index) const117 CXFA_ViewLayoutItem* CXFA_LayoutProcessor::GetPage(int32_t index) const {
118   return m_pViewLayoutProcessor ? m_pViewLayoutProcessor->GetPage(index)
119                                 : nullptr;
120 }
121 
GetLayoutItem(CXFA_Node * pFormItem)122 CXFA_LayoutItem* CXFA_LayoutProcessor::GetLayoutItem(CXFA_Node* pFormItem) {
123   return pFormItem->JSObject()->GetLayoutItem();
124 }
125 
AddChangedContainer(CXFA_Node * pContainer)126 void CXFA_LayoutProcessor::AddChangedContainer(CXFA_Node* pContainer) {
127   if (!pdfium::ContainsValue(m_rgChangedContainers, pContainer))
128     m_rgChangedContainers.push_back(pContainer);
129 }
130 
NeedLayout() const131 bool CXFA_LayoutProcessor::NeedLayout() const {
132   return m_bNeedLayout || !m_rgChangedContainers.empty();
133 }
134