1 // Copyright 2014 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 #ifndef XFA_FXFA_LAYOUT_CXFA_VIEWLAYOUTPROCESSOR_H_
8 #define XFA_FXFA_LAYOUT_CXFA_VIEWLAYOUTPROCESSOR_H_
9 
10 #include <iterator>
11 #include <list>
12 #include <map>
13 #include <memory>
14 #include <vector>
15 
16 #include "core/fxcrt/retain_ptr.h"
17 #include "third_party/base/optional.h"
18 #include "xfa/fxfa/layout/cxfa_contentlayoutprocessor.h"
19 
20 class CXFA_LayoutItem;
21 class CXFA_Node;
22 
23 class CXFA_ViewLayoutProcessor {
24  public:
25   struct BreakData {
26     CXFA_Node* pLeader;
27     CXFA_Node* pTrailer;
28     bool bCreatePage;
29   };
30 
31   struct OverflowData {
32     CXFA_Node* pLeader;
33     CXFA_Node* pTrailer;
34   };
35 
36   explicit CXFA_ViewLayoutProcessor(CXFA_LayoutProcessor* pLayoutProcessor);
37   ~CXFA_ViewLayoutProcessor();
38 
39   bool InitLayoutPage(CXFA_Node* pFormNode);
40   bool PrepareFirstPage(CXFA_Node* pRootSubform);
41   float GetAvailHeight();
42   bool GetNextAvailContentHeight(float fChildHeight);
43   void SubmitContentItem(
44       const RetainPtr<CXFA_ContentLayoutItem>& pContentLayoutItem,
45       CXFA_ContentLayoutProcessor::Result eStatus);
46   void FinishPaginatedPageSets();
47   void SyncLayoutData();
48   int32_t GetPageCount() const;
49   CXFA_ViewLayoutItem* GetPage(int32_t index) const;
50   int32_t GetPageIndex(const CXFA_ViewLayoutItem* pPage) const;
GetRootLayoutItem()51   CXFA_ViewLayoutItem* GetRootLayoutItem() const {
52     return m_pPageSetRootLayoutItem.Get();
53   }
54   Optional<BreakData> ProcessBreakBefore(const CXFA_Node* pBreakNode);
55   Optional<BreakData> ProcessBreakAfter(const CXFA_Node* pBreakNode);
56   Optional<OverflowData> ProcessOverflow(CXFA_Node* pFormNode,
57                                          bool bCreatePage);
58   CXFA_Node* QueryOverflow(CXFA_Node* pFormNode);
59   CXFA_Node* ProcessBookendLeader(const CXFA_Node* pBookendNode);
60   CXFA_Node* ProcessBookendTrailer(const CXFA_Node* pBookendNode);
61 
62  private:
63   struct CXFA_ViewRecord {
64     CXFA_ViewRecord();
65     ~CXFA_ViewRecord();
66 
67     RetainPtr<CXFA_ViewLayoutItem> pCurPageSet;
68     RetainPtr<CXFA_ViewLayoutItem> pCurPageArea;
69     RetainPtr<CXFA_ViewLayoutItem> pCurContentArea;
70   };
71 
72   using RecordList = std::list<std::unique_ptr<CXFA_ViewRecord>>;
73 
74   bool AppendNewPage(bool bFirstTemPage);
75   void ReorderPendingLayoutRecordToTail(CXFA_ViewRecord* pNewRecord,
76                                         CXFA_ViewRecord* pPrevRecord);
77   void RemoveLayoutRecord(CXFA_ViewRecord* pNewRecord,
78                           CXFA_ViewRecord* pPrevRecord);
HasCurrentViewRecord()79   bool HasCurrentViewRecord() const {
80     return m_CurrentViewRecordIter != m_ProposedViewRecords.end();
81   }
GetCurrentViewRecord()82   CXFA_ViewRecord* GetCurrentViewRecord() {
83     return m_CurrentViewRecordIter->get();
84   }
GetCurrentViewRecord()85   const CXFA_ViewRecord* GetCurrentViewRecord() const {
86     return m_CurrentViewRecordIter->get();
87   }
ResetToFirstViewRecord()88   void ResetToFirstViewRecord() {
89     m_CurrentViewRecordIter = m_ProposedViewRecords.begin();
90   }
GetTailPosition()91   RecordList::iterator GetTailPosition() {
92     auto iter = m_ProposedViewRecords.end();
93     return !m_ProposedViewRecords.empty() ? std::prev(iter) : iter;
94   }
95   CXFA_ViewRecord* AppendNewRecord(std::unique_ptr<CXFA_ViewRecord> pNewRecord);
96   CXFA_ViewRecord* CreateViewRecord(CXFA_Node* pPageNode, bool bCreateNew);
97   CXFA_ViewRecord* CreateViewRecordSimple();
98   void AddPageAreaLayoutItem(CXFA_ViewRecord* pNewRecord,
99                              CXFA_Node* pNewPageArea);
100   void AddContentAreaLayoutItem(CXFA_ViewRecord* pNewRecord,
101                                 CXFA_Node* pContentArea);
102   bool RunBreak(XFA_Element eBreakType,
103                 XFA_AttributeValue eTargetType,
104                 CXFA_Node* pTarget,
105                 bool bStartNew);
106   bool ShouldGetNextPageArea(CXFA_Node* pTarget, bool bStartNew) const;
107   bool BreakOverflow(const CXFA_Node* pOverflowNode,
108                      bool bCreatePage,
109                      CXFA_Node** pLeaderTemplate,
110                      CXFA_Node** pTrailerTemplate);
111   CXFA_Node* ProcessBookendLeaderOrTrailer(const CXFA_Node* pBookendNode,
112                                            bool bLeader);
113   CXFA_Node* ResolveBookendLeaderOrTrailer(const CXFA_Node* pBookendNode,
114                                            bool bLeader);
115   Optional<BreakData> ProcessBreakBeforeOrAfter(const CXFA_Node* pBreakNode,
116                                                 bool bBefore);
117   BreakData ExecuteBreakBeforeOrAfter(const CXFA_Node* pCurNode, bool bBefore);
118 
119   int32_t CreateMinPageRecord(CXFA_Node* pPageArea,
120                               bool bTargetPageArea,
121                               bool bCreateLast);
122   void CreateMinPageSetRecord(CXFA_Node* pPageSet, bool bCreateAll);
123   void CreateNextMinRecord(CXFA_Node* pRecordNode);
124   bool FindPageAreaFromPageSet(CXFA_Node* pPageSet,
125                                CXFA_Node* pStartChild,
126                                CXFA_Node* pTargetPageArea,
127                                CXFA_Node* pTargetContentArea,
128                                bool bNewPage,
129                                bool bQuery);
130   bool FindPageAreaFromPageSet_Ordered(CXFA_Node* pPageSet,
131                                        CXFA_Node* pStartChild,
132                                        CXFA_Node* pTargetPageArea,
133                                        CXFA_Node* pTargetContentArea,
134                                        bool bNewPage,
135                                        bool bQuery);
136   bool FindPageAreaFromPageSet_SimplexDuplex(
137       CXFA_Node* pPageSet,
138       CXFA_Node* pStartChild,
139       CXFA_Node* pTargetPageArea,
140       CXFA_Node* pTargetContentArea,
141       bool bNewPage,
142       bool bQuery,
143       XFA_AttributeValue ePreferredPosition);
144   bool MatchPageAreaOddOrEven(CXFA_Node* pPageArea);
145   CXFA_Node* GetNextAvailPageArea(CXFA_Node* pTargetPageArea,
146                                   CXFA_Node* pTargetContentArea,
147                                   bool bNewPage,
148                                   bool bQuery);
149   bool GetNextContentArea(CXFA_Node* pTargetContentArea);
150   void InitPageSetMap();
151   void ProcessLastPageSet();
IsPageSetRootOrderedOccurrence()152   bool IsPageSetRootOrderedOccurrence() const {
153     return m_ePageSetMode == XFA_AttributeValue::OrderedOccurrence;
154   }
155   void ClearData();
156   void MergePageSetContents();
157   void LayoutPageSetContents();
158   void PrepareLayout();
159   void SaveLayoutItemChildren(CXFA_LayoutItem* pParentLayoutItem);
160   void ProcessSimplexOrDuplexPageSets(CXFA_ViewLayoutItem* pPageSetLayoutItem,
161                                       bool bIsSimplex);
162 
163   CXFA_LayoutProcessor* m_pLayoutProcessor = nullptr;
164   CXFA_Node* m_pPageSetNode = nullptr;
165   RetainPtr<CXFA_ViewLayoutItem> m_pPageSetRootLayoutItem;
166   RetainPtr<CXFA_ViewLayoutItem> m_pPageSetCurLayoutItem;
167   RecordList m_ProposedViewRecords;
168   RecordList::iterator m_CurrentViewRecordIter;
169   CXFA_Node* m_pCurPageArea = nullptr;
170   int32_t m_nAvailPages = 0;
171   int32_t m_nCurPageCount = 0;
172   XFA_AttributeValue m_ePageSetMode = XFA_AttributeValue::OrderedOccurrence;
173   bool m_bCreateOverFlowPage = false;
174   std::map<CXFA_Node*, int32_t> m_pPageSetMap;
175   std::vector<RetainPtr<CXFA_ViewLayoutItem>> m_PageArray;
176 };
177 
178 #endif  // XFA_FXFA_LAYOUT_CXFA_VIEWLAYOUTPROCESSOR_H_
179