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 "xfa/fxfa/app/xfa_ffnotify.h"
10 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
11 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
12 #include "xfa/fxfa/parser/cxfa_measurement.h"
13
XFA_ReleaseLayoutItem(CXFA_LayoutItem * pLayoutItem)14 void XFA_ReleaseLayoutItem(CXFA_LayoutItem* pLayoutItem) {
15 CXFA_LayoutItem* pNode = pLayoutItem->m_pFirstChild;
16 CXFA_FFNotify* pNotify = pLayoutItem->m_pFormNode->GetDocument()->GetNotify();
17 CXFA_LayoutProcessor* pDocLayout =
18 pLayoutItem->m_pFormNode->GetDocument()->GetDocLayout();
19 while (pNode) {
20 CXFA_LayoutItem* pNext = pNode->m_pNextSibling;
21 pNode->m_pParent = nullptr;
22 pNotify->OnLayoutItemRemoving(pDocLayout,
23 static_cast<CXFA_LayoutItem*>(pNode));
24 XFA_ReleaseLayoutItem(pNode);
25 pNode = pNext;
26 }
27
28 pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
29 if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::PageArea) {
30 pNotify->OnPageEvent(static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem),
31 XFA_PAGEVIEWEVENT_PostRemoved);
32 }
33 delete pLayoutItem;
34 }
35
CXFA_LayoutItem(CXFA_Node * pNode,bool bIsContentLayoutItem)36 CXFA_LayoutItem::CXFA_LayoutItem(CXFA_Node* pNode, bool bIsContentLayoutItem)
37 : m_pFormNode(pNode),
38 m_pParent(nullptr),
39 m_pNextSibling(nullptr),
40 m_pFirstChild(nullptr),
41 m_bIsContentLayoutItem(bIsContentLayoutItem) {}
42
~CXFA_LayoutItem()43 CXFA_LayoutItem::~CXFA_LayoutItem() {}
44
AsContainerLayoutItem()45 CXFA_ContainerLayoutItem* CXFA_LayoutItem::AsContainerLayoutItem() {
46 return IsContainerLayoutItem() ? static_cast<CXFA_ContainerLayoutItem*>(this)
47 : nullptr;
48 }
49
AsContentLayoutItem()50 CXFA_ContentLayoutItem* CXFA_LayoutItem::AsContentLayoutItem() {
51 return IsContentLayoutItem() ? static_cast<CXFA_ContentLayoutItem*>(this)
52 : nullptr;
53 }
54
GetPage() const55 CXFA_ContainerLayoutItem* CXFA_LayoutItem::GetPage() const {
56 for (CXFA_LayoutItem* pCurNode = const_cast<CXFA_LayoutItem*>(this); pCurNode;
57 pCurNode = pCurNode->m_pParent) {
58 if (pCurNode->m_pFormNode->GetElementType() == XFA_Element::PageArea)
59 return static_cast<CXFA_ContainerLayoutItem*>(pCurNode);
60 }
61 return nullptr;
62 }
63
GetRect(bool bRelative) const64 CFX_RectF CXFA_LayoutItem::GetRect(bool bRelative) const {
65 ASSERT(m_bIsContentLayoutItem);
66
67 auto pThis = static_cast<const CXFA_ContentLayoutItem*>(this);
68 CFX_PointF sPos = pThis->m_sPos;
69 CFX_SizeF sSize = pThis->m_sSize;
70 if (bRelative)
71 return CFX_RectF(sPos, sSize);
72
73 for (CXFA_LayoutItem* pLayoutItem = pThis->m_pParent; pLayoutItem;
74 pLayoutItem = pLayoutItem->m_pParent) {
75 if (CXFA_ContentLayoutItem* pContent = pLayoutItem->AsContentLayoutItem()) {
76 sPos += pContent->m_sPos;
77 CXFA_Node* pMarginNode =
78 pLayoutItem->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
79 if (pMarginNode) {
80 sPos += CFX_PointF(pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset)
81 .ToUnit(XFA_UNIT_Pt),
82 pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset)
83 .ToUnit(XFA_UNIT_Pt));
84 }
85 continue;
86 }
87
88 if (pLayoutItem->m_pFormNode->GetElementType() ==
89 XFA_Element::ContentArea) {
90 sPos += CFX_PointF(pLayoutItem->m_pFormNode->GetMeasure(XFA_ATTRIBUTE_X)
91 .ToUnit(XFA_UNIT_Pt),
92 pLayoutItem->m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Y)
93 .ToUnit(XFA_UNIT_Pt));
94 break;
95 }
96 if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::PageArea)
97 break;
98 }
99 return CFX_RectF(sPos, sSize);
100 }
101
GetFirst()102 CXFA_LayoutItem* CXFA_LayoutItem::GetFirst() {
103 ASSERT(m_bIsContentLayoutItem);
104 CXFA_ContentLayoutItem* pCurNode = static_cast<CXFA_ContentLayoutItem*>(this);
105 while (pCurNode->m_pPrev)
106 pCurNode = pCurNode->m_pPrev;
107
108 return pCurNode;
109 }
110
GetLast() const111 const CXFA_LayoutItem* CXFA_LayoutItem::GetLast() const {
112 ASSERT(m_bIsContentLayoutItem);
113 const CXFA_ContentLayoutItem* pCurNode =
114 static_cast<const CXFA_ContentLayoutItem*>(this);
115 while (pCurNode->m_pNext)
116 pCurNode = pCurNode->m_pNext;
117
118 return pCurNode;
119 }
120
GetPrev() const121 CXFA_LayoutItem* CXFA_LayoutItem::GetPrev() const {
122 ASSERT(m_bIsContentLayoutItem);
123
124 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pPrev;
125 }
126
GetNext() const127 CXFA_LayoutItem* CXFA_LayoutItem::GetNext() const {
128 ASSERT(m_bIsContentLayoutItem);
129 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pNext;
130 }
131
GetIndex() const132 int32_t CXFA_LayoutItem::GetIndex() const {
133 ASSERT(m_bIsContentLayoutItem);
134 int32_t iIndex = 0;
135 const CXFA_ContentLayoutItem* pCurNode =
136 static_cast<const CXFA_ContentLayoutItem*>(this);
137 while (pCurNode->m_pPrev) {
138 pCurNode = pCurNode->m_pPrev;
139 ++iIndex;
140 }
141 return iIndex;
142 }
143
GetCount() const144 int32_t CXFA_LayoutItem::GetCount() const {
145 ASSERT(m_bIsContentLayoutItem);
146
147 int32_t iCount = GetIndex() + 1;
148 const CXFA_ContentLayoutItem* pCurNode =
149 static_cast<const CXFA_ContentLayoutItem*>(this);
150 while (pCurNode->m_pNext) {
151 pCurNode = pCurNode->m_pNext;
152 iCount++;
153 }
154 return iCount;
155 }
156
AddChild(CXFA_LayoutItem * pChildItem)157 void CXFA_LayoutItem::AddChild(CXFA_LayoutItem* pChildItem) {
158 if (pChildItem->m_pParent)
159 pChildItem->m_pParent->RemoveChild(pChildItem);
160
161 pChildItem->m_pParent = this;
162 if (!m_pFirstChild) {
163 m_pFirstChild = pChildItem;
164 return;
165 }
166
167 CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
168 while (pExistingChildItem->m_pNextSibling)
169 pExistingChildItem = pExistingChildItem->m_pNextSibling;
170
171 pExistingChildItem->m_pNextSibling = pChildItem;
172 }
173
AddHeadChild(CXFA_LayoutItem * pChildItem)174 void CXFA_LayoutItem::AddHeadChild(CXFA_LayoutItem* pChildItem) {
175 if (pChildItem->m_pParent)
176 pChildItem->m_pParent->RemoveChild(pChildItem);
177
178 pChildItem->m_pParent = this;
179 if (!m_pFirstChild) {
180 m_pFirstChild = pChildItem;
181 return;
182 }
183
184 CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
185 m_pFirstChild = pChildItem;
186 m_pFirstChild->m_pNextSibling = pExistingChildItem;
187 }
188
InsertChild(CXFA_LayoutItem * pBeforeItem,CXFA_LayoutItem * pChildItem)189 void CXFA_LayoutItem::InsertChild(CXFA_LayoutItem* pBeforeItem,
190 CXFA_LayoutItem* pChildItem) {
191 if (pBeforeItem->m_pParent != this)
192 return;
193 if (pChildItem->m_pParent)
194 pChildItem->m_pParent = nullptr;
195
196 pChildItem->m_pParent = this;
197
198 CXFA_LayoutItem* pExistingChildItem = pBeforeItem->m_pNextSibling;
199 pBeforeItem->m_pNextSibling = pChildItem;
200 pChildItem->m_pNextSibling = pExistingChildItem;
201 }
202
RemoveChild(CXFA_LayoutItem * pChildItem)203 void CXFA_LayoutItem::RemoveChild(CXFA_LayoutItem* pChildItem) {
204 if (pChildItem->m_pParent != this)
205 return;
206
207 if (m_pFirstChild == pChildItem) {
208 m_pFirstChild = pChildItem->m_pNextSibling;
209 } else {
210 CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
211 while (pExistingChildItem &&
212 pExistingChildItem->m_pNextSibling != pChildItem) {
213 pExistingChildItem = pExistingChildItem->m_pNextSibling;
214 }
215 if (pExistingChildItem)
216 pExistingChildItem->m_pNextSibling = pChildItem->m_pNextSibling;
217 }
218 pChildItem->m_pNextSibling = nullptr;
219 pChildItem->m_pParent = nullptr;
220 }
221