• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "fxjs/xfa/cjx_object.h"
15 #include "third_party/base/logging.h"
16 #include "third_party/base/ptr_util.h"
17 #include "third_party/base/stl_util.h"
18 #include "xfa/fxfa/cxfa_ffnotify.h"
19 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
20 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
21 #include "xfa/fxfa/parser/cxfa_document.h"
22 #include "xfa/fxfa/parser/cxfa_keep.h"
23 #include "xfa/fxfa/parser/cxfa_layoutcontext.h"
24 #include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
25 #include "xfa/fxfa/parser/cxfa_localemgr.h"
26 #include "xfa/fxfa/parser/cxfa_margin.h"
27 #include "xfa/fxfa/parser/cxfa_measurement.h"
28 #include "xfa/fxfa/parser/cxfa_node.h"
29 #include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
30 #include "xfa/fxfa/parser/cxfa_occur.h"
31 #include "xfa/fxfa/parser/cxfa_para.h"
32 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
33 #include "xfa/fxfa/parser/xfa_utils.h"
34 
35 namespace {
36 
SeparateStringW(const wchar_t * pStr,int32_t iStrLen,wchar_t delimiter)37 std::vector<WideString> SeparateStringW(const wchar_t* pStr,
38                                         int32_t iStrLen,
39                                         wchar_t delimiter) {
40   std::vector<WideString> ret;
41   if (!pStr)
42     return ret;
43   if (iStrLen < 0)
44     iStrLen = wcslen(pStr);
45 
46   const wchar_t* pToken = pStr;
47   const wchar_t* pEnd = pStr + iStrLen;
48   while (true) {
49     if (pStr >= pEnd || delimiter == *pStr) {
50       ret.push_back(WideString(pToken, pStr - pToken));
51       pToken = pStr + 1;
52       if (pStr >= pEnd)
53         break;
54     }
55     pStr++;
56   }
57   return ret;
58 }
59 
UpdateWidgetSize(CXFA_ContentLayoutItem * pLayoutItem,float * fWidth,float * fHeight)60 void UpdateWidgetSize(CXFA_ContentLayoutItem* pLayoutItem,
61                       float* fWidth,
62                       float* fHeight) {
63   CXFA_Node* pNode = pLayoutItem->m_pFormNode;
64   switch (pNode->GetElementType()) {
65     case XFA_Element::Subform:
66     case XFA_Element::Area:
67     case XFA_Element::ExclGroup:
68     case XFA_Element::SubformSet: {
69       if (*fWidth < -XFA_LAYOUT_FLOAT_PERCISION)
70         *fWidth = pLayoutItem->m_sSize.width;
71       if (*fHeight < -XFA_LAYOUT_FLOAT_PERCISION)
72         *fHeight = pLayoutItem->m_sSize.height;
73       break;
74     }
75     case XFA_Element::Draw:
76     case XFA_Element::Field: {
77       pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, *fWidth,
78                                                               *fHeight);
79       break;
80     }
81     default:
82       NOTREACHED();
83   }
84 }
85 
CalculateContainerSpecifiedSize(CXFA_Node * pFormNode,bool * bContainerWidthAutoSize,bool * bContainerHeightAutoSize)86 CFX_SizeF CalculateContainerSpecifiedSize(CXFA_Node* pFormNode,
87                                           bool* bContainerWidthAutoSize,
88                                           bool* bContainerHeightAutoSize) {
89   *bContainerWidthAutoSize = true;
90   *bContainerHeightAutoSize = true;
91 
92   XFA_Element eType = pFormNode->GetElementType();
93 
94   CFX_SizeF containerSize;
95   if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) {
96     Optional<CXFA_Measurement> wValue =
97         pFormNode->JSObject()->TryMeasure(XFA_Attribute::W, false);
98     if (wValue && wValue->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
99       containerSize.width = wValue->ToUnit(XFA_Unit::Pt);
100       *bContainerWidthAutoSize = false;
101     }
102 
103     Optional<CXFA_Measurement> hValue =
104         pFormNode->JSObject()->TryMeasure(XFA_Attribute::H, false);
105     if (hValue && hValue->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
106       containerSize.height = hValue->ToUnit(XFA_Unit::Pt);
107       *bContainerHeightAutoSize = false;
108     }
109   }
110 
111   if (*bContainerWidthAutoSize && eType == XFA_Element::Subform) {
112     Optional<CXFA_Measurement> maxW =
113         pFormNode->JSObject()->TryMeasure(XFA_Attribute::MaxW, false);
114     if (maxW && maxW->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
115       containerSize.width = maxW->ToUnit(XFA_Unit::Pt);
116       *bContainerWidthAutoSize = false;
117     }
118 
119     Optional<CXFA_Measurement> maxH =
120         pFormNode->JSObject()->TryMeasure(XFA_Attribute::MaxH, false);
121     if (maxH && maxH->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
122       containerSize.height = maxH->ToUnit(XFA_Unit::Pt);
123       *bContainerHeightAutoSize = false;
124     }
125   }
126   return containerSize;
127 }
128 
CalculateContainerComponentSizeFromContentSize(CXFA_Node * pFormNode,bool bContainerWidthAutoSize,float fContentCalculatedWidth,bool bContainerHeightAutoSize,float fContentCalculatedHeight,const CFX_SizeF & currentContainerSize)129 CFX_SizeF CalculateContainerComponentSizeFromContentSize(
130     CXFA_Node* pFormNode,
131     bool bContainerWidthAutoSize,
132     float fContentCalculatedWidth,
133     bool bContainerHeightAutoSize,
134     float fContentCalculatedHeight,
135     const CFX_SizeF& currentContainerSize) {
136   CFX_SizeF componentSize = currentContainerSize;
137   CXFA_Margin* pMarginNode =
138       pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
139   if (bContainerWidthAutoSize) {
140     componentSize.width = fContentCalculatedWidth;
141     if (pMarginNode) {
142       Optional<CXFA_Measurement> leftInset =
143           pMarginNode->JSObject()->TryMeasure(XFA_Attribute::LeftInset, false);
144       if (leftInset)
145         componentSize.width += leftInset->ToUnit(XFA_Unit::Pt);
146 
147       Optional<CXFA_Measurement> rightInset =
148           pMarginNode->JSObject()->TryMeasure(XFA_Attribute::RightInset, false);
149       if (rightInset)
150         componentSize.width += rightInset->ToUnit(XFA_Unit::Pt);
151     }
152   }
153 
154   if (bContainerHeightAutoSize) {
155     componentSize.height = fContentCalculatedHeight;
156     if (pMarginNode) {
157       Optional<CXFA_Measurement> topInset =
158           pMarginNode->JSObject()->TryMeasure(XFA_Attribute::TopInset, false);
159       if (topInset)
160         componentSize.height += topInset->ToUnit(XFA_Unit::Pt);
161 
162       Optional<CXFA_Measurement> bottomInset =
163           pMarginNode->JSObject()->TryMeasure(XFA_Attribute::BottomInset,
164                                               false);
165       if (bottomInset)
166         componentSize.height += bottomInset->ToUnit(XFA_Unit::Pt);
167     }
168   }
169   return componentSize;
170 }
171 
RelocateTableRowCells(CXFA_ContentLayoutItem * pLayoutRow,const std::vector<float> & rgSpecifiedColumnWidths,XFA_AttributeEnum eLayout)172 void RelocateTableRowCells(CXFA_ContentLayoutItem* pLayoutRow,
173                            const std::vector<float>& rgSpecifiedColumnWidths,
174                            XFA_AttributeEnum eLayout) {
175   bool bContainerWidthAutoSize = true;
176   bool bContainerHeightAutoSize = true;
177   CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
178       pLayoutRow->m_pFormNode, &bContainerWidthAutoSize,
179       &bContainerHeightAutoSize);
180   CXFA_Margin* pMarginNode =
181       pLayoutRow->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
182           XFA_Element::Margin);
183   float fLeftInset = 0;
184   float fTopInset = 0;
185   float fRightInset = 0;
186   float fBottomInset = 0;
187   if (pMarginNode) {
188     fLeftInset = pMarginNode->JSObject()
189                      ->GetMeasure(XFA_Attribute::LeftInset)
190                      .ToUnit(XFA_Unit::Pt);
191     fTopInset = pMarginNode->JSObject()
192                     ->GetMeasure(XFA_Attribute::TopInset)
193                     .ToUnit(XFA_Unit::Pt);
194     fRightInset = pMarginNode->JSObject()
195                       ->GetMeasure(XFA_Attribute::RightInset)
196                       .ToUnit(XFA_Unit::Pt);
197     fBottomInset = pMarginNode->JSObject()
198                        ->GetMeasure(XFA_Attribute::BottomInset)
199                        .ToUnit(XFA_Unit::Pt);
200   }
201 
202   float fContentWidthLimit =
203       bContainerWidthAutoSize ? FLT_MAX
204                               : containerSize.width - fLeftInset - fRightInset;
205   float fContentCurrentHeight =
206       pLayoutRow->m_sSize.height - fTopInset - fBottomInset;
207   float fContentCalculatedWidth = 0;
208   float fContentCalculatedHeight = 0;
209   float fCurrentColX = 0;
210   int32_t nCurrentColIdx = 0;
211   bool bMetWholeRowCell = false;
212 
213   for (auto* pLayoutChild =
214            static_cast<CXFA_ContentLayoutItem*>(pLayoutRow->m_pFirstChild);
215        pLayoutChild; pLayoutChild = static_cast<CXFA_ContentLayoutItem*>(
216                          pLayoutChild->m_pNextSibling)) {
217     int32_t nOriginalColSpan =
218         pLayoutChild->m_pFormNode->JSObject()->GetInteger(
219             XFA_Attribute::ColSpan);
220     int32_t nColSpan = nOriginalColSpan;
221     float fColSpanWidth = 0;
222     if (nColSpan == -1 ||
223         nCurrentColIdx + nColSpan >
224             pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths)) {
225       nColSpan = pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths) -
226                  nCurrentColIdx;
227     }
228     for (int32_t i = 0; i < nColSpan; i++)
229       fColSpanWidth += rgSpecifiedColumnWidths[nCurrentColIdx + i];
230 
231     if (nColSpan != nOriginalColSpan) {
232       fColSpanWidth =
233           bMetWholeRowCell ? 0 : std::max(fColSpanWidth,
234                                           pLayoutChild->m_sSize.height);
235     }
236     if (nOriginalColSpan == -1)
237       bMetWholeRowCell = true;
238 
239     pLayoutChild->m_sPos = CFX_PointF(fCurrentColX, 0);
240     pLayoutChild->m_sSize.width = fColSpanWidth;
241     if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
242       continue;
243 
244     fCurrentColX += fColSpanWidth;
245     nCurrentColIdx += nColSpan;
246     float fNewHeight = bContainerHeightAutoSize ? -1 : fContentCurrentHeight;
247     UpdateWidgetSize(pLayoutChild, &fColSpanWidth, &fNewHeight);
248     pLayoutChild->m_sSize.height = fNewHeight;
249     if (bContainerHeightAutoSize) {
250       fContentCalculatedHeight =
251           std::max(fContentCalculatedHeight, pLayoutChild->m_sSize.height);
252     }
253   }
254 
255   if (bContainerHeightAutoSize) {
256     for (CXFA_ContentLayoutItem* pLayoutChild =
257              (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
258          pLayoutChild;
259          pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
260       UpdateWidgetSize(pLayoutChild, &pLayoutChild->m_sSize.width,
261                        &fContentCalculatedHeight);
262       float fOldChildHeight = pLayoutChild->m_sSize.height;
263       pLayoutChild->m_sSize.height = fContentCalculatedHeight;
264       CXFA_Para* pParaNode =
265           pLayoutChild->m_pFormNode->GetFirstChildByClass<CXFA_Para>(
266               XFA_Element::Para);
267       if (pParaNode && pLayoutChild->m_pFirstChild) {
268         float fOffHeight = fContentCalculatedHeight - fOldChildHeight;
269         XFA_AttributeEnum eVType =
270             pParaNode->JSObject()->GetEnum(XFA_Attribute::VAlign);
271         switch (eVType) {
272           case XFA_AttributeEnum::Middle:
273             fOffHeight = fOffHeight / 2;
274             break;
275           case XFA_AttributeEnum::Bottom:
276             break;
277           case XFA_AttributeEnum::Top:
278           default:
279             fOffHeight = 0;
280             break;
281         }
282         if (fOffHeight > 0) {
283           for (CXFA_ContentLayoutItem* pInnerLayoutChild =
284                    (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild;
285                pInnerLayoutChild;
286                pInnerLayoutChild =
287                    (CXFA_ContentLayoutItem*)pInnerLayoutChild->m_pNextSibling) {
288             pInnerLayoutChild->m_sPos.y += fOffHeight;
289           }
290         }
291       }
292     }
293   }
294 
295   if (bContainerWidthAutoSize) {
296     float fChildSuppliedWidth = fCurrentColX;
297     if (fContentWidthLimit < FLT_MAX &&
298         fContentWidthLimit > fChildSuppliedWidth) {
299       fChildSuppliedWidth = fContentWidthLimit;
300     }
301     fContentCalculatedWidth =
302         std::max(fContentCalculatedWidth, fChildSuppliedWidth);
303   } else {
304     fContentCalculatedWidth = containerSize.width - fLeftInset - fRightInset;
305   }
306 
307   if (pLayoutRow->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout) ==
308       XFA_AttributeEnum::Rl_row) {
309     for (CXFA_ContentLayoutItem* pLayoutChild =
310              (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
311          pLayoutChild;
312          pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
313       pLayoutChild->m_sPos.x = fContentCalculatedWidth -
314                                pLayoutChild->m_sPos.x -
315                                pLayoutChild->m_sSize.width;
316     }
317   }
318   pLayoutRow->m_sSize = CalculateContainerComponentSizeFromContentSize(
319       pLayoutRow->m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
320       bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
321 }
322 
UpdatePendingItemLayout(CXFA_ItemLayoutProcessor * pProcessor,CXFA_ContentLayoutItem * pLayoutItem)323 void UpdatePendingItemLayout(CXFA_ItemLayoutProcessor* pProcessor,
324                              CXFA_ContentLayoutItem* pLayoutItem) {
325   XFA_AttributeEnum eLayout =
326       pLayoutItem->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
327   switch (eLayout) {
328     case XFA_AttributeEnum::Row:
329     case XFA_AttributeEnum::Rl_row:
330       RelocateTableRowCells(pLayoutItem, pProcessor->m_rgSpecifiedColumnWidths,
331                             eLayout);
332       break;
333     default:
334       break;
335   }
336 }
337 
AddTrailerBeforeSplit(CXFA_ItemLayoutProcessor * pProcessor,float fSplitPos,CXFA_ContentLayoutItem * pTrailerLayoutItem,bool bUseInherited)338 void AddTrailerBeforeSplit(CXFA_ItemLayoutProcessor* pProcessor,
339                            float fSplitPos,
340                            CXFA_ContentLayoutItem* pTrailerLayoutItem,
341                            bool bUseInherited) {
342   if (!pTrailerLayoutItem)
343     return;
344 
345   float fHeight = pTrailerLayoutItem->m_sSize.height;
346   if (bUseInherited) {
347     float fNewSplitPos = 0;
348     if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION)
349       fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
350     if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION)
351       pProcessor->SplitLayoutItem(fNewSplitPos);
352     return;
353   }
354 
355   UpdatePendingItemLayout(pProcessor, pTrailerLayoutItem);
356   CXFA_Margin* pMarginNode =
357       pProcessor->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
358           XFA_Element::Margin);
359   float fLeftInset = 0;
360   float fTopInset = 0;
361   float fRightInset = 0;
362   float fBottomInset = 0;
363   if (pMarginNode) {
364     fLeftInset = pMarginNode->JSObject()
365                      ->GetMeasure(XFA_Attribute::LeftInset)
366                      .ToUnit(XFA_Unit::Pt);
367     fTopInset = pMarginNode->JSObject()
368                     ->GetMeasure(XFA_Attribute::TopInset)
369                     .ToUnit(XFA_Unit::Pt);
370     fRightInset = pMarginNode->JSObject()
371                       ->GetMeasure(XFA_Attribute::RightInset)
372                       .ToUnit(XFA_Unit::Pt);
373     fBottomInset = pMarginNode->JSObject()
374                        ->GetMeasure(XFA_Attribute::BottomInset)
375                        .ToUnit(XFA_Unit::Pt);
376   }
377 
378   if (!pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem)) {
379     pTrailerLayoutItem->m_sPos.y = pProcessor->m_fLastRowY;
380     pTrailerLayoutItem->m_sPos.x = pProcessor->m_fLastRowWidth;
381     pProcessor->m_pLayoutItem->m_sSize.width +=
382         pTrailerLayoutItem->m_sSize.width;
383     pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
384     return;
385   }
386 
387   float fNewSplitPos = 0;
388   if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION)
389     fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
390 
391   if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
392     pProcessor->SplitLayoutItem(fNewSplitPos);
393     pTrailerLayoutItem->m_sPos.y = fNewSplitPos - fTopInset - fBottomInset;
394   } else {
395     pTrailerLayoutItem->m_sPos.y = fSplitPos - fTopInset - fBottomInset;
396   }
397 
398   switch (pTrailerLayoutItem->m_pFormNode->JSObject()->GetEnum(
399       XFA_Attribute::HAlign)) {
400     case XFA_AttributeEnum::Right:
401       pTrailerLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width -
402                                      fRightInset -
403                                      pTrailerLayoutItem->m_sSize.width;
404       break;
405     case XFA_AttributeEnum::Center:
406       pTrailerLayoutItem->m_sPos.x =
407           (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset -
408            pTrailerLayoutItem->m_sSize.width) /
409           2;
410       break;
411     case XFA_AttributeEnum::Left:
412     default:
413       pTrailerLayoutItem->m_sPos.x = fLeftInset;
414       break;
415   }
416   pProcessor->m_pLayoutItem->m_sSize.height += fHeight;
417   pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
418 }
419 
AddLeaderAfterSplit(CXFA_ItemLayoutProcessor * pProcessor,CXFA_ContentLayoutItem * pLeaderLayoutItem)420 void AddLeaderAfterSplit(CXFA_ItemLayoutProcessor* pProcessor,
421                          CXFA_ContentLayoutItem* pLeaderLayoutItem) {
422   UpdatePendingItemLayout(pProcessor, pLeaderLayoutItem);
423 
424   CXFA_Margin* pMarginNode =
425       pProcessor->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
426           XFA_Element::Margin);
427   float fLeftInset = 0;
428   float fRightInset = 0;
429   if (pMarginNode) {
430     fLeftInset = pMarginNode->JSObject()
431                      ->GetMeasure(XFA_Attribute::LeftInset)
432                      .ToUnit(XFA_Unit::Pt);
433     fRightInset = pMarginNode->JSObject()
434                       ->GetMeasure(XFA_Attribute::RightInset)
435                       .ToUnit(XFA_Unit::Pt);
436   }
437 
438   float fHeight = pLeaderLayoutItem->m_sSize.height;
439   for (CXFA_ContentLayoutItem* pChildItem =
440            (CXFA_ContentLayoutItem*)pProcessor->m_pLayoutItem->m_pFirstChild;
441        pChildItem;
442        pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
443     pChildItem->m_sPos.y += fHeight;
444   }
445   pLeaderLayoutItem->m_sPos.y = 0;
446 
447   switch (pLeaderLayoutItem->m_pFormNode->JSObject()->GetEnum(
448       XFA_Attribute::HAlign)) {
449     case XFA_AttributeEnum::Right:
450       pLeaderLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width -
451                                     fRightInset -
452                                     pLeaderLayoutItem->m_sSize.width;
453       break;
454     case XFA_AttributeEnum::Center:
455       pLeaderLayoutItem->m_sPos.x =
456           (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset -
457            pLeaderLayoutItem->m_sSize.width) /
458           2;
459       break;
460     case XFA_AttributeEnum::Left:
461     default:
462       pLeaderLayoutItem->m_sPos.x = fLeftInset;
463       break;
464   }
465   pProcessor->m_pLayoutItem->m_sSize.height += fHeight;
466   pProcessor->m_pLayoutItem->AddChild(pLeaderLayoutItem);
467 }
468 
AddPendingNode(CXFA_ItemLayoutProcessor * pProcessor,CXFA_Node * pPendingNode,bool bBreakPending)469 void AddPendingNode(CXFA_ItemLayoutProcessor* pProcessor,
470                     CXFA_Node* pPendingNode,
471                     bool bBreakPending) {
472   pProcessor->m_PendingNodes.push_back(pPendingNode);
473   pProcessor->m_bBreakPending = bBreakPending;
474 }
475 
InsertPendingItems(CXFA_ItemLayoutProcessor * pProcessor,CXFA_Node * pCurChildNode)476 float InsertPendingItems(CXFA_ItemLayoutProcessor* pProcessor,
477                          CXFA_Node* pCurChildNode) {
478   float fTotalHeight = 0;
479   if (pProcessor->m_PendingNodes.empty())
480     return fTotalHeight;
481 
482   if (!pProcessor->m_pLayoutItem) {
483     pProcessor->m_pLayoutItem =
484         pProcessor->CreateContentLayoutItem(pCurChildNode);
485     pProcessor->m_pLayoutItem->m_sSize.clear();
486   }
487 
488   while (!pProcessor->m_PendingNodes.empty()) {
489     auto pPendingProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
490         pProcessor->m_PendingNodes.front(), nullptr);
491     pProcessor->m_PendingNodes.pop_front();
492     pPendingProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
493     CXFA_ContentLayoutItem* pPendingLayoutItem =
494         pPendingProcessor->HasLayoutItem()
495             ? pPendingProcessor->ExtractLayoutItem()
496             : nullptr;
497     if (pPendingLayoutItem) {
498       AddLeaderAfterSplit(pProcessor, pPendingLayoutItem);
499       if (pProcessor->m_bBreakPending)
500         fTotalHeight += pPendingLayoutItem->m_sSize.height;
501     }
502   }
503   return fTotalHeight;
504 }
505 
GetLayout(CXFA_Node * pFormNode,bool * bRootForceTb)506 XFA_AttributeEnum GetLayout(CXFA_Node* pFormNode, bool* bRootForceTb) {
507   *bRootForceTb = false;
508   Optional<XFA_AttributeEnum> layoutMode =
509       pFormNode->JSObject()->TryEnum(XFA_Attribute::Layout, false);
510   if (layoutMode)
511     return *layoutMode;
512 
513   CXFA_Node* pParentNode = pFormNode->GetParent();
514   if (pParentNode && pParentNode->GetElementType() == XFA_Element::Form) {
515     *bRootForceTb = true;
516     return XFA_AttributeEnum::Tb;
517   }
518   return XFA_AttributeEnum::Position;
519 }
520 
ExistContainerKeep(CXFA_Node * pCurNode,bool bPreFind)521 bool ExistContainerKeep(CXFA_Node* pCurNode, bool bPreFind) {
522   if (!pCurNode || !XFA_ItemLayoutProcessor_IsTakingSpace(pCurNode))
523     return false;
524 
525   CXFA_Node* pPreContainer = bPreFind ? pCurNode->GetPrevContainerSibling()
526                                       : pCurNode->GetNextContainerSibling();
527   if (!pPreContainer)
528     return false;
529 
530   CXFA_Keep* pKeep =
531       pCurNode->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
532   if (pKeep) {
533     XFA_Attribute eKeepType = XFA_Attribute::Previous;
534     if (!bPreFind)
535       eKeepType = XFA_Attribute::Next;
536 
537     Optional<XFA_AttributeEnum> previous =
538         pKeep->JSObject()->TryEnum(eKeepType, false);
539     if (previous) {
540       if (*previous == XFA_AttributeEnum::ContentArea ||
541           *previous == XFA_AttributeEnum::PageArea) {
542         return true;
543       }
544     }
545   }
546 
547   pKeep = pPreContainer->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
548   if (!pKeep)
549     return false;
550 
551   XFA_Attribute eKeepType = XFA_Attribute::Next;
552   if (!bPreFind)
553     eKeepType = XFA_Attribute::Previous;
554 
555   Optional<XFA_AttributeEnum> next =
556       pKeep->JSObject()->TryEnum(eKeepType, false);
557   if (!next)
558     return false;
559   if (*next == XFA_AttributeEnum::ContentArea ||
560       *next == XFA_AttributeEnum::PageArea) {
561     return true;
562   }
563   return false;
564 }
565 
FindBreakNode(CXFA_Node * pContainerNode,CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages * nCurStage,bool bBreakBefore)566 bool FindBreakNode(CXFA_Node* pContainerNode,
567                    CXFA_Node*& pCurActionNode,
568                    XFA_ItemLayoutProcessorStages* nCurStage,
569                    bool bBreakBefore) {
570   bool bFindRs = false;
571   for (CXFA_Node* pBreakNode = pContainerNode; pBreakNode;
572        pBreakNode = pBreakNode->GetNextSibling()) {
573     XFA_Attribute eAttributeType = XFA_Attribute::Before;
574     if (!bBreakBefore)
575       eAttributeType = XFA_Attribute::After;
576 
577     switch (pBreakNode->GetElementType()) {
578       case XFA_Element::BreakBefore: {
579         if (bBreakBefore) {
580           pCurActionNode = pBreakNode;
581           *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
582           bFindRs = true;
583         }
584         break;
585       }
586       case XFA_Element::BreakAfter: {
587         if (!bBreakBefore) {
588           pCurActionNode = pBreakNode;
589           *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
590           bFindRs = true;
591         }
592         break;
593       }
594       case XFA_Element::Break:
595         if (pBreakNode->JSObject()->GetEnum(eAttributeType) !=
596             XFA_AttributeEnum::Auto) {
597           pCurActionNode = pBreakNode;
598           *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
599           if (!bBreakBefore)
600             *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
601 
602           bFindRs = true;
603         }
604         break;
605       default:
606         break;
607     }
608     if (bFindRs)
609       break;
610   }
611   return bFindRs;
612 }
613 
DeleteLayoutGeneratedNode(CXFA_Node * pGenerateNode)614 void DeleteLayoutGeneratedNode(CXFA_Node* pGenerateNode) {
615   CXFA_FFNotify* pNotify = pGenerateNode->GetDocument()->GetNotify();
616   CXFA_LayoutProcessor* pDocLayout =
617       pGenerateNode->GetDocument()->GetDocLayout();
618   CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
619       pGenerateNode);
620   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
621        pNode = sIterator.MoveToNext()) {
622     CXFA_ContentLayoutItem* pCurLayoutItem =
623         static_cast<CXFA_ContentLayoutItem*>(
624             pNode->JSObject()->GetLayoutItem());
625     CXFA_ContentLayoutItem* pNextLayoutItem = nullptr;
626     while (pCurLayoutItem) {
627       pNextLayoutItem = pCurLayoutItem->m_pNext;
628       pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
629       delete pCurLayoutItem;
630       pCurLayoutItem = pNextLayoutItem;
631     }
632   }
633   pGenerateNode->GetParent()->RemoveChild(pGenerateNode, true);
634 }
635 
HAlignEnumToInt(XFA_AttributeEnum eHAlign)636 uint8_t HAlignEnumToInt(XFA_AttributeEnum eHAlign) {
637   switch (eHAlign) {
638     case XFA_AttributeEnum::Center:
639       return 1;
640     case XFA_AttributeEnum::Right:
641       return 2;
642     case XFA_AttributeEnum::Left:
643     default:
644       return 0;
645   }
646 }
647 
InsertFlowedItem(CXFA_ItemLayoutProcessor * pThis,CXFA_ItemLayoutProcessor * pProcessor,bool bContainerWidthAutoSize,bool bContainerHeightAutoSize,float fContainerHeight,XFA_AttributeEnum eFlowStrategy,uint8_t * uCurHAlignState,std::vector<CXFA_ContentLayoutItem * > (& rgCurLineLayoutItems)[3],bool bUseBreakControl,float fAvailHeight,float fRealHeight,float fContentWidthLimit,float * fContentCurRowY,float * fContentCurRowAvailWidth,float * fContentCurRowHeight,bool * bAddedItemInRow,bool * bForceEndPage,CXFA_LayoutContext * pLayoutContext,bool bNewRow)648 XFA_ItemLayoutProcessorResult InsertFlowedItem(
649     CXFA_ItemLayoutProcessor* pThis,
650     CXFA_ItemLayoutProcessor* pProcessor,
651     bool bContainerWidthAutoSize,
652     bool bContainerHeightAutoSize,
653     float fContainerHeight,
654     XFA_AttributeEnum eFlowStrategy,
655     uint8_t* uCurHAlignState,
656     std::vector<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
657     bool bUseBreakControl,
658     float fAvailHeight,
659     float fRealHeight,
660     float fContentWidthLimit,
661     float* fContentCurRowY,
662     float* fContentCurRowAvailWidth,
663     float* fContentCurRowHeight,
664     bool* bAddedItemInRow,
665     bool* bForceEndPage,
666     CXFA_LayoutContext* pLayoutContext,
667     bool bNewRow) {
668   bool bTakeSpace =
669       XFA_ItemLayoutProcessor_IsTakingSpace(pProcessor->m_pFormNode);
670   uint8_t uHAlign = HAlignEnumToInt(
671       pThis->m_pCurChildNode->JSObject()->GetEnum(XFA_Attribute::HAlign));
672   if (bContainerWidthAutoSize)
673     uHAlign = 0;
674 
675   if ((eFlowStrategy != XFA_AttributeEnum::Rl_tb &&
676        uHAlign < *uCurHAlignState) ||
677       (eFlowStrategy == XFA_AttributeEnum::Rl_tb &&
678        uHAlign > *uCurHAlignState)) {
679     return XFA_ItemLayoutProcessorResult::RowFullBreak;
680   }
681 
682   *uCurHAlignState = uHAlign;
683   bool bIsOwnSplit =
684       pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None;
685   bool bUseRealHeight = bTakeSpace && bContainerHeightAutoSize && bIsOwnSplit &&
686                         pProcessor->m_pFormNode->GetParent()->GetIntact() ==
687                             XFA_AttributeEnum::None;
688   bool bIsTransHeight = bTakeSpace;
689   if (bIsTransHeight && !bIsOwnSplit) {
690     bool bRootForceTb = false;
691     XFA_AttributeEnum eLayoutStrategy =
692         GetLayout(pProcessor->m_pFormNode, &bRootForceTb);
693     if (eLayoutStrategy == XFA_AttributeEnum::Lr_tb ||
694         eLayoutStrategy == XFA_AttributeEnum::Rl_tb) {
695       bIsTransHeight = false;
696     }
697   }
698 
699   bool bUseInherited = false;
700   CXFA_LayoutContext layoutContext;
701   if (pThis->m_pPageMgr) {
702     CXFA_Node* pOverflowNode =
703         pThis->m_pPageMgr->QueryOverflow(pThis->m_pFormNode);
704     if (pOverflowNode) {
705       layoutContext.m_pOverflowNode = pOverflowNode;
706       layoutContext.m_pOverflowProcessor = pThis;
707       pLayoutContext = &layoutContext;
708     }
709   }
710 
711   XFA_ItemLayoutProcessorResult eRetValue = XFA_ItemLayoutProcessorResult::Done;
712   if (!bNewRow ||
713       pProcessor->m_ePreProcessRs == XFA_ItemLayoutProcessorResult::Done) {
714     eRetValue = pProcessor->DoLayout(
715         bTakeSpace ? bUseBreakControl : false,
716         bUseRealHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
717         bIsTransHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
718         pLayoutContext);
719     pProcessor->m_ePreProcessRs = eRetValue;
720   } else {
721     eRetValue = pProcessor->m_ePreProcessRs;
722     pProcessor->m_ePreProcessRs = XFA_ItemLayoutProcessorResult::Done;
723   }
724   if (pProcessor->HasLayoutItem() == false)
725     return eRetValue;
726 
727   CFX_SizeF childSize = pProcessor->GetCurrentComponentSize();
728   if (bUseRealHeight && fRealHeight < XFA_LAYOUT_FLOAT_PERCISION) {
729     fRealHeight = FLT_MAX;
730     fAvailHeight = FLT_MAX;
731   }
732   if (bTakeSpace && (childSize.width >
733                      *fContentCurRowAvailWidth + XFA_LAYOUT_FLOAT_PERCISION) &&
734       (fContentWidthLimit - *fContentCurRowAvailWidth >
735        XFA_LAYOUT_FLOAT_PERCISION)) {
736     return XFA_ItemLayoutProcessorResult::RowFullBreak;
737   }
738 
739   CXFA_Node* pOverflowLeaderNode = nullptr;
740   CXFA_Node* pOverflowTrailerNode = nullptr;
741   CXFA_Node* pFormNode = nullptr;
742   CXFA_ContentLayoutItem* pTrailerLayoutItem = nullptr;
743   bool bIsAddTrailerHeight = false;
744   if (pThis->m_pPageMgr &&
745       pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None) {
746     pFormNode = pThis->m_pPageMgr->QueryOverflow(pProcessor->m_pFormNode);
747     if (!pFormNode && pLayoutContext && pLayoutContext->m_pOverflowProcessor) {
748       pFormNode = pLayoutContext->m_pOverflowNode;
749       bUseInherited = true;
750     }
751     if (pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
752                                            pOverflowTrailerNode, false,
753                                            false)) {
754       if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowTrailerNode)) {
755         if (pOverflowTrailerNode) {
756           auto pOverflowLeaderProcessor =
757               pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pOverflowTrailerNode,
758                                                            nullptr);
759           pOverflowLeaderProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
760           pTrailerLayoutItem =
761               pOverflowLeaderProcessor->HasLayoutItem()
762                   ? pOverflowLeaderProcessor->ExtractLayoutItem()
763                   : nullptr;
764         }
765 
766         bIsAddTrailerHeight =
767             bUseInherited
768                 ? pThis->IsAddNewRowForTrailer(pTrailerLayoutItem)
769                 : pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem);
770         if (bIsAddTrailerHeight) {
771           childSize.height += pTrailerLayoutItem->m_sSize.height;
772           bIsAddTrailerHeight = true;
773         }
774       }
775     }
776   }
777 
778   if (!bTakeSpace ||
779       *fContentCurRowY + childSize.height <=
780           fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION ||
781       (!bContainerHeightAutoSize &&
782        pThis->m_fUsedSize + fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION >=
783            fContainerHeight)) {
784     if (!bTakeSpace || eRetValue == XFA_ItemLayoutProcessorResult::Done) {
785       if (pProcessor->m_bUseInheriated) {
786         if (pTrailerLayoutItem)
787           AddTrailerBeforeSplit(pProcessor, childSize.height,
788                                 pTrailerLayoutItem, false);
789         if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
790           AddPendingNode(pProcessor, pOverflowLeaderNode, false);
791 
792         pProcessor->m_bUseInheriated = false;
793       } else {
794         if (bIsAddTrailerHeight)
795           childSize.height -= pTrailerLayoutItem->m_sSize.height;
796 
797         pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
798                                          pOverflowTrailerNode,
799                                          pTrailerLayoutItem, pFormNode);
800       }
801 
802       CXFA_ContentLayoutItem* pChildLayoutItem =
803           pProcessor->ExtractLayoutItem();
804       if (ExistContainerKeep(pProcessor->m_pFormNode, false) &&
805           pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None) {
806         pThis->m_arrayKeepItems.push_back(pChildLayoutItem);
807       } else {
808         pThis->m_arrayKeepItems.clear();
809       }
810       rgCurLineLayoutItems[uHAlign].push_back(pChildLayoutItem);
811       *bAddedItemInRow = true;
812       if (bTakeSpace) {
813         *fContentCurRowAvailWidth -= childSize.width;
814         *fContentCurRowHeight =
815             std::max(*fContentCurRowHeight, childSize.height);
816       }
817       return XFA_ItemLayoutProcessorResult::Done;
818     }
819 
820     if (eRetValue == XFA_ItemLayoutProcessorResult::PageFullBreak) {
821       if (pProcessor->m_bUseInheriated) {
822         if (pTrailerLayoutItem) {
823           AddTrailerBeforeSplit(pProcessor, childSize.height,
824                                 pTrailerLayoutItem, false);
825         }
826         if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
827           AddPendingNode(pProcessor, pOverflowLeaderNode, false);
828 
829         pProcessor->m_bUseInheriated = false;
830       } else {
831         if (bIsAddTrailerHeight)
832           childSize.height -= pTrailerLayoutItem->m_sSize.height;
833 
834         pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
835                                          pOverflowTrailerNode,
836                                          pTrailerLayoutItem, pFormNode);
837       }
838     }
839     rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
840     *bAddedItemInRow = true;
841     *fContentCurRowAvailWidth -= childSize.width;
842     *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
843     return eRetValue;
844   }
845 
846   XFA_ItemLayoutProcessorResult eResult;
847   if (pThis->ProcessKeepForSplit(
848           pThis, pProcessor, eRetValue, &rgCurLineLayoutItems[uHAlign],
849           fContentCurRowAvailWidth, fContentCurRowHeight, fContentCurRowY,
850           bAddedItemInRow, bForceEndPage, &eResult)) {
851     return eResult;
852   }
853 
854   *bForceEndPage = true;
855   float fSplitPos = pProcessor->FindSplitPos(fAvailHeight - *fContentCurRowY);
856   if (fSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
857     XFA_AttributeEnum eLayout =
858         pProcessor->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
859     if (eLayout == XFA_AttributeEnum::Tb &&
860         eRetValue == XFA_ItemLayoutProcessorResult::Done) {
861       pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
862                                        pOverflowTrailerNode, pTrailerLayoutItem,
863                                        pFormNode);
864       rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
865       *bAddedItemInRow = true;
866       if (bTakeSpace) {
867         *fContentCurRowAvailWidth -= childSize.width;
868         *fContentCurRowHeight =
869             std::max(*fContentCurRowHeight, childSize.height);
870       }
871       return XFA_ItemLayoutProcessorResult::PageFullBreak;
872     }
873 
874     CXFA_Node* pTempLeaderNode = nullptr;
875     CXFA_Node* pTempTrailerNode = nullptr;
876     if (pThis->m_pPageMgr && !pProcessor->m_bUseInheriated &&
877         eRetValue != XFA_ItemLayoutProcessorResult::PageFullBreak) {
878       pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
879                                          pTempTrailerNode, false, true);
880     }
881     if (pTrailerLayoutItem && bIsAddTrailerHeight) {
882       AddTrailerBeforeSplit(pProcessor, fSplitPos, pTrailerLayoutItem,
883                             bUseInherited);
884     } else {
885       pProcessor->SplitLayoutItem(fSplitPos);
886     }
887 
888     if (bUseInherited) {
889       pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
890                                        pOverflowTrailerNode, pTrailerLayoutItem,
891                                        pFormNode);
892       pThis->m_bUseInheriated = true;
893     } else {
894       CXFA_LayoutItem* firstChild = pProcessor->m_pLayoutItem->m_pFirstChild;
895       if (firstChild && !firstChild->m_pNextSibling &&
896           firstChild->m_pFormNode->IsLayoutGeneratedNode()) {
897         pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
898                                          pOverflowTrailerNode,
899                                          pTrailerLayoutItem, pFormNode);
900       } else if (pProcessor->JudgeLeaderOrTrailerForOccur(
901                      pOverflowLeaderNode)) {
902         AddPendingNode(pProcessor, pOverflowLeaderNode, false);
903       }
904     }
905 
906     if (pProcessor->m_pLayoutItem->m_pNextSibling) {
907       childSize = pProcessor->GetCurrentComponentSize();
908       rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
909       *bAddedItemInRow = true;
910       if (bTakeSpace) {
911         *fContentCurRowAvailWidth -= childSize.width;
912         *fContentCurRowHeight =
913             std::max(*fContentCurRowHeight, childSize.height);
914       }
915     }
916     return XFA_ItemLayoutProcessorResult::PageFullBreak;
917   }
918 
919   if (*fContentCurRowY <= XFA_LAYOUT_FLOAT_PERCISION) {
920     childSize = pProcessor->GetCurrentComponentSize();
921     if (pProcessor->m_pPageMgr->GetNextAvailContentHeight(childSize.height)) {
922       CXFA_Node* pTempLeaderNode = nullptr;
923       CXFA_Node* pTempTrailerNode = nullptr;
924       if (pThis->m_pPageMgr) {
925         if (!pFormNode && pLayoutContext)
926           pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
927 
928         pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
929                                            pTempTrailerNode, false, true);
930       }
931       if (bUseInherited) {
932         pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
933                                          pOverflowTrailerNode,
934                                          pTrailerLayoutItem, pFormNode);
935         pThis->m_bUseInheriated = true;
936       }
937       return XFA_ItemLayoutProcessorResult::PageFullBreak;
938     }
939 
940     rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
941     *bAddedItemInRow = true;
942     if (bTakeSpace) {
943       *fContentCurRowAvailWidth -= childSize.width;
944       *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
945     }
946     if (eRetValue == XFA_ItemLayoutProcessorResult::Done)
947       *bForceEndPage = false;
948 
949     return eRetValue;
950   }
951 
952   XFA_AttributeEnum eLayout =
953       pProcessor->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
954   if (pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None &&
955       eLayout == XFA_AttributeEnum::Tb) {
956     if (pThis->m_pPageMgr) {
957       pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
958                                          pOverflowTrailerNode, false, true);
959     }
960     if (pTrailerLayoutItem)
961       AddTrailerBeforeSplit(pProcessor, fSplitPos, pTrailerLayoutItem, false);
962     if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
963       AddPendingNode(pProcessor, pOverflowLeaderNode, false);
964 
965     return XFA_ItemLayoutProcessorResult::PageFullBreak;
966   }
967 
968   if (eRetValue != XFA_ItemLayoutProcessorResult::Done)
969     return XFA_ItemLayoutProcessorResult::PageFullBreak;
970 
971   if (!pFormNode && pLayoutContext)
972     pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
973   if (pThis->m_pPageMgr) {
974     pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
975                                        pOverflowTrailerNode, false, true);
976   }
977   if (bUseInherited) {
978     pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode, pOverflowTrailerNode,
979                                      pTrailerLayoutItem, pFormNode);
980     pThis->m_bUseInheriated = true;
981   }
982   return XFA_ItemLayoutProcessorResult::PageFullBreak;
983 }
984 
FindLayoutItemSplitPos(CXFA_ContentLayoutItem * pLayoutItem,float fCurVerticalOffset,float * fProposedSplitPos,bool * bAppChange,bool bCalculateMargin)985 bool FindLayoutItemSplitPos(CXFA_ContentLayoutItem* pLayoutItem,
986                             float fCurVerticalOffset,
987                             float* fProposedSplitPos,
988                             bool* bAppChange,
989                             bool bCalculateMargin) {
990   CXFA_Node* pFormNode = pLayoutItem->m_pFormNode;
991   if (*fProposedSplitPos <= fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION ||
992       *fProposedSplitPos > fCurVerticalOffset + pLayoutItem->m_sSize.height -
993                                XFA_LAYOUT_FLOAT_PERCISION) {
994     return false;
995   }
996 
997   switch (pFormNode->GetIntact()) {
998     case XFA_AttributeEnum::None: {
999       bool bAnyChanged = false;
1000       CXFA_Document* pDocument = pFormNode->GetDocument();
1001       CXFA_FFNotify* pNotify = pDocument->GetNotify();
1002       float fCurTopMargin = 0, fCurBottomMargin = 0;
1003       CXFA_Margin* pMarginNode =
1004           pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
1005       if (pMarginNode && bCalculateMargin) {
1006         fCurTopMargin = pMarginNode->JSObject()
1007                             ->GetMeasure(XFA_Attribute::TopInset)
1008                             .ToUnit(XFA_Unit::Pt);
1009         fCurBottomMargin = pMarginNode->JSObject()
1010                                ->GetMeasure(XFA_Attribute::BottomInset)
1011                                .ToUnit(XFA_Unit::Pt);
1012       }
1013       bool bChanged = true;
1014       while (bChanged) {
1015         bChanged = false;
1016         {
1017           float fRelSplitPos = *fProposedSplitPos - fCurVerticalOffset;
1018           if (pNotify->FindSplitPos(pFormNode, pLayoutItem->GetIndex(),
1019                                     fRelSplitPos)) {
1020             bAnyChanged = true;
1021             bChanged = true;
1022             *fProposedSplitPos = fCurVerticalOffset + fRelSplitPos;
1023             *bAppChange = true;
1024             if (*fProposedSplitPos <=
1025                 fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
1026               return true;
1027             }
1028           }
1029         }
1030         float fRelSplitPos = *fProposedSplitPos - fCurBottomMargin;
1031         for (CXFA_ContentLayoutItem* pChildItem =
1032                  (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
1033              pChildItem;
1034              pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
1035           float fChildOffset =
1036               fCurVerticalOffset + fCurTopMargin + pChildItem->m_sPos.y;
1037           bool bChange = false;
1038           if (FindLayoutItemSplitPos(pChildItem, fChildOffset, &fRelSplitPos,
1039                                      &bChange, bCalculateMargin)) {
1040             if (fRelSplitPos - fChildOffset < XFA_LAYOUT_FLOAT_PERCISION &&
1041                 bChange) {
1042               *fProposedSplitPos = fRelSplitPos - fCurTopMargin;
1043             } else {
1044               *fProposedSplitPos = fRelSplitPos + fCurBottomMargin;
1045             }
1046             bAnyChanged = true;
1047             bChanged = true;
1048             if (*fProposedSplitPos <=
1049                 fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
1050               return true;
1051             }
1052             if (bAnyChanged)
1053               break;
1054           }
1055         }
1056       }
1057       return bAnyChanged;
1058     }
1059     case XFA_AttributeEnum::ContentArea:
1060     case XFA_AttributeEnum::PageArea: {
1061       *fProposedSplitPos = fCurVerticalOffset;
1062       return true;
1063     }
1064     default:
1065       return false;
1066   }
1067 }
1068 
CalculatePositionedContainerPos(CXFA_Node * pNode,const CFX_SizeF & size)1069 CFX_PointF CalculatePositionedContainerPos(CXFA_Node* pNode,
1070                                            const CFX_SizeF& size) {
1071   XFA_AttributeEnum eAnchorType =
1072       pNode->JSObject()->GetEnum(XFA_Attribute::AnchorType);
1073   int32_t nAnchorType = 0;
1074   switch (eAnchorType) {
1075     case XFA_AttributeEnum::TopLeft:
1076       nAnchorType = 0;
1077       break;
1078     case XFA_AttributeEnum::TopCenter:
1079       nAnchorType = 1;
1080       break;
1081     case XFA_AttributeEnum::TopRight:
1082       nAnchorType = 2;
1083       break;
1084     case XFA_AttributeEnum::MiddleLeft:
1085       nAnchorType = 3;
1086       break;
1087     case XFA_AttributeEnum::MiddleCenter:
1088       nAnchorType = 4;
1089       break;
1090     case XFA_AttributeEnum::MiddleRight:
1091       nAnchorType = 5;
1092       break;
1093     case XFA_AttributeEnum::BottomLeft:
1094       nAnchorType = 6;
1095       break;
1096     case XFA_AttributeEnum::BottomCenter:
1097       nAnchorType = 7;
1098       break;
1099     case XFA_AttributeEnum::BottomRight:
1100       nAnchorType = 8;
1101       break;
1102     default:
1103       break;
1104   }
1105   static const uint8_t nNextPos[4][9] = {{0, 1, 2, 3, 4, 5, 6, 7, 8},
1106                                          {6, 3, 0, 7, 4, 1, 8, 5, 2},
1107                                          {8, 7, 6, 5, 4, 3, 2, 1, 0},
1108                                          {2, 5, 8, 1, 4, 7, 0, 3, 6}};
1109 
1110   CFX_PointF pos(
1111       pNode->JSObject()->GetMeasure(XFA_Attribute::X).ToUnit(XFA_Unit::Pt),
1112       pNode->JSObject()->GetMeasure(XFA_Attribute::Y).ToUnit(XFA_Unit::Pt));
1113   int32_t nRotate =
1114       XFA_MapRotation(pNode->JSObject()->GetInteger(XFA_Attribute::Rotate)) /
1115       90;
1116   int32_t nAbsoluteAnchorType = nNextPos[nRotate][nAnchorType];
1117   switch (nAbsoluteAnchorType / 3) {
1118     case 1:
1119       pos.y -= size.height / 2;
1120       break;
1121     case 2:
1122       pos.y -= size.height;
1123       break;
1124     default:
1125       break;
1126   }
1127   switch (nAbsoluteAnchorType % 3) {
1128     case 1:
1129       pos.x -= size.width / 2;
1130       break;
1131     case 2:
1132       pos.x -= size.width;
1133       break;
1134     default:
1135       break;
1136   }
1137   return pos;
1138 }
1139 
1140 }  // namespace
1141 
CXFA_ItemLayoutProcessor(CXFA_Node * pNode,CXFA_LayoutPageMgr * pPageMgr)1142 CXFA_ItemLayoutProcessor::CXFA_ItemLayoutProcessor(CXFA_Node* pNode,
1143                                                    CXFA_LayoutPageMgr* pPageMgr)
1144     : m_pFormNode(pNode),
1145       m_pLayoutItem(nullptr),
1146       m_pCurChildNode(XFA_LAYOUT_INVALIDNODE),
1147       m_fUsedSize(0),
1148       m_pPageMgr(pPageMgr),
1149       m_bBreakPending(true),
1150       m_fLastRowWidth(0),
1151       m_fLastRowY(0),
1152       m_bUseInheriated(false),
1153       m_ePreProcessRs(XFA_ItemLayoutProcessorResult::Done),
1154       m_bKeepBreakFinish(false),
1155       m_bIsProcessKeep(false),
1156       m_pKeepHeadNode(nullptr),
1157       m_pKeepTailNode(nullptr),
1158       m_pOldLayoutItem(nullptr),
1159       m_pCurChildPreprocessor(nullptr),
1160       m_nCurChildNodeStage(XFA_ItemLayoutProcessorStages::None),
1161       m_fWidthLimite(0),
1162       m_bHasAvailHeight(true) {
1163   ASSERT(m_pFormNode && (m_pFormNode->IsContainerNode() ||
1164                          m_pFormNode->GetElementType() == XFA_Element::Form));
1165   m_pOldLayoutItem = static_cast<CXFA_ContentLayoutItem*>(
1166       m_pFormNode->JSObject()->GetLayoutItem());
1167 }
1168 
~CXFA_ItemLayoutProcessor()1169 CXFA_ItemLayoutProcessor::~CXFA_ItemLayoutProcessor() {}
1170 
CreateContentLayoutItem(CXFA_Node * pFormNode)1171 CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::CreateContentLayoutItem(
1172     CXFA_Node* pFormNode) {
1173   if (!pFormNode)
1174     return nullptr;
1175 
1176   CXFA_ContentLayoutItem* pLayoutItem = nullptr;
1177   if (m_pOldLayoutItem) {
1178     pLayoutItem = m_pOldLayoutItem;
1179     m_pOldLayoutItem = m_pOldLayoutItem->m_pNext;
1180     return pLayoutItem;
1181   }
1182   pLayoutItem =
1183       pFormNode->GetDocument()->GetNotify()->OnCreateContentLayoutItem(
1184           pFormNode);
1185   CXFA_ContentLayoutItem* pPrevLayoutItem =
1186       static_cast<CXFA_ContentLayoutItem*>(
1187           pFormNode->JSObject()->GetLayoutItem());
1188   if (pPrevLayoutItem) {
1189     while (pPrevLayoutItem->m_pNext)
1190       pPrevLayoutItem = pPrevLayoutItem->m_pNext;
1191 
1192     pPrevLayoutItem->m_pNext = pLayoutItem;
1193     pLayoutItem->m_pPrev = pPrevLayoutItem;
1194   } else {
1195     pFormNode->JSObject()->SetLayoutItem(pLayoutItem);
1196   }
1197   return pLayoutItem;
1198 }
1199 
FindSplitPos(float fProposedSplitPos)1200 float CXFA_ItemLayoutProcessor::FindSplitPos(float fProposedSplitPos) {
1201   ASSERT(m_pLayoutItem);
1202   XFA_AttributeEnum eLayout = m_pFormNode->JSObject()
1203                                   ->TryEnum(XFA_Attribute::Layout, true)
1204                                   .value_or(XFA_AttributeEnum::Position);
1205   bool bCalculateMargin = eLayout != XFA_AttributeEnum::Position;
1206   while (fProposedSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
1207     bool bAppChange = false;
1208     if (!FindLayoutItemSplitPos(m_pLayoutItem, 0, &fProposedSplitPos,
1209                                 &bAppChange, bCalculateMargin)) {
1210       break;
1211     }
1212   }
1213   return fProposedSplitPos;
1214 }
1215 
SplitLayoutItem(CXFA_ContentLayoutItem * pLayoutItem,CXFA_ContentLayoutItem * pSecondParent,float fSplitPos)1216 void CXFA_ItemLayoutProcessor::SplitLayoutItem(
1217     CXFA_ContentLayoutItem* pLayoutItem,
1218     CXFA_ContentLayoutItem* pSecondParent,
1219     float fSplitPos) {
1220   float fCurTopMargin = 0, fCurBottomMargin = 0;
1221   XFA_AttributeEnum eLayout = m_pFormNode->JSObject()
1222                                   ->TryEnum(XFA_Attribute::Layout, true)
1223                                   .value_or(XFA_AttributeEnum::Position);
1224   bool bCalculateMargin = true;
1225   if (eLayout == XFA_AttributeEnum::Position)
1226     bCalculateMargin = false;
1227 
1228   CXFA_Margin* pMarginNode =
1229       pLayoutItem->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
1230           XFA_Element::Margin);
1231   if (pMarginNode && bCalculateMargin) {
1232     fCurTopMargin = pMarginNode->JSObject()
1233                         ->GetMeasure(XFA_Attribute::TopInset)
1234                         .ToUnit(XFA_Unit::Pt);
1235     fCurBottomMargin = pMarginNode->JSObject()
1236                            ->GetMeasure(XFA_Attribute::BottomInset)
1237                            .ToUnit(XFA_Unit::Pt);
1238   }
1239 
1240   CXFA_ContentLayoutItem* pSecondLayoutItem = nullptr;
1241   if (m_pCurChildPreprocessor &&
1242       m_pCurChildPreprocessor->m_pFormNode == pLayoutItem->m_pFormNode) {
1243     pSecondLayoutItem = m_pCurChildPreprocessor->CreateContentLayoutItem(
1244         pLayoutItem->m_pFormNode);
1245   } else {
1246     pSecondLayoutItem = CreateContentLayoutItem(pLayoutItem->m_pFormNode);
1247   }
1248   pSecondLayoutItem->m_sPos.x = pLayoutItem->m_sPos.x;
1249   pSecondLayoutItem->m_sSize.width = pLayoutItem->m_sSize.width;
1250   pSecondLayoutItem->m_sPos.y = 0;
1251   pSecondLayoutItem->m_sSize.height = pLayoutItem->m_sSize.height - fSplitPos;
1252   pLayoutItem->m_sSize.height -= pSecondLayoutItem->m_sSize.height;
1253   if (pLayoutItem->m_pFirstChild)
1254     pSecondLayoutItem->m_sSize.height += fCurTopMargin;
1255 
1256   if (pSecondParent) {
1257     pSecondParent->AddChild(pSecondLayoutItem);
1258     if (fCurTopMargin > 0 && pLayoutItem->m_pFirstChild) {
1259       pSecondParent->m_sSize.height += fCurTopMargin;
1260       CXFA_ContentLayoutItem* pParentItem =
1261           (CXFA_ContentLayoutItem*)pSecondParent->m_pParent;
1262       while (pParentItem) {
1263         pParentItem->m_sSize.height += fCurTopMargin;
1264         pParentItem = (CXFA_ContentLayoutItem*)pParentItem->m_pParent;
1265       }
1266     }
1267   } else {
1268     pSecondLayoutItem->m_pParent = pLayoutItem->m_pParent;
1269     pSecondLayoutItem->m_pNextSibling = pLayoutItem->m_pNextSibling;
1270     pLayoutItem->m_pNextSibling = pSecondLayoutItem;
1271   }
1272 
1273   CXFA_ContentLayoutItem* pChildren =
1274       (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
1275   pLayoutItem->m_pFirstChild = nullptr;
1276 
1277   float lHeightForKeep = 0;
1278   float fAddMarginHeight = 0;
1279   std::vector<CXFA_ContentLayoutItem*> keepLayoutItems;
1280   for (CXFA_ContentLayoutItem *pChildItem = pChildren, *pChildNext = nullptr;
1281        pChildItem; pChildItem = pChildNext) {
1282     pChildNext = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling;
1283     pChildItem->m_pNextSibling = nullptr;
1284     if (fSplitPos <= fCurTopMargin + pChildItem->m_sPos.y + fCurBottomMargin +
1285                          XFA_LAYOUT_FLOAT_PERCISION) {
1286       if (!ExistContainerKeep(pChildItem->m_pFormNode, true)) {
1287         pChildItem->m_sPos.y -= fSplitPos - fCurBottomMargin;
1288         pChildItem->m_sPos.y += lHeightForKeep;
1289         pChildItem->m_sPos.y += fAddMarginHeight;
1290         pSecondLayoutItem->AddChild(pChildItem);
1291         continue;
1292       }
1293       if (lHeightForKeep < XFA_LAYOUT_FLOAT_PERCISION) {
1294         for (auto* pPreItem : keepLayoutItems) {
1295           pLayoutItem->RemoveChild(pPreItem);
1296           pPreItem->m_sPos.y -= fSplitPos;
1297           if (pPreItem->m_sPos.y < 0)
1298             pPreItem->m_sPos.y = 0;
1299           if (pPreItem->m_sPos.y + pPreItem->m_sSize.height > lHeightForKeep) {
1300             pPreItem->m_sPos.y = lHeightForKeep;
1301             lHeightForKeep += pPreItem->m_sSize.height;
1302             pSecondLayoutItem->m_sSize.height += pPreItem->m_sSize.height;
1303             if (pSecondParent)
1304               pSecondParent->m_sSize.height += pPreItem->m_sSize.height;
1305           }
1306           pSecondLayoutItem->AddChild(pPreItem);
1307         }
1308       }
1309       pChildItem->m_sPos.y -= fSplitPos;
1310       pChildItem->m_sPos.y += lHeightForKeep;
1311       pChildItem->m_sPos.y += fAddMarginHeight;
1312       pSecondLayoutItem->AddChild(pChildItem);
1313       continue;
1314     }
1315     if (fSplitPos + XFA_LAYOUT_FLOAT_PERCISION >=
1316         fCurTopMargin + fCurBottomMargin + pChildItem->m_sPos.y +
1317             pChildItem->m_sSize.height) {
1318       pLayoutItem->AddChild(pChildItem);
1319       if (ExistContainerKeep(pChildItem->m_pFormNode, false))
1320         keepLayoutItems.push_back(pChildItem);
1321       else
1322         keepLayoutItems.clear();
1323       continue;
1324     }
1325 
1326     float fOldHeight = pSecondLayoutItem->m_sSize.height;
1327     SplitLayoutItem(
1328         pChildItem, pSecondLayoutItem,
1329         fSplitPos - fCurTopMargin - fCurBottomMargin - pChildItem->m_sPos.y);
1330     fAddMarginHeight = pSecondLayoutItem->m_sSize.height - fOldHeight;
1331     pLayoutItem->AddChild(pChildItem);
1332   }
1333 }
1334 
SplitLayoutItem(float fSplitPos)1335 void CXFA_ItemLayoutProcessor::SplitLayoutItem(float fSplitPos) {
1336   ASSERT(m_pLayoutItem);
1337   SplitLayoutItem(m_pLayoutItem, nullptr, fSplitPos);
1338 }
1339 
ExtractLayoutItem()1340 CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::ExtractLayoutItem() {
1341   CXFA_ContentLayoutItem* pLayoutItem = m_pLayoutItem;
1342   if (pLayoutItem) {
1343     m_pLayoutItem =
1344         static_cast<CXFA_ContentLayoutItem*>(pLayoutItem->m_pNextSibling);
1345     pLayoutItem->m_pNextSibling = nullptr;
1346   }
1347 
1348   if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done ||
1349       !ToContentLayoutItem(m_pOldLayoutItem)) {
1350     return pLayoutItem;
1351   }
1352 
1353   if (m_pOldLayoutItem->m_pPrev)
1354     m_pOldLayoutItem->m_pPrev->m_pNext = nullptr;
1355 
1356   CXFA_FFNotify* pNotify =
1357       m_pOldLayoutItem->m_pFormNode->GetDocument()->GetNotify();
1358   CXFA_LayoutProcessor* pDocLayout =
1359       m_pOldLayoutItem->m_pFormNode->GetDocument()->GetDocLayout();
1360   CXFA_ContentLayoutItem* pOldLayoutItem = m_pOldLayoutItem;
1361   while (pOldLayoutItem) {
1362     CXFA_ContentLayoutItem* pNextOldLayoutItem = pOldLayoutItem->m_pNext;
1363     pNotify->OnLayoutItemRemoving(pDocLayout, pOldLayoutItem);
1364     if (pOldLayoutItem->m_pParent)
1365       pOldLayoutItem->m_pParent->RemoveChild(pOldLayoutItem);
1366 
1367     delete pOldLayoutItem;
1368     pOldLayoutItem = pNextOldLayoutItem;
1369   }
1370   m_pOldLayoutItem = nullptr;
1371   return pLayoutItem;
1372 }
1373 
GotoNextContainerNode(CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages & nCurStage,CXFA_Node * pParentContainer,bool bUsePageBreak)1374 void CXFA_ItemLayoutProcessor::GotoNextContainerNode(
1375     CXFA_Node*& pCurActionNode,
1376     XFA_ItemLayoutProcessorStages& nCurStage,
1377     CXFA_Node* pParentContainer,
1378     bool bUsePageBreak) {
1379   CXFA_Node* pEntireContainer = pParentContainer;
1380   CXFA_Node* pChildContainer = XFA_LAYOUT_INVALIDNODE;
1381   switch (nCurStage) {
1382     case XFA_ItemLayoutProcessorStages::BreakBefore:
1383     case XFA_ItemLayoutProcessorStages::BreakAfter: {
1384       pChildContainer = pCurActionNode->GetParent();
1385       break;
1386     }
1387     case XFA_ItemLayoutProcessorStages::Keep:
1388     case XFA_ItemLayoutProcessorStages::Container:
1389       pChildContainer = pCurActionNode;
1390       break;
1391     default:
1392       pChildContainer = XFA_LAYOUT_INVALIDNODE;
1393       break;
1394   }
1395 
1396   switch (nCurStage) {
1397     case XFA_ItemLayoutProcessorStages::Keep: {
1398       CXFA_Node* pBreakAfterNode = pChildContainer->GetFirstChild();
1399       if (!m_bKeepBreakFinish &&
1400           FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, false)) {
1401         return;
1402       }
1403       goto CheckNextChildContainer;
1404     }
1405     case XFA_ItemLayoutProcessorStages::None: {
1406       pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1407       case XFA_ItemLayoutProcessorStages::BookendLeader:
1408         for (CXFA_Node* pBookendNode = pCurActionNode == XFA_LAYOUT_INVALIDNODE
1409                                            ? pEntireContainer->GetFirstChild()
1410                                            : pCurActionNode->GetNextSibling();
1411              pBookendNode; pBookendNode = pBookendNode->GetNextSibling()) {
1412           switch (pBookendNode->GetElementType()) {
1413             case XFA_Element::Bookend:
1414             case XFA_Element::Break:
1415               pCurActionNode = pBookendNode;
1416               nCurStage = XFA_ItemLayoutProcessorStages::BookendLeader;
1417               return;
1418             default:
1419               break;
1420           }
1421         }
1422     }
1423       {
1424         pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1425         case XFA_ItemLayoutProcessorStages::BreakBefore:
1426           if (pCurActionNode != XFA_LAYOUT_INVALIDNODE) {
1427             CXFA_Node* pBreakBeforeNode = pCurActionNode->GetNextSibling();
1428             if (!m_bKeepBreakFinish &&
1429                 FindBreakNode(pBreakBeforeNode, pCurActionNode, &nCurStage,
1430                               true)) {
1431               return;
1432             }
1433             if (m_bIsProcessKeep) {
1434               if (ProcessKeepNodesForBreakBefore(pCurActionNode, nCurStage,
1435                                                  pChildContainer)) {
1436                 return;
1437               }
1438               goto CheckNextChildContainer;
1439             }
1440             pCurActionNode = pChildContainer;
1441             nCurStage = XFA_ItemLayoutProcessorStages::Container;
1442             return;
1443           }
1444           goto CheckNextChildContainer;
1445       }
1446     case XFA_ItemLayoutProcessorStages::Container: {
1447       pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1448       case XFA_ItemLayoutProcessorStages::BreakAfter: {
1449         if (pCurActionNode == XFA_LAYOUT_INVALIDNODE) {
1450           CXFA_Node* pBreakAfterNode = pChildContainer->GetFirstChild();
1451           if (!m_bKeepBreakFinish &&
1452               FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
1453                             false)) {
1454             return;
1455           }
1456         } else {
1457           CXFA_Node* pBreakAfterNode = pCurActionNode->GetNextSibling();
1458           if (FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
1459                             false)) {
1460             return;
1461           }
1462         }
1463         goto CheckNextChildContainer;
1464       }
1465     }
1466 
1467     CheckNextChildContainer : {
1468       CXFA_Node* pNextChildContainer =
1469           pChildContainer == XFA_LAYOUT_INVALIDNODE
1470               ? pEntireContainer->GetFirstContainerChild()
1471               : pChildContainer->GetNextContainerSibling();
1472       while (pNextChildContainer &&
1473              pNextChildContainer->IsLayoutGeneratedNode()) {
1474         CXFA_Node* pSaveNode = pNextChildContainer;
1475         pNextChildContainer = pNextChildContainer->GetNextContainerSibling();
1476         if (pSaveNode->IsUnusedNode())
1477           DeleteLayoutGeneratedNode(pSaveNode);
1478       }
1479       if (!pNextChildContainer)
1480         goto NoMoreChildContainer;
1481 
1482       bool bLastKeep = false;
1483       if (ProcessKeepNodesForCheckNext(pCurActionNode, nCurStage,
1484                                        pNextChildContainer, bLastKeep)) {
1485         return;
1486       }
1487       if (!m_bKeepBreakFinish && !bLastKeep &&
1488           FindBreakNode(pNextChildContainer->GetFirstChild(), pCurActionNode,
1489                         &nCurStage, true)) {
1490         return;
1491       }
1492       pCurActionNode = pNextChildContainer;
1493       if (m_bIsProcessKeep)
1494         nCurStage = XFA_ItemLayoutProcessorStages::Keep;
1495       else
1496         nCurStage = XFA_ItemLayoutProcessorStages::Container;
1497       return;
1498     }
1499 
1500     NoMoreChildContainer : {
1501       pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1502       case XFA_ItemLayoutProcessorStages::BookendTrailer:
1503         for (CXFA_Node* pBookendNode = pCurActionNode == XFA_LAYOUT_INVALIDNODE
1504                                            ? pEntireContainer->GetFirstChild()
1505                                            : pCurActionNode->GetNextSibling();
1506              pBookendNode; pBookendNode = pBookendNode->GetNextSibling()) {
1507           switch (pBookendNode->GetElementType()) {
1508             case XFA_Element::Bookend:
1509             case XFA_Element::Break:
1510               pCurActionNode = pBookendNode;
1511               nCurStage = XFA_ItemLayoutProcessorStages::BookendTrailer;
1512               return;
1513             default:
1514               break;
1515           }
1516         }
1517     }
1518     default:
1519       pCurActionNode = nullptr;
1520       nCurStage = XFA_ItemLayoutProcessorStages::Done;
1521   }
1522 }
1523 
ProcessKeepNodesForCheckNext(CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages & nCurStage,CXFA_Node * & pNextContainer,bool & bLastKeepNode)1524 bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForCheckNext(
1525     CXFA_Node*& pCurActionNode,
1526     XFA_ItemLayoutProcessorStages& nCurStage,
1527     CXFA_Node*& pNextContainer,
1528     bool& bLastKeepNode) {
1529   const bool bCanSplit = pNextContainer->GetIntact() == XFA_AttributeEnum::None;
1530   bool bNextKeep = false;
1531   if (ExistContainerKeep(pNextContainer, false))
1532     bNextKeep = true;
1533 
1534   if (bNextKeep && !bCanSplit) {
1535     if (!m_bIsProcessKeep && !m_bKeepBreakFinish) {
1536       m_pKeepHeadNode = pNextContainer;
1537       m_bIsProcessKeep = true;
1538     }
1539     return false;
1540   }
1541 
1542   if (m_bIsProcessKeep && m_pKeepHeadNode) {
1543     m_pKeepTailNode = pNextContainer;
1544     if (!m_bKeepBreakFinish &&
1545         FindBreakNode(pNextContainer->GetFirstChild(), pCurActionNode,
1546                       &nCurStage, true)) {
1547       return true;
1548     }
1549 
1550     pNextContainer = m_pKeepHeadNode;
1551     m_bKeepBreakFinish = true;
1552     m_pKeepHeadNode = nullptr;
1553     m_pKeepTailNode = nullptr;
1554     m_bIsProcessKeep = false;
1555   } else {
1556     if (m_bKeepBreakFinish)
1557       bLastKeepNode = true;
1558     m_bKeepBreakFinish = false;
1559   }
1560 
1561   return false;
1562 }
1563 
ProcessKeepNodesForBreakBefore(CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages & nCurStage,CXFA_Node * pContainerNode)1564 bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForBreakBefore(
1565     CXFA_Node*& pCurActionNode,
1566     XFA_ItemLayoutProcessorStages& nCurStage,
1567     CXFA_Node* pContainerNode) {
1568   if (m_pKeepTailNode == pContainerNode) {
1569     pCurActionNode = m_pKeepHeadNode;
1570     m_bKeepBreakFinish = true;
1571     m_pKeepHeadNode = nullptr;
1572     m_pKeepTailNode = nullptr;
1573     m_bIsProcessKeep = false;
1574     nCurStage = XFA_ItemLayoutProcessorStages::Container;
1575     return true;
1576   }
1577 
1578   CXFA_Node* pBreakAfterNode = pContainerNode->GetFirstChild();
1579   return FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, false);
1580 }
1581 
XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node * pNode)1582 bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode) {
1583   XFA_AttributeEnum ePresence = pNode->JSObject()
1584                                     ->TryEnum(XFA_Attribute::Presence, true)
1585                                     .value_or(XFA_AttributeEnum::Visible);
1586   return ePresence == XFA_AttributeEnum::Visible ||
1587          ePresence == XFA_AttributeEnum::Invisible;
1588 }
1589 
IncrementRelayoutNode(CXFA_LayoutProcessor * pLayoutProcessor,CXFA_Node * pNode,CXFA_Node * pParentNode)1590 bool CXFA_ItemLayoutProcessor::IncrementRelayoutNode(
1591     CXFA_LayoutProcessor* pLayoutProcessor,
1592     CXFA_Node* pNode,
1593     CXFA_Node* pParentNode) {
1594   return false;
1595 }
1596 
DoLayoutPageArea(CXFA_ContainerLayoutItem * pPageAreaLayoutItem)1597 void CXFA_ItemLayoutProcessor::DoLayoutPageArea(
1598     CXFA_ContainerLayoutItem* pPageAreaLayoutItem) {
1599   CXFA_Node* pFormNode = pPageAreaLayoutItem->m_pFormNode;
1600   CXFA_Node* pCurChildNode = XFA_LAYOUT_INVALIDNODE;
1601   XFA_ItemLayoutProcessorStages nCurChildNodeStage =
1602       XFA_ItemLayoutProcessorStages::None;
1603   CXFA_LayoutItem* pBeforeItem = nullptr;
1604   for (GotoNextContainerNode(pCurChildNode, nCurChildNodeStage, pFormNode,
1605                              false);
1606        pCurChildNode; GotoNextContainerNode(pCurChildNode, nCurChildNodeStage,
1607                                             pFormNode, false)) {
1608     if (nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
1609       continue;
1610     if (pCurChildNode->GetElementType() == XFA_Element::Variables)
1611       continue;
1612 
1613     auto pProcessor =
1614         pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pCurChildNode, nullptr);
1615     pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
1616     if (!pProcessor->HasLayoutItem())
1617       continue;
1618 
1619     pProcessor->SetCurrentComponentPos(CalculatePositionedContainerPos(
1620         pCurChildNode, pProcessor->GetCurrentComponentSize()));
1621     CXFA_LayoutItem* pProcessItem = pProcessor->ExtractLayoutItem();
1622     if (!pBeforeItem)
1623       pPageAreaLayoutItem->AddHeadChild(pProcessItem);
1624     else
1625       pPageAreaLayoutItem->InsertChild(pBeforeItem, pProcessItem);
1626 
1627     pBeforeItem = pProcessItem;
1628   }
1629 
1630   pBeforeItem = nullptr;
1631   CXFA_LayoutItem* pLayoutItem = pPageAreaLayoutItem->m_pFirstChild;
1632   while (pLayoutItem) {
1633     if (!pLayoutItem->IsContentLayoutItem() ||
1634         pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::Draw) {
1635       pLayoutItem = pLayoutItem->m_pNextSibling;
1636       continue;
1637     }
1638     if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::Draw)
1639       continue;
1640 
1641     CXFA_LayoutItem* pNextLayoutItem = pLayoutItem->m_pNextSibling;
1642     pPageAreaLayoutItem->RemoveChild(pLayoutItem);
1643     if (!pBeforeItem)
1644       pPageAreaLayoutItem->AddHeadChild(pLayoutItem);
1645     else
1646       pPageAreaLayoutItem->InsertChild(pBeforeItem, pLayoutItem);
1647 
1648     pBeforeItem = pLayoutItem;
1649     pLayoutItem = pNextLayoutItem;
1650   }
1651 }
1652 
DoLayoutPositionedContainer(CXFA_LayoutContext * pContext)1653 void CXFA_ItemLayoutProcessor::DoLayoutPositionedContainer(
1654     CXFA_LayoutContext* pContext) {
1655   if (m_pLayoutItem)
1656     return;
1657 
1658   m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
1659   bool bIgnoreXY = (m_pFormNode->JSObject()
1660                         ->TryEnum(XFA_Attribute::Layout, true)
1661                         .value_or(XFA_AttributeEnum::Position) !=
1662                     XFA_AttributeEnum::Position);
1663   bool bContainerWidthAutoSize = true;
1664   bool bContainerHeightAutoSize = true;
1665   CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
1666       m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
1667 
1668   float fContentCalculatedWidth = 0;
1669   float fContentCalculatedHeight = 0;
1670   float fHiddenContentCalculatedWidth = 0;
1671   float fHiddenContentCalculatedHeight = 0;
1672   if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
1673     GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
1674                           false);
1675   }
1676 
1677   int32_t iColIndex = 0;
1678   for (; m_pCurChildNode; GotoNextContainerNode(
1679            m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
1680     if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
1681       continue;
1682     if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
1683       continue;
1684 
1685     auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
1686         m_pCurChildNode, m_pPageMgr);
1687     if (pContext && pContext->m_prgSpecifiedColumnWidths) {
1688       int32_t iColSpan =
1689           m_pCurChildNode->JSObject()->GetInteger(XFA_Attribute::ColSpan);
1690       if (iColSpan <= pdfium::CollectionSize<int32_t>(
1691                           *pContext->m_prgSpecifiedColumnWidths) -
1692                           iColIndex) {
1693         pContext->m_fCurColumnWidth = 0;
1694         pContext->m_bCurColumnWidthAvaiable = true;
1695         if (iColSpan == -1) {
1696           iColSpan = pdfium::CollectionSize<int32_t>(
1697               *pContext->m_prgSpecifiedColumnWidths);
1698         }
1699         for (int32_t i = 0; iColIndex + i < iColSpan; ++i) {
1700           pContext->m_fCurColumnWidth +=
1701               (*pContext->m_prgSpecifiedColumnWidths)[iColIndex + i];
1702         }
1703         if (pContext->m_fCurColumnWidth == 0)
1704           pContext->m_bCurColumnWidthAvaiable = false;
1705 
1706         iColIndex += iColSpan >= 0 ? iColSpan : 0;
1707       }
1708     }
1709 
1710     pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pContext);
1711     if (!pProcessor->HasLayoutItem())
1712       continue;
1713 
1714     CFX_SizeF size = pProcessor->GetCurrentComponentSize();
1715     bool bChangeParentSize = false;
1716     if (XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode))
1717       bChangeParentSize = true;
1718 
1719     CFX_PointF absolutePos;
1720     if (!bIgnoreXY)
1721       absolutePos = CalculatePositionedContainerPos(m_pCurChildNode, size);
1722 
1723     pProcessor->SetCurrentComponentPos(absolutePos);
1724     if (bContainerWidthAutoSize) {
1725       float fChildSuppliedWidth = absolutePos.x + size.width;
1726       if (bChangeParentSize) {
1727         fContentCalculatedWidth =
1728             std::max(fContentCalculatedWidth, fChildSuppliedWidth);
1729       } else {
1730         if (fHiddenContentCalculatedWidth < fChildSuppliedWidth &&
1731             m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
1732           fHiddenContentCalculatedWidth = fChildSuppliedWidth;
1733         }
1734       }
1735     }
1736 
1737     if (bContainerHeightAutoSize) {
1738       float fChildSuppliedHeight = absolutePos.y + size.height;
1739       if (bChangeParentSize) {
1740         fContentCalculatedHeight =
1741             std::max(fContentCalculatedHeight, fChildSuppliedHeight);
1742       } else {
1743         if (fHiddenContentCalculatedHeight < fChildSuppliedHeight &&
1744             m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
1745           fHiddenContentCalculatedHeight = fChildSuppliedHeight;
1746         }
1747       }
1748     }
1749     m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
1750   }
1751 
1752   XFA_VERSION eVersion = m_pFormNode->GetDocument()->GetCurVersionMode();
1753   if (fContentCalculatedWidth == 0 && eVersion < XFA_VERSION_207)
1754     fContentCalculatedWidth = fHiddenContentCalculatedWidth;
1755   if (fContentCalculatedHeight == 0 && eVersion < XFA_VERSION_207)
1756     fContentCalculatedHeight = fHiddenContentCalculatedHeight;
1757 
1758   containerSize = CalculateContainerComponentSizeFromContentSize(
1759       m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
1760       bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
1761   SetCurrentComponentSize(containerSize);
1762 }
1763 
DoLayoutTableContainer(CXFA_Node * pLayoutNode)1764 void CXFA_ItemLayoutProcessor::DoLayoutTableContainer(CXFA_Node* pLayoutNode) {
1765   if (m_pLayoutItem)
1766     return;
1767   if (!pLayoutNode)
1768     pLayoutNode = m_pFormNode;
1769 
1770   ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
1771 
1772   m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
1773   bool bContainerWidthAutoSize = true;
1774   bool bContainerHeightAutoSize = true;
1775   CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
1776       m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
1777   float fContentCalculatedWidth = 0;
1778   float fContentCalculatedHeight = 0;
1779   CXFA_Margin* pMarginNode =
1780       m_pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
1781   float fLeftInset = 0;
1782   float fRightInset = 0;
1783   if (pMarginNode) {
1784     fLeftInset = pMarginNode->JSObject()
1785                      ->GetMeasure(XFA_Attribute::LeftInset)
1786                      .ToUnit(XFA_Unit::Pt);
1787     fRightInset = pMarginNode->JSObject()
1788                       ->GetMeasure(XFA_Attribute::RightInset)
1789                       .ToUnit(XFA_Unit::Pt);
1790   }
1791 
1792   float fContentWidthLimit =
1793       bContainerWidthAutoSize ? FLT_MAX
1794                               : containerSize.width - fLeftInset - fRightInset;
1795   WideString wsColumnWidths =
1796       pLayoutNode->JSObject()->GetCData(XFA_Attribute::ColumnWidths);
1797   if (!wsColumnWidths.IsEmpty()) {
1798     auto widths = SeparateStringW(wsColumnWidths.c_str(),
1799                                   wsColumnWidths.GetLength(), L' ');
1800     for (auto& width : widths) {
1801       width.TrimLeft(L' ');
1802       if (width.IsEmpty())
1803         continue;
1804 
1805       m_rgSpecifiedColumnWidths.push_back(
1806           CXFA_Measurement(width.AsStringView()).ToUnit(XFA_Unit::Pt));
1807     }
1808   }
1809 
1810   int32_t iSpecifiedColumnCount =
1811       pdfium::CollectionSize<int32_t>(m_rgSpecifiedColumnWidths);
1812   CXFA_LayoutContext layoutContext;
1813   layoutContext.m_prgSpecifiedColumnWidths = &m_rgSpecifiedColumnWidths;
1814   CXFA_LayoutContext* pLayoutContext =
1815       iSpecifiedColumnCount > 0 ? &layoutContext : nullptr;
1816   if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
1817     GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
1818                           false);
1819   }
1820 
1821   for (; m_pCurChildNode; GotoNextContainerNode(
1822            m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
1823     layoutContext.m_bCurColumnWidthAvaiable = false;
1824     layoutContext.m_fCurColumnWidth = 0;
1825     if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
1826       continue;
1827 
1828     auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
1829         m_pCurChildNode, m_pPageMgr);
1830     pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pLayoutContext);
1831     if (!pProcessor->HasLayoutItem())
1832       continue;
1833 
1834     m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
1835   }
1836 
1837   int32_t iRowCount = 0;
1838   int32_t iColCount = 0;
1839   {
1840     std::vector<CXFA_ContentLayoutItem*> rgRowItems;
1841     std::vector<int32_t> rgRowItemsSpan;
1842     std::vector<float> rgRowItemsWidth;
1843     for (auto* pLayoutChild =
1844              static_cast<CXFA_ContentLayoutItem*>(m_pLayoutItem->m_pFirstChild);
1845          pLayoutChild; pLayoutChild = static_cast<CXFA_ContentLayoutItem*>(
1846                            pLayoutChild->m_pNextSibling)) {
1847       if (pLayoutChild->m_pFormNode->GetElementType() != XFA_Element::Subform)
1848         continue;
1849       if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
1850         continue;
1851 
1852       XFA_AttributeEnum eLayout =
1853           pLayoutChild->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
1854       if (eLayout != XFA_AttributeEnum::Row &&
1855           eLayout != XFA_AttributeEnum::Rl_row) {
1856         continue;
1857       }
1858       if (CXFA_ContentLayoutItem* pRowLayoutCell =
1859               (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild) {
1860         rgRowItems.push_back(pRowLayoutCell);
1861         int32_t iColSpan = pRowLayoutCell->m_pFormNode->JSObject()->GetInteger(
1862             XFA_Attribute::ColSpan);
1863         rgRowItemsSpan.push_back(iColSpan);
1864         rgRowItemsWidth.push_back(pRowLayoutCell->m_sSize.width);
1865       }
1866     }
1867 
1868     iRowCount = pdfium::CollectionSize<int32_t>(rgRowItems);
1869     iColCount = 0;
1870     bool bMoreColumns = true;
1871     while (bMoreColumns) {
1872       bMoreColumns = false;
1873       bool bAutoCol = false;
1874       for (int32_t i = 0; i < iRowCount; i++) {
1875         while (rgRowItems[i] && (rgRowItemsSpan[i] <= 0 ||
1876                                  !XFA_ItemLayoutProcessor_IsTakingSpace(
1877                                      rgRowItems[i]->m_pFormNode))) {
1878           CXFA_ContentLayoutItem* pNewCell =
1879               (CXFA_ContentLayoutItem*)rgRowItems[i]->m_pNextSibling;
1880           if (rgRowItemsSpan[i] < 0 && XFA_ItemLayoutProcessor_IsTakingSpace(
1881                                            rgRowItems[i]->m_pFormNode)) {
1882             pNewCell = nullptr;
1883           }
1884           rgRowItems[i] = pNewCell;
1885           rgRowItemsSpan[i] =
1886               pNewCell ? pNewCell->m_pFormNode->JSObject()->GetInteger(
1887                              XFA_Attribute::ColSpan)
1888                        : 0;
1889           rgRowItemsWidth[i] = pNewCell ? pNewCell->m_sSize.width : 0;
1890         }
1891         CXFA_ContentLayoutItem* pCell = rgRowItems[i];
1892         if (!pCell)
1893           continue;
1894 
1895         bMoreColumns = true;
1896         if (rgRowItemsSpan[i] != 1)
1897           continue;
1898 
1899         if (iColCount >= iSpecifiedColumnCount) {
1900           int32_t c = iColCount + 1 - pdfium::CollectionSize<int32_t>(
1901                                           m_rgSpecifiedColumnWidths);
1902           for (int32_t j = 0; j < c; j++)
1903             m_rgSpecifiedColumnWidths.push_back(0);
1904         }
1905         if (m_rgSpecifiedColumnWidths[iColCount] < XFA_LAYOUT_FLOAT_PERCISION)
1906           bAutoCol = true;
1907         if (bAutoCol &&
1908             m_rgSpecifiedColumnWidths[iColCount] < rgRowItemsWidth[i]) {
1909           m_rgSpecifiedColumnWidths[iColCount] = rgRowItemsWidth[i];
1910         }
1911       }
1912 
1913       if (!bMoreColumns)
1914         continue;
1915 
1916       float fFinalColumnWidth = 0.0f;
1917       if (pdfium::IndexInBounds(m_rgSpecifiedColumnWidths, iColCount))
1918         fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount];
1919 
1920       for (int32_t i = 0; i < iRowCount; ++i) {
1921         if (!rgRowItems[i])
1922           continue;
1923         --rgRowItemsSpan[i];
1924         rgRowItemsWidth[i] -= fFinalColumnWidth;
1925       }
1926       ++iColCount;
1927     }
1928   }
1929 
1930   float fCurrentRowY = 0;
1931   for (CXFA_ContentLayoutItem* pLayoutChild =
1932            (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
1933        pLayoutChild;
1934        pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
1935     if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
1936       continue;
1937 
1938     if (pLayoutChild->m_pFormNode->GetElementType() == XFA_Element::Subform) {
1939       XFA_AttributeEnum eSubformLayout =
1940           pLayoutChild->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
1941       if (eSubformLayout == XFA_AttributeEnum::Row ||
1942           eSubformLayout == XFA_AttributeEnum::Rl_row) {
1943         RelocateTableRowCells(pLayoutChild, m_rgSpecifiedColumnWidths,
1944                               eSubformLayout);
1945       }
1946     }
1947 
1948     pLayoutChild->m_sPos.y = fCurrentRowY;
1949     if (bContainerWidthAutoSize) {
1950       pLayoutChild->m_sPos.x = 0;
1951     } else {
1952       switch (pLayoutChild->m_pFormNode->JSObject()->GetEnum(
1953           XFA_Attribute::HAlign)) {
1954         case XFA_AttributeEnum::Center:
1955           pLayoutChild->m_sPos.x =
1956               (fContentWidthLimit - pLayoutChild->m_sSize.width) / 2;
1957           break;
1958         case XFA_AttributeEnum::Right:
1959           pLayoutChild->m_sPos.x =
1960               fContentWidthLimit - pLayoutChild->m_sSize.width;
1961           break;
1962         case XFA_AttributeEnum::Left:
1963         default:
1964           pLayoutChild->m_sPos.x = 0;
1965           break;
1966       }
1967     }
1968 
1969     if (bContainerWidthAutoSize) {
1970       float fChildSuppliedWidth =
1971           pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.width;
1972       if (fContentWidthLimit < FLT_MAX &&
1973           fContentWidthLimit > fChildSuppliedWidth) {
1974         fChildSuppliedWidth = fContentWidthLimit;
1975       }
1976       fContentCalculatedWidth =
1977           std::max(fContentCalculatedWidth, fChildSuppliedWidth);
1978     }
1979     fCurrentRowY += pLayoutChild->m_sSize.height;
1980   }
1981 
1982   if (bContainerHeightAutoSize)
1983     fContentCalculatedHeight = std::max(fContentCalculatedHeight, fCurrentRowY);
1984 
1985   containerSize = CalculateContainerComponentSizeFromContentSize(
1986       m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
1987       bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
1988   SetCurrentComponentSize(containerSize);
1989 }
1990 
IsAddNewRowForTrailer(CXFA_ContentLayoutItem * pTrailerItem)1991 bool CXFA_ItemLayoutProcessor::IsAddNewRowForTrailer(
1992     CXFA_ContentLayoutItem* pTrailerItem) {
1993   if (!pTrailerItem)
1994     return false;
1995 
1996   float fWidth = pTrailerItem->m_sSize.width;
1997   XFA_AttributeEnum eLayout =
1998       m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
1999   return eLayout == XFA_AttributeEnum::Tb || m_fWidthLimite <= fWidth;
2000 }
2001 
InsertKeepLayoutItems()2002 float CXFA_ItemLayoutProcessor::InsertKeepLayoutItems() {
2003   if (m_arrayKeepItems.empty())
2004     return 0;
2005 
2006   if (!m_pLayoutItem) {
2007     m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
2008     m_pLayoutItem->m_sSize.clear();
2009   }
2010 
2011   float fTotalHeight = 0;
2012   for (auto iter = m_arrayKeepItems.rbegin(); iter != m_arrayKeepItems.rend();
2013        iter++) {
2014     AddLeaderAfterSplit(this, *iter);
2015     fTotalHeight += (*iter)->m_sSize.height;
2016   }
2017   m_arrayKeepItems.clear();
2018 
2019   return fTotalHeight;
2020 }
2021 
ProcessKeepForSplit(CXFA_ItemLayoutProcessor * pParentProcessor,CXFA_ItemLayoutProcessor * pChildProcessor,XFA_ItemLayoutProcessorResult eRetValue,std::vector<CXFA_ContentLayoutItem * > * rgCurLineLayoutItem,float * fContentCurRowAvailWidth,float * fContentCurRowHeight,float * fContentCurRowY,bool * bAddedItemInRow,bool * bForceEndPage,XFA_ItemLayoutProcessorResult * result)2022 bool CXFA_ItemLayoutProcessor::ProcessKeepForSplit(
2023     CXFA_ItemLayoutProcessor* pParentProcessor,
2024     CXFA_ItemLayoutProcessor* pChildProcessor,
2025     XFA_ItemLayoutProcessorResult eRetValue,
2026     std::vector<CXFA_ContentLayoutItem*>* rgCurLineLayoutItem,
2027     float* fContentCurRowAvailWidth,
2028     float* fContentCurRowHeight,
2029     float* fContentCurRowY,
2030     bool* bAddedItemInRow,
2031     bool* bForceEndPage,
2032     XFA_ItemLayoutProcessorResult* result) {
2033   if (!pParentProcessor || !pChildProcessor)
2034     return false;
2035 
2036   if (pParentProcessor->m_pCurChildNode->GetIntact() ==
2037           XFA_AttributeEnum::None &&
2038       pChildProcessor->m_bHasAvailHeight)
2039     return false;
2040 
2041   if (!ExistContainerKeep(pParentProcessor->m_pCurChildNode, true))
2042     return false;
2043 
2044   CFX_SizeF childSize = pChildProcessor->GetCurrentComponentSize();
2045   std::vector<CXFA_ContentLayoutItem*> keepLayoutItems;
2046   if (pParentProcessor->JudgePutNextPage(pParentProcessor->m_pLayoutItem,
2047                                          childSize.height, &keepLayoutItems)) {
2048     m_arrayKeepItems.clear();
2049 
2050     for (auto* item : keepLayoutItems) {
2051       pParentProcessor->m_pLayoutItem->RemoveChild(item);
2052       *fContentCurRowY -= item->m_sSize.height;
2053       m_arrayKeepItems.push_back(item);
2054     }
2055     *bAddedItemInRow = true;
2056     *bForceEndPage = true;
2057     *result = XFA_ItemLayoutProcessorResult::PageFullBreak;
2058     return true;
2059   }
2060 
2061   rgCurLineLayoutItem->push_back(pChildProcessor->ExtractLayoutItem());
2062   *bAddedItemInRow = true;
2063   *fContentCurRowAvailWidth -= childSize.width;
2064   *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
2065   *result = eRetValue;
2066 
2067   return true;
2068 }
2069 
JudgePutNextPage(CXFA_ContentLayoutItem * pParentLayoutItem,float fChildHeight,std::vector<CXFA_ContentLayoutItem * > * pKeepItems)2070 bool CXFA_ItemLayoutProcessor::JudgePutNextPage(
2071     CXFA_ContentLayoutItem* pParentLayoutItem,
2072     float fChildHeight,
2073     std::vector<CXFA_ContentLayoutItem*>* pKeepItems) {
2074   if (!pParentLayoutItem)
2075     return false;
2076 
2077   float fItemsHeight = 0;
2078   for (CXFA_ContentLayoutItem* pChildLayoutItem =
2079            (CXFA_ContentLayoutItem*)pParentLayoutItem->m_pFirstChild;
2080        pChildLayoutItem;
2081        pChildLayoutItem =
2082            (CXFA_ContentLayoutItem*)pChildLayoutItem->m_pNextSibling) {
2083     if (ExistContainerKeep(pChildLayoutItem->m_pFormNode, false)) {
2084       pKeepItems->push_back(pChildLayoutItem);
2085       fItemsHeight += pChildLayoutItem->m_sSize.height;
2086     } else {
2087       pKeepItems->clear();
2088       fItemsHeight = 0;
2089     }
2090   }
2091   fItemsHeight += fChildHeight;
2092   return m_pPageMgr->GetNextAvailContentHeight(fItemsHeight);
2093 }
2094 
ProcessUnUseBinds(CXFA_Node * pFormNode)2095 void CXFA_ItemLayoutProcessor::ProcessUnUseBinds(CXFA_Node* pFormNode) {
2096   if (!pFormNode)
2097     return;
2098 
2099   CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
2100       pFormNode);
2101   for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
2102        pNode = sIterator.MoveToNext()) {
2103     if (pNode->IsContainerNode()) {
2104       CXFA_Node* pBindNode = pNode->GetBindData();
2105       if (pBindNode) {
2106         pBindNode->RemoveBindItem(pNode);
2107         pNode->SetBindingNode(nullptr);
2108       }
2109     }
2110     pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
2111   }
2112 }
2113 
ProcessUnUseOverFlow(CXFA_Node * pLeaderNode,CXFA_Node * pTrailerNode,CXFA_ContentLayoutItem * pTrailerItem,CXFA_Node * pFormNode)2114 void CXFA_ItemLayoutProcessor::ProcessUnUseOverFlow(
2115     CXFA_Node* pLeaderNode,
2116     CXFA_Node* pTrailerNode,
2117     CXFA_ContentLayoutItem* pTrailerItem,
2118     CXFA_Node* pFormNode) {
2119   ProcessUnUseBinds(pLeaderNode);
2120   ProcessUnUseBinds(pTrailerNode);
2121   if (!pFormNode)
2122     return;
2123 
2124   if (pFormNode->GetElementType() == XFA_Element::Overflow ||
2125       pFormNode->GetElementType() == XFA_Element::Break) {
2126     pFormNode = pFormNode->GetParent();
2127   }
2128   if (pLeaderNode && pFormNode)
2129     pFormNode->RemoveChild(pLeaderNode, true);
2130   if (pTrailerNode && pFormNode)
2131     pFormNode->RemoveChild(pTrailerNode, true);
2132   if (pTrailerItem)
2133     XFA_ReleaseLayoutItem(pTrailerItem);
2134 }
2135 
DoLayoutFlowedContainer(bool bUseBreakControl,XFA_AttributeEnum eFlowStrategy,float fHeightLimit,float fRealHeight,CXFA_LayoutContext * pContext,bool bRootForceTb)2136 XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayoutFlowedContainer(
2137     bool bUseBreakControl,
2138     XFA_AttributeEnum eFlowStrategy,
2139     float fHeightLimit,
2140     float fRealHeight,
2141     CXFA_LayoutContext* pContext,
2142     bool bRootForceTb) {
2143   m_bHasAvailHeight = true;
2144   bool bBreakDone = false;
2145   bool bContainerWidthAutoSize = true;
2146   bool bContainerHeightAutoSize = true;
2147   bool bForceEndPage = false;
2148   bool bIsManualBreak = false;
2149   if (m_pCurChildPreprocessor) {
2150     m_pCurChildPreprocessor->m_ePreProcessRs =
2151         XFA_ItemLayoutProcessorResult::Done;
2152   }
2153 
2154   CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
2155       m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
2156   if (pContext && pContext->m_bCurColumnWidthAvaiable) {
2157     bContainerWidthAutoSize = false;
2158     containerSize.width = pContext->m_fCurColumnWidth;
2159   }
2160   if (!bContainerHeightAutoSize)
2161     containerSize.height -= m_fUsedSize;
2162 
2163   if (!bContainerHeightAutoSize) {
2164     CXFA_Node* pParentNode = m_pFormNode->GetParent();
2165     bool bFocrTb = false;
2166     if (pParentNode &&
2167         GetLayout(pParentNode, &bFocrTb) == XFA_AttributeEnum::Row) {
2168       CXFA_Node* pChildContainer = m_pFormNode->GetFirstContainerChild();
2169       if (pChildContainer && pChildContainer->GetNextContainerSibling()) {
2170         containerSize.height = 0;
2171         bContainerHeightAutoSize = true;
2172       }
2173     }
2174   }
2175 
2176   CXFA_Margin* pMarginNode =
2177       m_pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
2178   float fLeftInset = 0;
2179   float fTopInset = 0;
2180   float fRightInset = 0;
2181   float fBottomInset = 0;
2182   if (pMarginNode) {
2183     fLeftInset = pMarginNode->JSObject()
2184                      ->GetMeasure(XFA_Attribute::LeftInset)
2185                      .ToUnit(XFA_Unit::Pt);
2186     fTopInset = pMarginNode->JSObject()
2187                     ->GetMeasure(XFA_Attribute::TopInset)
2188                     .ToUnit(XFA_Unit::Pt);
2189     fRightInset = pMarginNode->JSObject()
2190                       ->GetMeasure(XFA_Attribute::RightInset)
2191                       .ToUnit(XFA_Unit::Pt);
2192     fBottomInset = pMarginNode->JSObject()
2193                        ->GetMeasure(XFA_Attribute::BottomInset)
2194                        .ToUnit(XFA_Unit::Pt);
2195   }
2196   float fContentWidthLimit =
2197       bContainerWidthAutoSize ? FLT_MAX
2198                               : containerSize.width - fLeftInset - fRightInset;
2199   float fContentCalculatedWidth = 0;
2200   float fContentCalculatedHeight = 0;
2201   float fAvailHeight = fHeightLimit - fTopInset - fBottomInset;
2202   if (fAvailHeight < 0)
2203     m_bHasAvailHeight = false;
2204 
2205   fRealHeight = fRealHeight - fTopInset - fBottomInset;
2206   float fContentCurRowY = 0;
2207   CXFA_ContentLayoutItem* pLayoutChild = nullptr;
2208   if (m_pLayoutItem) {
2209     if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done &&
2210         eFlowStrategy != XFA_AttributeEnum::Tb) {
2211       pLayoutChild = (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
2212       for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
2213            pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
2214         if (pLayoutNext->m_sPos.y != pLayoutChild->m_sPos.y)
2215           pLayoutChild = pLayoutNext;
2216       }
2217     }
2218 
2219     for (CXFA_ContentLayoutItem* pLayoutTempChild =
2220              (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
2221          pLayoutTempChild != pLayoutChild;
2222          pLayoutTempChild =
2223              (CXFA_ContentLayoutItem*)pLayoutTempChild->m_pNextSibling) {
2224       if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutTempChild->m_pFormNode))
2225         continue;
2226 
2227       fContentCalculatedWidth = std::max(
2228           fContentCalculatedWidth,
2229           pLayoutTempChild->m_sPos.x + pLayoutTempChild->m_sSize.width);
2230       fContentCalculatedHeight = std::max(
2231           fContentCalculatedHeight,
2232           pLayoutTempChild->m_sPos.y + pLayoutTempChild->m_sSize.height);
2233     }
2234 
2235     if (pLayoutChild)
2236       fContentCurRowY = pLayoutChild->m_sPos.y;
2237     else
2238       fContentCurRowY = fContentCalculatedHeight;
2239   }
2240 
2241   fContentCurRowY += InsertKeepLayoutItems();
2242   if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::None) {
2243     GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
2244                           true);
2245   }
2246 
2247   fContentCurRowY += InsertPendingItems(this, m_pFormNode);
2248   if (m_pCurChildPreprocessor &&
2249       m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Container) {
2250     if (ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) {
2251       m_pKeepHeadNode = m_pCurChildNode;
2252       m_bIsProcessKeep = true;
2253       m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Keep;
2254     }
2255   }
2256 
2257   while (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done) {
2258     float fContentCurRowHeight = 0;
2259     float fContentCurRowAvailWidth = fContentWidthLimit;
2260     m_fWidthLimite = fContentCurRowAvailWidth;
2261     std::vector<CXFA_ContentLayoutItem*> rgCurLineLayoutItems[3];
2262     uint8_t uCurHAlignState =
2263         (eFlowStrategy != XFA_AttributeEnum::Rl_tb ? 0 : 2);
2264     if (pLayoutChild) {
2265       for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
2266            pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
2267         if (!pLayoutNext->m_pNextSibling && m_pCurChildPreprocessor &&
2268             m_pCurChildPreprocessor->m_pFormNode == pLayoutNext->m_pFormNode) {
2269           pLayoutNext->m_pNext = m_pCurChildPreprocessor->m_pLayoutItem;
2270           m_pCurChildPreprocessor->m_pLayoutItem = pLayoutNext;
2271           break;
2272         }
2273         uint8_t uHAlign =
2274             HAlignEnumToInt(pLayoutNext->m_pFormNode->JSObject()->GetEnum(
2275                 XFA_Attribute::HAlign));
2276         rgCurLineLayoutItems[uHAlign].push_back(pLayoutNext);
2277         if (eFlowStrategy == XFA_AttributeEnum::Lr_tb) {
2278           if (uHAlign > uCurHAlignState)
2279             uCurHAlignState = uHAlign;
2280         } else if (uHAlign < uCurHAlignState) {
2281           uCurHAlignState = uHAlign;
2282         }
2283         if (XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutNext->m_pFormNode)) {
2284           if (pLayoutNext->m_sSize.height > fContentCurRowHeight)
2285             fContentCurRowHeight = pLayoutNext->m_sSize.height;
2286           fContentCurRowAvailWidth -= pLayoutNext->m_sSize.width;
2287         }
2288       }
2289 
2290       if ((CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild ==
2291           pLayoutChild) {
2292         m_pLayoutItem->m_pFirstChild = nullptr;
2293       } else {
2294         CXFA_ContentLayoutItem* pLayoutNext =
2295             (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
2296         for (; pLayoutNext;
2297              pLayoutNext =
2298                  (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
2299           if ((CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling ==
2300               pLayoutChild) {
2301             pLayoutNext->m_pNextSibling = nullptr;
2302             break;
2303           }
2304         }
2305       }
2306 
2307       CXFA_ContentLayoutItem* pLayoutNextTemp =
2308           (CXFA_ContentLayoutItem*)pLayoutChild;
2309       while (pLayoutNextTemp) {
2310         pLayoutNextTemp->m_pParent = nullptr;
2311         CXFA_ContentLayoutItem* pSaveLayoutNext =
2312             (CXFA_ContentLayoutItem*)pLayoutNextTemp->m_pNextSibling;
2313         pLayoutNextTemp->m_pNextSibling = nullptr;
2314         pLayoutNextTemp = pSaveLayoutNext;
2315       }
2316       pLayoutChild = nullptr;
2317     }
2318 
2319     while (m_pCurChildNode) {
2320       std::unique_ptr<CXFA_ItemLayoutProcessor> pProcessor;
2321       bool bAddedItemInRow = false;
2322       fContentCurRowY += InsertPendingItems(this, m_pFormNode);
2323       switch (m_nCurChildNodeStage) {
2324         case XFA_ItemLayoutProcessorStages::Keep:
2325         case XFA_ItemLayoutProcessorStages::None:
2326           break;
2327         case XFA_ItemLayoutProcessorStages::BreakBefore: {
2328           for (auto* item : m_arrayKeepItems) {
2329             m_pLayoutItem->RemoveChild(item);
2330             fContentCalculatedHeight -= item->m_sSize.height;
2331           }
2332 
2333           CXFA_Node* pLeaderNode = nullptr;
2334           CXFA_Node* pTrailerNode = nullptr;
2335           bool bCreatePage = false;
2336           if (!bUseBreakControl || !m_pPageMgr ||
2337               !m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, true,
2338                                                      pLeaderNode, pTrailerNode,
2339                                                      bCreatePage) ||
2340               m_pFormNode->GetElementType() == XFA_Element::Form ||
2341               !bCreatePage) {
2342             break;
2343           }
2344 
2345           if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
2346             AddPendingNode(this, pLeaderNode, true);
2347 
2348           if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
2349             if (m_pFormNode->GetParent()->GetElementType() ==
2350                     XFA_Element::Form &&
2351                 !m_pLayoutItem) {
2352               AddPendingNode(this, pTrailerNode, true);
2353             } else {
2354               auto pTempProcessor =
2355                   pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pTrailerNode,
2356                                                                nullptr);
2357               InsertFlowedItem(
2358                   this, pTempProcessor.get(), bContainerWidthAutoSize,
2359                   bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2360                   &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX,
2361                   FLT_MAX, fContentWidthLimit, &fContentCurRowY,
2362                   &fContentCurRowAvailWidth, &fContentCurRowHeight,
2363                   &bAddedItemInRow, &bForceEndPage, pContext, false);
2364             }
2365           }
2366           GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage,
2367                                 m_pFormNode, true);
2368           bForceEndPage = true;
2369           bIsManualBreak = true;
2370           goto SuspendAndCreateNewRow;
2371         }
2372         case XFA_ItemLayoutProcessorStages::BreakAfter: {
2373           CXFA_Node* pLeaderNode = nullptr;
2374           CXFA_Node* pTrailerNode = nullptr;
2375           bool bCreatePage = false;
2376           if (!bUseBreakControl || !m_pPageMgr ||
2377               !m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, false,
2378                                                      pLeaderNode, pTrailerNode,
2379                                                      bCreatePage) ||
2380               m_pFormNode->GetElementType() == XFA_Element::Form) {
2381             break;
2382           }
2383 
2384           if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
2385             auto pTempProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2386                 pTrailerNode, nullptr);
2387             InsertFlowedItem(
2388                 this, pTempProcessor.get(), bContainerWidthAutoSize,
2389                 bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2390                 &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX, FLT_MAX,
2391                 fContentWidthLimit, &fContentCurRowY, &fContentCurRowAvailWidth,
2392                 &fContentCurRowHeight, &bAddedItemInRow, &bForceEndPage,
2393                 pContext, false);
2394           }
2395           if (!bCreatePage) {
2396             if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
2397               CalculateRowChildPosition(
2398                   rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
2399                   bContainerWidthAutoSize, &fContentCalculatedWidth,
2400                   &fContentCalculatedHeight, &fContentCurRowY,
2401                   fContentCurRowHeight, fContentWidthLimit, false);
2402               rgCurLineLayoutItems->clear();
2403               auto pTempProcessor =
2404                   pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pLeaderNode,
2405                                                                nullptr);
2406               InsertFlowedItem(
2407                   this, pTempProcessor.get(), bContainerWidthAutoSize,
2408                   bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2409                   &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX,
2410                   FLT_MAX, fContentWidthLimit, &fContentCurRowY,
2411                   &fContentCurRowAvailWidth, &fContentCurRowHeight,
2412                   &bAddedItemInRow, &bForceEndPage, pContext, false);
2413             }
2414           } else {
2415             if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
2416               AddPendingNode(this, pLeaderNode, true);
2417           }
2418 
2419           GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage,
2420                                 m_pFormNode, true);
2421           if (bCreatePage) {
2422             bForceEndPage = true;
2423             bIsManualBreak = true;
2424             if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done)
2425               bBreakDone = true;
2426           }
2427           goto SuspendAndCreateNewRow;
2428         }
2429         case XFA_ItemLayoutProcessorStages::BookendLeader: {
2430           CXFA_Node* pLeaderNode = nullptr;
2431           if (m_pCurChildPreprocessor) {
2432             pProcessor.reset(m_pCurChildPreprocessor);
2433             m_pCurChildPreprocessor = nullptr;
2434           } else if (m_pPageMgr &&
2435                      m_pPageMgr->ProcessBookendLeaderOrTrailer(
2436                          m_pCurChildNode, true, pLeaderNode)) {
2437             pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2438                 pLeaderNode, m_pPageMgr);
2439           }
2440 
2441           if (pProcessor) {
2442             if (InsertFlowedItem(
2443                     this, pProcessor.get(), bContainerWidthAutoSize,
2444                     bContainerHeightAutoSize, containerSize.height,
2445                     eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
2446                     bUseBreakControl, fAvailHeight, fRealHeight,
2447                     fContentWidthLimit, &fContentCurRowY,
2448                     &fContentCurRowAvailWidth, &fContentCurRowHeight,
2449                     &bAddedItemInRow, &bForceEndPage, pContext,
2450                     false) != XFA_ItemLayoutProcessorResult::Done) {
2451               goto SuspendAndCreateNewRow;
2452             } else {
2453               pProcessor.reset();
2454             }
2455           }
2456           break;
2457         }
2458         case XFA_ItemLayoutProcessorStages::BookendTrailer: {
2459           CXFA_Node* pTrailerNode = nullptr;
2460           if (m_pCurChildPreprocessor) {
2461             pProcessor.reset(m_pCurChildPreprocessor);
2462             m_pCurChildPreprocessor = nullptr;
2463           } else if (m_pPageMgr &&
2464                      m_pPageMgr->ProcessBookendLeaderOrTrailer(
2465                          m_pCurChildNode, false, pTrailerNode)) {
2466             pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2467                 pTrailerNode, m_pPageMgr);
2468           }
2469           if (pProcessor) {
2470             if (InsertFlowedItem(
2471                     this, pProcessor.get(), bContainerWidthAutoSize,
2472                     bContainerHeightAutoSize, containerSize.height,
2473                     eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
2474                     bUseBreakControl, fAvailHeight, fRealHeight,
2475                     fContentWidthLimit, &fContentCurRowY,
2476                     &fContentCurRowAvailWidth, &fContentCurRowHeight,
2477                     &bAddedItemInRow, &bForceEndPage, pContext,
2478                     false) != XFA_ItemLayoutProcessorResult::Done) {
2479               goto SuspendAndCreateNewRow;
2480             } else {
2481               pProcessor.reset();
2482             }
2483           }
2484           break;
2485         }
2486         case XFA_ItemLayoutProcessorStages::Container: {
2487           ASSERT(m_pCurChildNode->IsContainerNode());
2488           if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
2489             break;
2490           if (fContentCurRowY >= fHeightLimit + XFA_LAYOUT_FLOAT_PERCISION &&
2491               XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode)) {
2492             bForceEndPage = true;
2493             goto SuspendAndCreateNewRow;
2494           }
2495           if (!m_pCurChildNode->IsContainerNode())
2496             break;
2497 
2498           bool bNewRow = false;
2499           if (m_pCurChildPreprocessor) {
2500             pProcessor.reset(m_pCurChildPreprocessor);
2501             m_pCurChildPreprocessor = nullptr;
2502             bNewRow = true;
2503           } else {
2504             pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2505                 m_pCurChildNode, m_pPageMgr);
2506           }
2507 
2508           InsertPendingItems(pProcessor.get(), m_pCurChildNode);
2509           XFA_ItemLayoutProcessorResult rs = InsertFlowedItem(
2510               this, pProcessor.get(), bContainerWidthAutoSize,
2511               bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2512               &uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
2513               fAvailHeight, fRealHeight, fContentWidthLimit, &fContentCurRowY,
2514               &fContentCurRowAvailWidth, &fContentCurRowHeight,
2515               &bAddedItemInRow, &bForceEndPage, pContext, bNewRow);
2516           switch (rs) {
2517             case XFA_ItemLayoutProcessorResult::ManualBreak:
2518               bIsManualBreak = true;
2519             case XFA_ItemLayoutProcessorResult::PageFullBreak:
2520               bForceEndPage = true;
2521             case XFA_ItemLayoutProcessorResult::RowFullBreak:
2522               goto SuspendAndCreateNewRow;
2523             case XFA_ItemLayoutProcessorResult::Done:
2524             default:
2525               fContentCurRowY +=
2526                   InsertPendingItems(pProcessor.get(), m_pCurChildNode);
2527               pProcessor.reset();
2528           }
2529           break;
2530         }
2531         case XFA_ItemLayoutProcessorStages::Done:
2532           break;
2533         default:
2534           break;
2535       }
2536       GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
2537                             true);
2538       if (bAddedItemInRow && eFlowStrategy == XFA_AttributeEnum::Tb)
2539         break;
2540       continue;
2541     SuspendAndCreateNewRow:
2542       if (pProcessor)
2543         m_pCurChildPreprocessor = pProcessor.release();
2544       break;
2545     }
2546 
2547     CalculateRowChildPosition(
2548         rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
2549         bContainerWidthAutoSize, &fContentCalculatedWidth,
2550         &fContentCalculatedHeight, &fContentCurRowY, fContentCurRowHeight,
2551         fContentWidthLimit, bRootForceTb);
2552     m_fWidthLimite = fContentCurRowAvailWidth;
2553     if (bForceEndPage)
2554       break;
2555   }
2556 
2557   bool bRetValue =
2558       m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done &&
2559       m_PendingNodes.empty();
2560   if (bBreakDone)
2561     bRetValue = false;
2562 
2563   containerSize = CalculateContainerComponentSizeFromContentSize(
2564       m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
2565       bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
2566 
2567   if (containerSize.height >= XFA_LAYOUT_FLOAT_PERCISION || m_pLayoutItem ||
2568       bRetValue) {
2569     if (!m_pLayoutItem)
2570       m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
2571     containerSize.height = std::max(containerSize.height, 0.f);
2572 
2573     SetCurrentComponentSize(containerSize);
2574     if (bForceEndPage)
2575       m_fUsedSize = 0;
2576     else
2577       m_fUsedSize += m_pLayoutItem->m_sSize.height;
2578   }
2579 
2580   return bRetValue
2581              ? XFA_ItemLayoutProcessorResult::Done
2582              : (bIsManualBreak ? XFA_ItemLayoutProcessorResult::ManualBreak
2583                                : XFA_ItemLayoutProcessorResult::PageFullBreak);
2584 }
2585 
CalculateRowChildPosition(std::vector<CXFA_ContentLayoutItem * > (& rgCurLineLayoutItems)[3],XFA_AttributeEnum eFlowStrategy,bool bContainerHeightAutoSize,bool bContainerWidthAutoSize,float * fContentCalculatedWidth,float * fContentCalculatedHeight,float * fContentCurRowY,float fContentCurRowHeight,float fContentWidthLimit,bool bRootForceTb)2586 bool CXFA_ItemLayoutProcessor::CalculateRowChildPosition(
2587     std::vector<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
2588     XFA_AttributeEnum eFlowStrategy,
2589     bool bContainerHeightAutoSize,
2590     bool bContainerWidthAutoSize,
2591     float* fContentCalculatedWidth,
2592     float* fContentCalculatedHeight,
2593     float* fContentCurRowY,
2594     float fContentCurRowHeight,
2595     float fContentWidthLimit,
2596     bool bRootForceTb) {
2597   int32_t nGroupLengths[3] = {0, 0, 0};
2598   float fGroupWidths[3] = {0, 0, 0};
2599   int32_t nTotalLength = 0;
2600   for (int32_t i = 0; i < 3; i++) {
2601     nGroupLengths[i] = pdfium::CollectionSize<int32_t>(rgCurLineLayoutItems[i]);
2602     for (int32_t c = nGroupLengths[i], j = 0; j < c; j++) {
2603       nTotalLength++;
2604       if (XFA_ItemLayoutProcessor_IsTakingSpace(
2605               rgCurLineLayoutItems[i][j]->m_pFormNode)) {
2606         fGroupWidths[i] += rgCurLineLayoutItems[i][j]->m_sSize.width;
2607       }
2608     }
2609   }
2610   if (!nTotalLength) {
2611     if (bContainerHeightAutoSize) {
2612       *fContentCalculatedHeight =
2613           std::min(*fContentCalculatedHeight, *fContentCurRowY);
2614     }
2615     return false;
2616   }
2617   if (!m_pLayoutItem)
2618     m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
2619 
2620   if (eFlowStrategy != XFA_AttributeEnum::Rl_tb) {
2621     float fCurPos;
2622     fCurPos = 0;
2623     for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
2624       if (bRootForceTb) {
2625         rgCurLineLayoutItems[0][j]->m_sPos = CalculatePositionedContainerPos(
2626             rgCurLineLayoutItems[0][j]->m_pFormNode,
2627             rgCurLineLayoutItems[0][j]->m_sSize);
2628       } else {
2629         rgCurLineLayoutItems[0][j]->m_sPos =
2630             CFX_PointF(fCurPos, *fContentCurRowY);
2631         if (XFA_ItemLayoutProcessor_IsTakingSpace(
2632                 rgCurLineLayoutItems[0][j]->m_pFormNode)) {
2633           fCurPos += rgCurLineLayoutItems[0][j]->m_sSize.width;
2634         }
2635       }
2636       m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
2637       m_fLastRowWidth = fCurPos;
2638     }
2639     fCurPos = (fContentWidthLimit + fGroupWidths[0] - fGroupWidths[1] -
2640                fGroupWidths[2]) /
2641               2;
2642     for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
2643       if (bRootForceTb) {
2644         rgCurLineLayoutItems[1][j]->m_sPos = CalculatePositionedContainerPos(
2645             rgCurLineLayoutItems[1][j]->m_pFormNode,
2646             rgCurLineLayoutItems[1][j]->m_sSize);
2647       } else {
2648         rgCurLineLayoutItems[1][j]->m_sPos =
2649             CFX_PointF(fCurPos, *fContentCurRowY);
2650         if (XFA_ItemLayoutProcessor_IsTakingSpace(
2651                 rgCurLineLayoutItems[1][j]->m_pFormNode)) {
2652           fCurPos += rgCurLineLayoutItems[1][j]->m_sSize.width;
2653         }
2654       }
2655       m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
2656       m_fLastRowWidth = fCurPos;
2657     }
2658     fCurPos = fContentWidthLimit - fGroupWidths[2];
2659     for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
2660       if (bRootForceTb) {
2661         rgCurLineLayoutItems[2][j]->m_sPos = CalculatePositionedContainerPos(
2662             rgCurLineLayoutItems[2][j]->m_pFormNode,
2663             rgCurLineLayoutItems[2][j]->m_sSize);
2664       } else {
2665         rgCurLineLayoutItems[2][j]->m_sPos =
2666             CFX_PointF(fCurPos, *fContentCurRowY);
2667         if (XFA_ItemLayoutProcessor_IsTakingSpace(
2668                 rgCurLineLayoutItems[2][j]->m_pFormNode)) {
2669           fCurPos += rgCurLineLayoutItems[2][j]->m_sSize.width;
2670         }
2671       }
2672       m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
2673       m_fLastRowWidth = fCurPos;
2674     }
2675   } else {
2676     float fCurPos;
2677     fCurPos = fGroupWidths[0];
2678     for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
2679       if (XFA_ItemLayoutProcessor_IsTakingSpace(
2680               rgCurLineLayoutItems[0][j]->m_pFormNode)) {
2681         fCurPos -= rgCurLineLayoutItems[0][j]->m_sSize.width;
2682       }
2683       rgCurLineLayoutItems[0][j]->m_sPos =
2684           CFX_PointF(fCurPos, *fContentCurRowY);
2685       m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
2686       m_fLastRowWidth = fCurPos;
2687     }
2688     fCurPos = (fContentWidthLimit + fGroupWidths[0] + fGroupWidths[1] -
2689                fGroupWidths[2]) /
2690               2;
2691     for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
2692       if (XFA_ItemLayoutProcessor_IsTakingSpace(
2693               rgCurLineLayoutItems[1][j]->m_pFormNode)) {
2694         fCurPos -= rgCurLineLayoutItems[1][j]->m_sSize.width;
2695       }
2696       rgCurLineLayoutItems[1][j]->m_sPos =
2697           CFX_PointF(fCurPos, *fContentCurRowY);
2698       m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
2699       m_fLastRowWidth = fCurPos;
2700     }
2701     fCurPos = fContentWidthLimit;
2702     for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
2703       if (XFA_ItemLayoutProcessor_IsTakingSpace(
2704               rgCurLineLayoutItems[2][j]->m_pFormNode)) {
2705         fCurPos -= rgCurLineLayoutItems[2][j]->m_sSize.width;
2706       }
2707       rgCurLineLayoutItems[2][j]->m_sPos =
2708           CFX_PointF(fCurPos, *fContentCurRowY);
2709       m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
2710       m_fLastRowWidth = fCurPos;
2711     }
2712   }
2713   m_fLastRowY = *fContentCurRowY;
2714   *fContentCurRowY += fContentCurRowHeight;
2715   if (bContainerWidthAutoSize) {
2716     float fChildSuppliedWidth = fGroupWidths[0];
2717     if (fContentWidthLimit < FLT_MAX &&
2718         fContentWidthLimit > fChildSuppliedWidth) {
2719       fChildSuppliedWidth = fContentWidthLimit;
2720     }
2721     *fContentCalculatedWidth =
2722         std::max(*fContentCalculatedWidth, fChildSuppliedWidth);
2723   }
2724   if (bContainerHeightAutoSize) {
2725     *fContentCalculatedHeight =
2726         std::max(*fContentCalculatedHeight, *fContentCurRowY);
2727   }
2728   return true;
2729 }
2730 
GetSubformSetParent(CXFA_Node * pSubformSet)2731 CXFA_Node* CXFA_ItemLayoutProcessor::GetSubformSetParent(
2732     CXFA_Node* pSubformSet) {
2733   if (pSubformSet && pSubformSet->GetElementType() == XFA_Element::SubformSet) {
2734     CXFA_Node* pParent = pSubformSet->GetParent();
2735     while (pParent) {
2736       if (pParent->GetElementType() != XFA_Element::SubformSet)
2737         return pParent;
2738       pParent = pParent->GetParent();
2739     }
2740   }
2741   return pSubformSet;
2742 }
2743 
DoLayoutField()2744 void CXFA_ItemLayoutProcessor::DoLayoutField() {
2745   if (m_pLayoutItem)
2746     return;
2747 
2748   ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
2749   m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
2750   if (!m_pLayoutItem)
2751     return;
2752 
2753   CXFA_Document* pDocument = m_pFormNode->GetDocument();
2754   CXFA_FFNotify* pNotify = pDocument->GetNotify();
2755   CFX_SizeF size(-1, -1);
2756   pNotify->StartFieldDrawLayout(m_pFormNode, size.width, size.height);
2757 
2758   int32_t nRotate = XFA_MapRotation(
2759       m_pFormNode->JSObject()->GetInteger(XFA_Attribute::Rotate));
2760   if (nRotate == 90 || nRotate == 270)
2761     std::swap(size.width, size.height);
2762 
2763   SetCurrentComponentSize(size);
2764 }
2765 
DoLayout(bool bUseBreakControl,float fHeightLimit,float fRealHeight,CXFA_LayoutContext * pContext)2766 XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayout(
2767     bool bUseBreakControl,
2768     float fHeightLimit,
2769     float fRealHeight,
2770     CXFA_LayoutContext* pContext) {
2771   switch (m_pFormNode->GetElementType()) {
2772     case XFA_Element::Subform:
2773     case XFA_Element::Area:
2774     case XFA_Element::ExclGroup:
2775     case XFA_Element::SubformSet: {
2776       bool bRootForceTb = false;
2777       CXFA_Node* pLayoutNode = GetSubformSetParent(m_pFormNode);
2778       XFA_AttributeEnum eLayoutStrategy = GetLayout(pLayoutNode, &bRootForceTb);
2779       switch (eLayoutStrategy) {
2780         case XFA_AttributeEnum::Tb:
2781         case XFA_AttributeEnum::Lr_tb:
2782         case XFA_AttributeEnum::Rl_tb:
2783           return DoLayoutFlowedContainer(bUseBreakControl, eLayoutStrategy,
2784                                          fHeightLimit, fRealHeight, pContext,
2785                                          bRootForceTb);
2786         case XFA_AttributeEnum::Position:
2787         case XFA_AttributeEnum::Row:
2788         case XFA_AttributeEnum::Rl_row:
2789         default:
2790           DoLayoutPositionedContainer(pContext);
2791           m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
2792           return XFA_ItemLayoutProcessorResult::Done;
2793         case XFA_AttributeEnum::Table:
2794           DoLayoutTableContainer(pLayoutNode);
2795           m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
2796           return XFA_ItemLayoutProcessorResult::Done;
2797       }
2798     }
2799     case XFA_Element::Draw:
2800     case XFA_Element::Field:
2801       DoLayoutField();
2802       m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
2803       return XFA_ItemLayoutProcessorResult::Done;
2804     case XFA_Element::ContentArea:
2805       return XFA_ItemLayoutProcessorResult::Done;
2806     default:
2807       return XFA_ItemLayoutProcessorResult::Done;
2808   }
2809 }
2810 
GetCurrentComponentSize()2811 CFX_SizeF CXFA_ItemLayoutProcessor::GetCurrentComponentSize() {
2812   return CFX_SizeF(m_pLayoutItem->m_sSize.width, m_pLayoutItem->m_sSize.height);
2813 }
2814 
SetCurrentComponentPos(const CFX_PointF & pos)2815 void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(const CFX_PointF& pos) {
2816   m_pLayoutItem->m_sPos = pos;
2817 }
2818 
SetCurrentComponentSize(const CFX_SizeF & size)2819 void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(const CFX_SizeF& size) {
2820   m_pLayoutItem->m_sSize = size;
2821 }
2822 
JudgeLeaderOrTrailerForOccur(CXFA_Node * pFormNode)2823 bool CXFA_ItemLayoutProcessor::JudgeLeaderOrTrailerForOccur(
2824     CXFA_Node* pFormNode) {
2825   if (!pFormNode)
2826     return false;
2827 
2828   CXFA_Node* pTemplate = pFormNode->GetTemplateNodeIfExists();
2829   if (!pTemplate)
2830     pTemplate = pFormNode;
2831 
2832   int32_t iMax =
2833       pTemplate->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur)->GetMax();
2834   if (iMax < 0)
2835     return true;
2836 
2837   int32_t iCount = m_PendingNodesCount[pTemplate];
2838   if (iCount >= iMax)
2839     return false;
2840 
2841   m_PendingNodesCount[pTemplate] = iCount + 1;
2842   return true;
2843 }
2844