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 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 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 44 CXFA_LayoutItem::~CXFA_LayoutItem() {} 45 46 CXFA_ContainerLayoutItem* CXFA_LayoutItem::AsContainerLayoutItem() { 47 return IsContainerLayoutItem() ? static_cast<CXFA_ContainerLayoutItem*>(this) 48 : nullptr; 49 } 50 51 CXFA_ContentLayoutItem* CXFA_LayoutItem::AsContentLayoutItem() { 52 return IsContentLayoutItem() ? static_cast<CXFA_ContentLayoutItem*>(this) 53 : nullptr; 54 } 55 56 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 65 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 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 117 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 127 CXFA_LayoutItem* CXFA_LayoutItem::GetPrev() const { 128 ASSERT(m_bIsContentLayoutItem); 129 130 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pPrev; 131 } 132 133 CXFA_LayoutItem* CXFA_LayoutItem::GetNext() const { 134 ASSERT(m_bIsContentLayoutItem); 135 return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pNext; 136 } 137 138 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 150 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 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 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 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 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