1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fxfa/parser/cxfa_layoutitem.h"
8
9 #include "fxjs/xfa/cjx_object.h"
10 #include "xfa/fxfa/cxfa_ffnotify.h"
11 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
12 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
13 #include "xfa/fxfa/parser/cxfa_margin.h"
14 #include "xfa/fxfa/parser/cxfa_measurement.h"
15 #include "xfa/fxfa/parser/cxfa_node.h"
16
XFA_ReleaseLayoutItem(CXFA_LayoutItem * pLayoutItem)17 void XFA_ReleaseLayoutItem(CXFA_LayoutItem* pLayoutItem) {
18 CXFA_LayoutItem* pNode = pLayoutItem->m_pFirstChild;
19 CXFA_FFNotify* pNotify = pLayoutItem->m_pFormNode->GetDocument()->GetNotify();
20 CXFA_LayoutProcessor* pDocLayout =
21 pLayoutItem->m_pFormNode->GetDocument()->GetDocLayout();
22 while (pNode) {
23 CXFA_LayoutItem* pNext = pNode->m_pNextSibling;
24 pNode->m_pParent = nullptr;
25 pNotify->OnLayoutItemRemoving(pDocLayout, pNode);
26 XFA_ReleaseLayoutItem(pNode);
27 pNode = pNext;
28 }
29 pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
30 if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::PageArea) {
31 pNotify->OnPageEvent(static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem),
32 XFA_PAGEVIEWEVENT_PostRemoved);
33 }
34 delete pLayoutItem;
35 }
36
CXFA_LayoutItem(CXFA_Node * pNode,bool bIsContentLayoutItem)37 CXFA_LayoutItem::CXFA_LayoutItem(CXFA_Node* pNode, bool bIsContentLayoutItem)
38 : m_pFormNode(pNode),
39 m_pParent(nullptr),
40 m_pNextSibling(nullptr),
41 m_pFirstChild(nullptr),
42 m_bIsContentLayoutItem(bIsContentLayoutItem) {}
43
~CXFA_LayoutItem()44 CXFA_LayoutItem::~CXFA_LayoutItem() {}
45
AsContainerLayoutItem()46 CXFA_ContainerLayoutItem* CXFA_LayoutItem::AsContainerLayoutItem() {
47 return IsContainerLayoutItem() ? static_cast<CXFA_ContainerLayoutItem*>(this)
48 : nullptr;
49 }
50
AsContentLayoutItem()51 CXFA_ContentLayoutItem* CXFA_LayoutItem::AsContentLayoutItem() {
52 return IsContentLayoutItem() ? static_cast<CXFA_ContentLayoutItem*>(this)
53 : nullptr;
54 }
55
GetPage() const56 CXFA_ContainerLayoutItem* CXFA_LayoutItem::GetPage() const {
57 for (CXFA_LayoutItem* pCurNode = const_cast<CXFA_LayoutItem*>(this); pCurNode;
58 pCurNode = pCurNode->m_pParent) {
59 if (pCurNode->m_pFormNode->GetElementType() == XFA_Element::PageArea)
60 return static_cast<CXFA_ContainerLayoutItem*>(pCurNode);
61 }
62 return nullptr;
63 }
64
GetRect(bool bRelative) const65 CFX_RectF CXFA_LayoutItem::GetRect(bool bRelative) const {
66 ASSERT(m_bIsContentLayoutItem);
67
68 auto* pThis = static_cast<const CXFA_ContentLayoutItem*>(this);
69 CFX_PointF sPos = pThis->m_sPos;
70 CFX_SizeF sSize = pThis->m_sSize;
71 if (bRelative)
72 return CFX_RectF(sPos, sSize);
73
74 for (CXFA_LayoutItem* pLayoutItem = pThis->m_pParent; pLayoutItem;
75 pLayoutItem = pLayoutItem->m_pParent) {
76 if (CXFA_ContentLayoutItem* pContent = pLayoutItem->AsContentLayoutItem()) {
77 sPos += pContent->m_sPos;
78 CXFA_Margin* pMarginNode =
79 pLayoutItem->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
80 XFA_Element::Margin);
81 if (pMarginNode) {
82 sPos += CFX_PointF(pMarginNode->JSObject()
83 ->GetMeasure(XFA_Attribute::LeftInset)
84 .ToUnit(XFA_Unit::Pt),
85 pMarginNode->JSObject()
86 ->GetMeasure(XFA_Attribute::TopInset)
87 .ToUnit(XFA_Unit::Pt));
88 }
89 continue;
90 }
91
92 if (pLayoutItem->m_pFormNode->GetElementType() ==
93 XFA_Element::ContentArea) {
94 sPos += CFX_PointF(pLayoutItem->m_pFormNode->JSObject()
95 ->GetMeasure(XFA_Attribute::X)
96 .ToUnit(XFA_Unit::Pt),
97 pLayoutItem->m_pFormNode->JSObject()
98 ->GetMeasure(XFA_Attribute::Y)
99 .ToUnit(XFA_Unit::Pt));
100 break;
101 }
102 if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::PageArea)
103 break;
104 }
105 return CFX_RectF(sPos, sSize);
106 }
107
GetFirst()108 CXFA_LayoutItem* CXFA_LayoutItem::GetFirst() {
109 ASSERT(m_bIsContentLayoutItem);
110 CXFA_ContentLayoutItem* pCurNode = static_cast<CXFA_ContentLayoutItem*>(this);
111 while (pCurNode->m_pPrev)
112 pCurNode = pCurNode->m_pPrev;
113
114 return pCurNode;
115 }
116
GetLast() const117 const CXFA_LayoutItem* CXFA_LayoutItem::GetLast() const {
118 ASSERT(m_bIsContentLayoutItem);
119 const CXFA_ContentLayoutItem* pCurNode =
120 static_cast<const CXFA_ContentLayoutItem*>(this);
121 while (pCurNode->m_pNext)
122 pCurNode = pCurNode->m_pNext;
123
124 return pCurNode;
125 }
126
GetPrev() const127 CXFA_LayoutItem* CXFA_LayoutItem::GetPrev() const {
128 ASSERT(m_bIsContentLayoutItem);
129
130 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pPrev;
131 }
132
GetNext() const133 CXFA_LayoutItem* CXFA_LayoutItem::GetNext() const {
134 ASSERT(m_bIsContentLayoutItem);
135 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pNext;
136 }
137
GetIndex() const138 int32_t CXFA_LayoutItem::GetIndex() const {
139 ASSERT(m_bIsContentLayoutItem);
140 int32_t iIndex = 0;
141 const CXFA_ContentLayoutItem* pCurNode =
142 static_cast<const CXFA_ContentLayoutItem*>(this);
143 while (pCurNode->m_pPrev) {
144 pCurNode = pCurNode->m_pPrev;
145 ++iIndex;
146 }
147 return iIndex;
148 }
149
GetCount() const150 int32_t CXFA_LayoutItem::GetCount() const {
151 ASSERT(m_bIsContentLayoutItem);
152
153 int32_t iCount = GetIndex() + 1;
154 const CXFA_ContentLayoutItem* pCurNode =
155 static_cast<const CXFA_ContentLayoutItem*>(this);
156 while (pCurNode->m_pNext) {
157 pCurNode = pCurNode->m_pNext;
158 iCount++;
159 }
160 return iCount;
161 }
162
AddChild(CXFA_LayoutItem * pChildItem)163 void CXFA_LayoutItem::AddChild(CXFA_LayoutItem* pChildItem) {
164 if (pChildItem->m_pParent)
165 pChildItem->m_pParent->RemoveChild(pChildItem);
166
167 pChildItem->m_pParent = this;
168 if (!m_pFirstChild) {
169 m_pFirstChild = pChildItem;
170 return;
171 }
172
173 CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
174 while (pExistingChildItem->m_pNextSibling)
175 pExistingChildItem = pExistingChildItem->m_pNextSibling;
176
177 pExistingChildItem->m_pNextSibling = pChildItem;
178 }
179
AddHeadChild(CXFA_LayoutItem * pChildItem)180 void CXFA_LayoutItem::AddHeadChild(CXFA_LayoutItem* pChildItem) {
181 if (pChildItem->m_pParent)
182 pChildItem->m_pParent->RemoveChild(pChildItem);
183
184 pChildItem->m_pParent = this;
185 if (!m_pFirstChild) {
186 m_pFirstChild = pChildItem;
187 return;
188 }
189
190 CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
191 m_pFirstChild = pChildItem;
192 m_pFirstChild->m_pNextSibling = pExistingChildItem;
193 }
194
InsertChild(CXFA_LayoutItem * pBeforeItem,CXFA_LayoutItem * pChildItem)195 void CXFA_LayoutItem::InsertChild(CXFA_LayoutItem* pBeforeItem,
196 CXFA_LayoutItem* pChildItem) {
197 if (pBeforeItem->m_pParent != this)
198 return;
199 if (pChildItem->m_pParent)
200 pChildItem->m_pParent = nullptr;
201
202 pChildItem->m_pParent = this;
203
204 CXFA_LayoutItem* pExistingChildItem = pBeforeItem->m_pNextSibling;
205 pBeforeItem->m_pNextSibling = pChildItem;
206 pChildItem->m_pNextSibling = pExistingChildItem;
207 }
208
RemoveChild(CXFA_LayoutItem * pChildItem)209 void CXFA_LayoutItem::RemoveChild(CXFA_LayoutItem* pChildItem) {
210 if (pChildItem->m_pParent != this)
211 return;
212
213 if (m_pFirstChild == pChildItem) {
214 m_pFirstChild = pChildItem->m_pNextSibling;
215 } else {
216 CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
217 while (pExistingChildItem &&
218 pExistingChildItem->m_pNextSibling != pChildItem) {
219 pExistingChildItem = pExistingChildItem->m_pNextSibling;
220 }
221 if (pExistingChildItem)
222 pExistingChildItem->m_pNextSibling = pChildItem->m_pNextSibling;
223 }
224 pChildItem->m_pNextSibling = nullptr;
225 pChildItem->m_pParent = nullptr;
226 }
227