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 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 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 43 CXFA_LayoutItem::~CXFA_LayoutItem() {} 44 45 CXFA_ContainerLayoutItem* CXFA_LayoutItem::AsContainerLayoutItem() { 46 return IsContainerLayoutItem() ? static_cast<CXFA_ContainerLayoutItem*>(this) 47 : nullptr; 48 } 49 50 CXFA_ContentLayoutItem* CXFA_LayoutItem::AsContentLayoutItem() { 51 return IsContentLayoutItem() ? static_cast<CXFA_ContentLayoutItem*>(this) 52 : nullptr; 53 } 54 55 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 64 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 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 111 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 121 CXFA_LayoutItem* CXFA_LayoutItem::GetPrev() const { 122 ASSERT(m_bIsContentLayoutItem); 123 124 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pPrev; 125 } 126 127 CXFA_LayoutItem* CXFA_LayoutItem::GetNext() const { 128 ASSERT(m_bIsContentLayoutItem); 129 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pNext; 130 } 131 132 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 144 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 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 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 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 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