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_CONTENTLAYOUTPROCESSOR_H_
8 #define XFA_FXFA_LAYOUT_CXFA_CONTENTLAYOUTPROCESSOR_H_
9 
10 #include <float.h>
11 
12 #include <list>
13 #include <map>
14 #include <utility>
15 #include <vector>
16 
17 #include "core/fxcrt/fx_coordinates.h"
18 #include "core/fxcrt/unowned_ptr.h"
19 #include "fxjs/gc/heap.h"
20 #include "third_party/base/optional.h"
21 #include "v8/include/cppgc/garbage-collected.h"
22 #include "v8/include/cppgc/macros.h"
23 #include "v8/include/cppgc/member.h"
24 #include "v8/include/cppgc/persistent.h"
25 #include "xfa/fxfa/fxfa_basic.h"
26 
27 constexpr float kXFALayoutPrecision = 0.0005f;
28 
29 class CXFA_ContentLayoutItem;
30 class CXFA_ContentLayoutProcessor;
31 class CXFA_LayoutProcessor;
32 class CXFA_Node;
33 class CXFA_ViewLayoutItem;
34 class CXFA_ViewLayoutProcessor;
35 
36 class CXFA_ContentLayoutProcessor
37     : public cppgc::GarbageCollected<CXFA_ContentLayoutProcessor> {
38  public:
39   enum class Result : uint8_t {
40     kDone,
41     kPageFullBreak,
42     kRowFullBreak,
43     kManualBreak,
44   };
45 
46   enum class Stage : uint8_t {
47     kNone,
48     kBookendLeader,
49     kBreakBefore,
50     kKeep,
51     kContainer,
52     kBreakAfter,
53     kBookendTrailer,
54     kDone,
55   };
56 
57   CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
58   ~CXFA_ContentLayoutProcessor();
59 
60   void Trace(cppgc::Visitor* visitor) const;
GetHeap()61   cppgc::Heap* GetHeap() const { return m_pHeap.Get(); }
62 
63   Result DoLayout(bool bUseBreakControl, float fHeightLimit, float fRealHeight);
64   void DoLayoutPageArea(CXFA_ViewLayoutItem* pPageAreaLayoutItem);
65 
GetFormNode()66   CXFA_Node* GetFormNode() { return m_pFormNode; }
67   CXFA_ContentLayoutItem* ExtractLayoutItem();
68 
69  private:
70   class Context {
71     CPPGC_STACK_ALLOCATED();  // Allows Raw/Unowned pointers.
72 
73    public:
74     Context();
75     ~Context();
76 
77     Optional<float> m_fCurColumnWidth;
78     UnownedPtr<std::vector<float>> m_prgSpecifiedColumnWidths;
79     UnownedPtr<CXFA_ContentLayoutProcessor> m_pOverflowProcessor;  // OK, stack
80     UnownedPtr<CXFA_Node> m_pOverflowNode;                         // Ok, stack
81   };
82 
83   CXFA_ContentLayoutProcessor(cppgc::Heap* pHeap,
84                               CXFA_Node* pNode,
85                               CXFA_ViewLayoutProcessor* pViewLayoutProcessor);
86 
87   Result DoLayoutInternal(bool bUseBreakControl,
88                           float fHeightLimit,
89                           float fRealHeight,
90                           Context* pContext);
91 
92   CFX_SizeF GetCurrentComponentSize();
HasLayoutItem()93   bool HasLayoutItem() const { return !!m_pLayoutItem; }
94   void SplitLayoutItem(float fSplitPos);
95   float FindSplitPos(float fProposedSplitPos);
96   bool ProcessKeepForSplit(
97       CXFA_ContentLayoutProcessor* pChildProcessor,
98       Result eRetValue,
99       std::vector<cppgc::Persistent<CXFA_ContentLayoutItem>>*
100           rgCurLineLayoutItem,
101       float* fContentCurRowAvailWidth,
102       float* fContentCurRowHeight,
103       float* fContentCurRowY,
104       bool* bAddedItemInRow,
105       bool* bForceEndPage,
106       Result* result);
107   void ProcessUnUseOverFlow(CXFA_Node* pLeaderNode,
108                             CXFA_Node* pTrailerNode,
109                             CXFA_ContentLayoutItem* pTrailerItem,
110                             CXFA_Node* pFormNode);
111   bool IsAddNewRowForTrailer(CXFA_ContentLayoutItem* pTrailerItem);
112   bool JudgeLeaderOrTrailerForOccur(CXFA_Node* pFormNode);
113 
114   // Object comes from GCed heap.
115   CXFA_ContentLayoutItem* CreateContentLayoutItem(CXFA_Node* pFormNode);
116 
117   void SetCurrentComponentPos(const CFX_PointF& pos);
118   void SetCurrentComponentSize(const CFX_SizeF& size);
119 
120   void SplitLayoutItem(CXFA_ContentLayoutItem* pLayoutItem,
121                        CXFA_ContentLayoutItem* pSecondParent,
122                        float fSplitPos);
123   float InsertKeepLayoutItems();
124   bool CalculateRowChildPosition(
125       std::vector<cppgc::Persistent<CXFA_ContentLayoutItem>> (
126           &rgCurLineLayoutItems)[3],
127       XFA_AttributeValue eFlowStrategy,
128       bool bContainerHeightAutoSize,
129       bool bContainerWidthAutoSize,
130       float* fContentCalculatedWidth,
131       float* fContentCalculatedHeight,
132       float* fContentCurRowY,
133       float fContentCurRowHeight,
134       float fContentWidthLimit,
135       bool bRootForceTb);
136   void ProcessUnUseBinds(CXFA_Node* pFormNode);
137   bool JudgePutNextPage(CXFA_ContentLayoutItem* pParentLayoutItem,
138                         float fChildHeight,
139                         std::vector<CXFA_ContentLayoutItem*>* pKeepItems);
140 
141   void DoLayoutPositionedContainer(Context* pContext);
142   void DoLayoutTableContainer(CXFA_Node* pLayoutNode);
143   Result DoLayoutFlowedContainer(bool bUseBreakControl,
144                                  XFA_AttributeValue eFlowStrategy,
145                                  float fHeightLimit,
146                                  float fRealHeight,
147                                  Context* pContext,
148                                  bool bRootForceTb);
149   void DoLayoutField();
150 
151   void GotoNextContainerNodeSimple(bool bUsePageBreak);
152 
153   // Return new stage and new action node.
154   std::pair<Stage, CXFA_Node*> GotoNextContainerNode(
155       Stage nCurStage,
156       bool bUsePageBreak,
157       CXFA_Node* pParentContainer,
158       CXFA_Node* pCurActionNode);
159 
160   Optional<Stage> ProcessKeepNodesForCheckNext(CXFA_Node** pCurActionNode,
161                                                CXFA_Node** pNextContainer,
162                                                bool* pLastKeepNode);
163 
164   Optional<Stage> ProcessKeepNodesForBreakBefore(CXFA_Node** pCurActionNode,
165                                                  CXFA_Node* pContainerNode);
166 
167   CXFA_Node* GetSubformSetParent(CXFA_Node* pSubformSet);
168 
169   void UpdatePendingItemLayout(CXFA_ContentLayoutItem* pLayoutItem);
170   void AddTrailerBeforeSplit(float fSplitPos,
171                              CXFA_ContentLayoutItem* pTrailerLayoutItem,
172                              bool bUseInherited);
173   void AddLeaderAfterSplit(CXFA_ContentLayoutItem* pLeaderLayoutItem);
174   void AddPendingNode(CXFA_Node* pPendingNode, bool bBreakPending);
175   float InsertPendingItems(CXFA_Node* pCurChildNode);
176   Result InsertFlowedItem(
177       CXFA_ContentLayoutProcessor* pProcessor,
178       bool bContainerWidthAutoSize,
179       bool bContainerHeightAutoSize,
180       float fContainerHeight,
181       XFA_AttributeValue eFlowStrategy,
182       uint8_t* uCurHAlignState,
183       std::vector<cppgc::Persistent<CXFA_ContentLayoutItem>> (
184           &rgCurLineLayoutItems)[3],
185       bool bUseBreakControl,
186       float fAvailHeight,
187       float fRealHeight,
188       float fContentWidthLimit,
189       float* fContentCurRowY,
190       float* fContentCurRowAvailWidth,
191       float* fContentCurRowHeight,
192       bool* bAddedItemInRow,
193       bool* bForceEndPage,
194       Context* pLayoutContext,
195       bool bNewRow);
196 
197   Optional<Stage> HandleKeep(CXFA_Node* pBreakAfterNode,
198                              CXFA_Node** pCurActionNode);
199   Optional<Stage> HandleBookendLeader(CXFA_Node* pParentContainer,
200                                       CXFA_Node** pCurActionNode);
201   Optional<Stage> HandleBreakBefore(CXFA_Node* pChildContainer,
202                                     CXFA_Node** pCurActionNode);
203   Optional<Stage> HandleBreakAfter(CXFA_Node* pChildContainer,
204                                    CXFA_Node** pCurActionNode);
205   Optional<Stage> HandleCheckNextChildContainer(CXFA_Node* pParentContainer,
206                                                 CXFA_Node* pChildContainer,
207                                                 CXFA_Node** pCurActionNode);
208   Optional<Stage> HandleBookendTrailer(CXFA_Node* pParentContainer,
209                                        CXFA_Node** pCurActionNode);
210   void ProcessKeepNodesEnd();
211   void AdjustContainerSpecifiedSize(Context* pContext,
212                                     CFX_SizeF* pSize,
213                                     bool* pContainerWidthAutoSize,
214                                     bool* pContainerHeightAutoSize);
215   CXFA_ContentLayoutItem* FindLastContentLayoutItem(
216       XFA_AttributeValue eFlowStrategy);
217   CFX_SizeF CalculateLayoutItemSize(const CXFA_ContentLayoutItem* pLayoutChild);
218 
219   Stage m_nCurChildNodeStage = Stage::kNone;
220   Result m_ePreProcessRs = Result::kDone;
221   bool m_bBreakPending = true;
222   bool m_bUseInherited = false;
223   bool m_bKeepBreakFinish = false;
224   bool m_bIsProcessKeep = false;
225   bool m_bHasAvailHeight = true;
226   float m_fUsedSize = 0;
227   float m_fLastRowWidth = 0;
228   float m_fLastRowY = 0;
229   float m_fWidthLimit = 0;
230   UnownedPtr<cppgc::Heap> m_pHeap;
231   cppgc::Member<CXFA_Node> const m_pFormNode;
232   cppgc::Member<CXFA_Node> m_pCurChildNode;
233   cppgc::Member<CXFA_Node> m_pKeepHeadNode;
234   cppgc::Member<CXFA_Node> m_pKeepTailNode;
235   cppgc::Member<CXFA_ContentLayoutItem> m_pLayoutItem;
236   cppgc::Member<CXFA_ContentLayoutItem> m_pOldLayoutItem;
237   cppgc::Member<CXFA_ViewLayoutProcessor> m_pViewLayoutProcessor;
238   std::vector<float> m_rgSpecifiedColumnWidths;
239   std::vector<cppgc::Member<CXFA_ContentLayoutItem>> m_ArrayKeepItems;
240   std::list<cppgc::Member<CXFA_Node>> m_PendingNodes;
241   std::map<CXFA_Node*, int32_t> m_PendingNodesCount;
242   cppgc::Member<CXFA_ContentLayoutProcessor> m_pCurChildPreprocessor;
243 };
244 
245 #endif  // XFA_FXFA_LAYOUT_CXFA_CONTENTLAYOUTPROCESSOR_H_
246