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