Home | History | Annotate | Download | only in parser
      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