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 "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/parser/cxfa_contentlayoutitem.h"
13 #include "xfa/fxfa/parser/cxfa_document.h"
14 #include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h"
15 #include "xfa/fxfa/parser/cxfa_layoutpagemgr.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
CXFA_LayoutProcessor(CXFA_Document * pDocument)23 CXFA_LayoutProcessor::CXFA_LayoutProcessor(CXFA_Document* pDocument)
24 : m_pDocument(pDocument), m_nProgressCounter(0), m_bNeedLayout(true) {}
25
~CXFA_LayoutProcessor()26 CXFA_LayoutProcessor::~CXFA_LayoutProcessor() {}
27
GetDocument() const28 CXFA_Document* CXFA_LayoutProcessor::GetDocument() const {
29 return m_pDocument.Get();
30 }
31
StartLayout(bool bForceRestart)32 int32_t CXFA_LayoutProcessor::StartLayout(bool bForceRestart) {
33 if (!bForceRestart && !IsNeedLayout())
34 return 100;
35
36 m_pRootItemLayoutProcessor.reset();
37 m_nProgressCounter = 0;
38 CXFA_Node* pFormPacketNode =
39 ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Form));
40 if (!pFormPacketNode)
41 return -1;
42
43 CXFA_Subform* pFormRoot =
44 pFormPacketNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
45 if (!pFormRoot)
46 return -1;
47
48 if (!m_pLayoutPageMgr)
49 m_pLayoutPageMgr = pdfium::MakeUnique<CXFA_LayoutPageMgr>(this);
50 if (!m_pLayoutPageMgr->InitLayoutPage(pFormRoot))
51 return -1;
52
53 if (!m_pLayoutPageMgr->PrepareFirstPage(pFormRoot))
54 return -1;
55
56 m_pRootItemLayoutProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
57 pFormRoot, m_pLayoutPageMgr.get());
58 m_nProgressCounter = 1;
59 return 0;
60 }
61
DoLayout()62 int32_t CXFA_LayoutProcessor::DoLayout() {
63 if (m_nProgressCounter < 1)
64 return -1;
65
66 XFA_ItemLayoutProcessorResult eStatus;
67 CXFA_Node* pFormNode = m_pRootItemLayoutProcessor->GetFormNode();
68 float fPosX =
69 pFormNode->JSObject()->GetMeasure(XFA_Attribute::X).ToUnit(XFA_Unit::Pt);
70 float fPosY =
71 pFormNode->JSObject()->GetMeasure(XFA_Attribute::Y).ToUnit(XFA_Unit::Pt);
72 do {
73 float fAvailHeight = m_pLayoutPageMgr->GetAvailHeight();
74 eStatus = m_pRootItemLayoutProcessor->DoLayout(true, fAvailHeight,
75 fAvailHeight, nullptr);
76 if (eStatus != XFA_ItemLayoutProcessorResult::Done)
77 m_nProgressCounter++;
78
79 CXFA_ContentLayoutItem* pLayoutItem =
80 m_pRootItemLayoutProcessor->ExtractLayoutItem();
81 if (pLayoutItem)
82 pLayoutItem->m_sPos = CFX_PointF(fPosX, fPosY);
83
84 m_pLayoutPageMgr->SubmitContentItem(pLayoutItem, eStatus);
85 } while (eStatus != XFA_ItemLayoutProcessorResult::Done);
86
87 if (eStatus == XFA_ItemLayoutProcessorResult::Done) {
88 m_pLayoutPageMgr->FinishPaginatedPageSets();
89 m_pLayoutPageMgr->SyncLayoutData();
90 m_bNeedLayout = false;
91 m_rgChangedContainers.clear();
92 }
93 return 100 * (eStatus == XFA_ItemLayoutProcessorResult::Done
94 ? m_nProgressCounter
95 : m_nProgressCounter - 1) /
96 m_nProgressCounter;
97 }
98
IncrementLayout()99 bool CXFA_LayoutProcessor::IncrementLayout() {
100 if (m_bNeedLayout) {
101 StartLayout(true);
102 return DoLayout() == 100;
103 }
104 for (CXFA_Node* pNode : m_rgChangedContainers) {
105 CXFA_Node* pParentNode = pNode->GetContainerParent();
106 if (!pParentNode)
107 return false;
108 if (!CXFA_ItemLayoutProcessor::IncrementRelayoutNode(this, pNode,
109 pParentNode)) {
110 return false;
111 }
112 }
113 m_rgChangedContainers.clear();
114 return true;
115 }
116
CountPages() const117 int32_t CXFA_LayoutProcessor::CountPages() const {
118 return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPageCount() : 0;
119 }
120
GetPage(int32_t index) const121 CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetPage(int32_t index) const {
122 return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPage(index) : nullptr;
123 }
124
GetLayoutItem(CXFA_Node * pFormItem)125 CXFA_LayoutItem* CXFA_LayoutProcessor::GetLayoutItem(CXFA_Node* pFormItem) {
126 return pFormItem->JSObject()->GetLayoutItem();
127 }
128
AddChangedContainer(CXFA_Node * pContainer)129 void CXFA_LayoutProcessor::AddChangedContainer(CXFA_Node* pContainer) {
130 if (!pdfium::ContainsValue(m_rgChangedContainers, pContainer))
131 m_rgChangedContainers.push_back(pContainer);
132 }
133
GetRootLayoutItem() const134 CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetRootLayoutItem() const {
135 return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetRootLayoutItem() : nullptr;
136 }
137
IsNeedLayout()138 bool CXFA_LayoutProcessor::IsNeedLayout() {
139 return m_bNeedLayout || !m_rgChangedContainers.empty();
140 }
141