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