// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fxfa/app/xfa_ffnotify.h"

#include "xfa/fxfa/app/xfa_ffbarcode.h"
#include "xfa/fxfa/app/xfa_ffcheckbutton.h"
#include "xfa/fxfa/app/xfa_ffchoicelist.h"
#include "xfa/fxfa/app/xfa_ffdraw.h"
#include "xfa/fxfa/app/xfa_ffexclgroup.h"
#include "xfa/fxfa/app/xfa_fffield.h"
#include "xfa/fxfa/app/xfa_ffimage.h"
#include "xfa/fxfa/app/xfa_ffimageedit.h"
#include "xfa/fxfa/app/xfa_ffpath.h"
#include "xfa/fxfa/app/xfa_ffpushbutton.h"
#include "xfa/fxfa/app/xfa_ffsignature.h"
#include "xfa/fxfa/app/xfa_ffsubform.h"
#include "xfa/fxfa/app/xfa_fftext.h"
#include "xfa/fxfa/app/xfa_fftextedit.h"
#include "xfa/fxfa/app/xfa_ffwidgetacc.h"
#include "xfa/fxfa/app/xfa_fwladapter.h"
#include "xfa/fxfa/app/xfa_textlayout.h"
#include "xfa/include/fxfa/xfa_ffapp.h"
#include "xfa/include/fxfa/xfa_ffdoc.h"
#include "xfa/include/fxfa/xfa_ffdocview.h"
#include "xfa/include/fxfa/xfa_ffpageview.h"
#include "xfa/include/fxfa/xfa_ffwidget.h"
#include "xfa/include/fxfa/xfa_ffwidgethandler.h"

static void XFA_FFDeleteWidgetAcc(void* pData) {
  delete static_cast<CXFA_WidgetAcc*>(pData);
}

static XFA_MAPDATABLOCKCALLBACKINFO gs_XFADeleteWidgetAcc = {
    XFA_FFDeleteWidgetAcc, nullptr};

CXFA_FFNotify::CXFA_FFNotify(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
CXFA_FFNotify::~CXFA_FFNotify() {}
void CXFA_FFNotify::OnPageEvent(CXFA_ContainerLayoutItem* pSender,
                                XFA_PAGEEVENT eEvent,
                                void* pParam) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pSender->GetLayout());
  if (!pDocView) {
    return;
  }
  pDocView->OnPageEvent(pSender, eEvent, (int32_t)(uintptr_t)pParam);
}
void CXFA_FFNotify::OnNodeEvent(CXFA_Node* pSender,
                                XFA_NODEEVENT eEvent,
                                void* pParam,
                                void* pParam2,
                                void* pParam3,
                                void* pParam4) {
  switch (eEvent) {
    case XFA_NODEEVENT_Ready:
      OnNodeReady(pSender);
      break;
    case XFA_NODEEVENT_ValueChanging:
      OnValueChanging(pSender, pParam, pParam2);
      break;
    case XFA_NODEEVENT_ValueChanged:
      OnValueChanged(pSender, pParam, pParam2, pParam3, pParam4);
      break;
    case XFA_NODEEVENT_ChildAdded:
      OnChildAdded(pSender, pParam, pParam2);
      break;
    case XFA_NODEEVENT_ChildRemoved:
      OnChildRemoved(pSender, pParam, pParam2);
      break;
  }
}
void CXFA_FFNotify::OnWidgetDataEvent(CXFA_WidgetData* pSender,
                                      uint32_t dwEvent,
                                      void* pParam,
                                      void* pAdditional,
                                      void* pAdditional2) {
  CXFA_WidgetAcc* pWidgetAcc = static_cast<CXFA_WidgetAcc*>(pSender);
  switch (dwEvent) {
    case XFA_WIDGETEVENT_ListItemAdded: {
      if (pWidgetAcc->GetUIType() != XFA_ELEMENT_ChoiceList) {
        return;
      }
      FX_BOOL bStaticNotify = pWidgetAcc->GetDocView()->IsStaticNotify();
      CXFA_FFWidget* pWidget = pWidgetAcc->GetNextWidget(NULL);
      if (!pWidget) {
        if (bStaticNotify) {
          pWidgetAcc->GetDoc()->GetDocProvider()->WidgetEvent(
              pWidget, pWidgetAcc, XFA_WIDGETEVENT_ListItemAdded, pParam,
              pAdditional);
        }
        return;
      }
      while (pWidget) {
        if (pWidget->IsLoaded()) {
          if (pWidgetAcc->IsListBox()) {
            static_cast<CXFA_FFListBox*>(pWidget)
                ->InsertItem((const CFX_WideStringC&)(const FX_WCHAR*)pParam,
                             (int32_t)(uintptr_t)pAdditional2);
          } else {
            static_cast<CXFA_FFComboBox*>(pWidget)
                ->InsertItem((const CFX_WideStringC&)(const FX_WCHAR*)pParam,
                             (int32_t)(uintptr_t)pAdditional2);
          }
        }
        if (bStaticNotify) {
          pWidgetAcc->GetDoc()->GetDocProvider()->WidgetEvent(
              pWidget, pWidgetAcc, XFA_WIDGETEVENT_ListItemAdded, pParam,
              pAdditional);
        }
        pWidget = pWidgetAcc->GetNextWidget(pWidget);
      }
    } break;
    case XFA_WIDGETEVENT_ListItemRemoved: {
      if (pWidgetAcc->GetUIType() != XFA_ELEMENT_ChoiceList) {
        return;
      }
      FX_BOOL bStaticNotify = pWidgetAcc->GetDocView()->IsStaticNotify();
      CXFA_FFWidget* pWidget = pWidgetAcc->GetNextWidget(NULL);
      if (!pWidget) {
        if (bStaticNotify) {
          pWidgetAcc->GetDoc()->GetDocProvider()->WidgetEvent(
              pWidget, pWidgetAcc, XFA_WIDGETEVENT_ListItemRemoved, pParam,
              pAdditional);
        }
        return;
      }
      while (pWidget) {
        if (pWidget->IsLoaded()) {
          if (pWidgetAcc->IsListBox()) {
            static_cast<CXFA_FFListBox*>(pWidget)
                ->DeleteItem((int32_t)(uintptr_t)pParam);
          } else {
            static_cast<CXFA_FFComboBox*>(pWidget)
                ->DeleteItem((int32_t)(uintptr_t)pParam);
          }
        }
        if (bStaticNotify) {
          pWidgetAcc->GetDoc()->GetDocProvider()->WidgetEvent(
              pWidget, pWidgetAcc, XFA_WIDGETEVENT_ListItemRemoved, pParam,
              pAdditional);
        }
        pWidget = pWidgetAcc->GetNextWidget(pWidget);
      }
    } break;
  }
}
CXFA_LayoutItem* CXFA_FFNotify::OnCreateLayoutItem(CXFA_Node* pNode) {
  CXFA_LayoutProcessor* pLayout = m_pDoc->GetXFADoc()->GetDocLayout();
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
  XFA_ELEMENT eType = pNode->GetClassID();
  if (eType == XFA_ELEMENT_PageArea) {
    return new CXFA_FFPageView(pDocView, pNode);
  }
  if (eType == XFA_ELEMENT_ContentArea) {
    return new CXFA_ContainerLayoutItem(pNode);
  }
  CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData());
  if (!pAcc) {
    return new CXFA_ContentLayoutItem(pNode);
  }
  CXFA_FFPageView* pPageView = NULL;
  CXFA_FFWidget* pWidget = NULL;
  switch (pAcc->GetUIType()) {
    case XFA_ELEMENT_Barcode:
      pWidget = new CXFA_FFBarcode(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Button:
      pWidget = new CXFA_FFPushButton(pPageView, pAcc);
      break;
    case XFA_ELEMENT_CheckButton:
      pWidget = new CXFA_FFCheckButton(pPageView, pAcc);
      break;
    case XFA_ELEMENT_ChoiceList: {
      if (pAcc->IsListBox()) {
        pWidget = new CXFA_FFListBox(pPageView, pAcc);
      } else {
        pWidget = new CXFA_FFComboBox(pPageView, pAcc);
      }
    } break;
    case XFA_ELEMENT_DateTimeEdit:
      pWidget = new CXFA_FFDateTimeEdit(pPageView, pAcc);
      break;
    case XFA_ELEMENT_ImageEdit:
      pWidget = new CXFA_FFImageEdit(pPageView, pAcc);
      break;
    case XFA_ELEMENT_NumericEdit:
      pWidget = new CXFA_FFNumericEdit(pPageView, pAcc);
      break;
    case XFA_ELEMENT_PasswordEdit:
      pWidget = new CXFA_FFPasswordEdit(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Signature:
      pWidget = new CXFA_FFSignature(pPageView, pAcc);
      break;
    case XFA_ELEMENT_TextEdit:
      pWidget = new CXFA_FFTextEdit(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Arc:
      pWidget = new CXFA_FFArc(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Line:
      pWidget = new CXFA_FFLine(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Rectangle:
      pWidget = new CXFA_FFRectangle(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Text:
      pWidget = new CXFA_FFText(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Image:
      pWidget = new CXFA_FFImage(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Draw:
      pWidget = new CXFA_FFDraw(pPageView, pAcc);
      break;
    case XFA_ELEMENT_Subform:
      pWidget = new CXFA_FFSubForm(pPageView, pAcc);
      break;
    case XFA_ELEMENT_ExclGroup:
      pWidget = new CXFA_FFExclGroup(pPageView, pAcc);
      break;
    case XFA_ELEMENT_DefaultUi:
    default:
      pWidget = NULL;
      break;
  }
  if (!pWidget) {
    return NULL;
  }
  pWidget->SetDocView(pDocView);
  return pWidget;
}
void CXFA_FFNotify::OnLayoutEvent(CXFA_LayoutProcessor* pLayout,
                                  CXFA_LayoutItem* pSender,
                                  XFA_LAYOUTEVENT eEvent,
                                  void* pParam,
                                  void* pParam2) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
  if (!pDocView || !XFA_GetWidgetFromLayoutItem(pSender)) {
    return;
  }
  switch (eEvent) {
    case XFA_LAYOUTEVENT_ItemAdded:
      OnLayoutItemAdd(pDocView, pLayout, pSender, pParam, pParam2);
      break;
    case XFA_LAYOUTEVENT_ItemRemoving:
      OnLayoutItemRemoving(pDocView, pLayout, pSender, pParam, pParam2);
      break;
    case XFA_LAYOUTEVENT_RectChanged:
      OnLayoutItemRectChanged(pDocView, pLayout, pSender, pParam, pParam2);
      break;
    case XFA_LAYOUTEVENT_StatusChanged:
      OnLayoutItemStatustChanged(pDocView, pLayout, pSender, pParam, pParam2);
      break;
  }
}
void CXFA_FFNotify::StartFieldDrawLayout(CXFA_Node* pItem,
                                         FX_FLOAT& fCalcWidth,
                                         FX_FLOAT& fCalcHeight) {
  CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pItem->GetWidgetData());
  if (!pAcc) {
    return;
  }
  pAcc->StartWidgetLayout(fCalcWidth, fCalcHeight);
}
FX_BOOL CXFA_FFNotify::FindSplitPos(CXFA_Node* pItem,
                                    int32_t iBlockIndex,
                                    FX_FLOAT& fCalcHeightPos) {
  CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pItem->GetWidgetData());
  if (!pAcc) {
    return FALSE;
  }
  return (XFA_LAYOUTRESULT)pAcc->FindSplitPos(iBlockIndex, fCalcHeightPos);
}
FX_BOOL CXFA_FFNotify::RunScript(CXFA_Node* pScript, CXFA_Node* pFormItem) {
  FX_BOOL bRet = FALSE;
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return bRet;
  }
  CXFA_WidgetAcc* pWidgetAcc =
      static_cast<CXFA_WidgetAcc*>(pFormItem->GetWidgetData());
  if (!pWidgetAcc) {
    return bRet;
  }
  CXFA_EventParam EventParam;
  EventParam.m_eType = XFA_EVENT_Unknown;
  FXJSE_HVALUE pRetValue = NULL;
  int32_t iRet =
      pWidgetAcc->ExecuteScript(CXFA_Script(pScript), &EventParam, &pRetValue);
  if (iRet == XFA_EVENTERROR_Success && pRetValue) {
    bRet = FXJSE_Value_ToBoolean(pRetValue);
    FXJSE_Value_Release(pRetValue);
  }
  return bRet;
}
int32_t CXFA_FFNotify::ExecEventByDeepFirst(CXFA_Node* pFormNode,
                                            XFA_EVENTTYPE eEventType,
                                            FX_BOOL bIsFormReady,
                                            FX_BOOL bRecursive,
                                            CXFA_WidgetAcc* pExclude) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return XFA_EVENTERROR_NotExist;
  }
  return pDocView->ExecEventActivityByDeepFirst(
      pFormNode, eEventType, bIsFormReady, bRecursive,
      pExclude ? pExclude->GetNode() : NULL);
}
void CXFA_FFNotify::AddCalcValidate(CXFA_Node* pNode) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  CXFA_WidgetAcc* pWidgetAcc =
      static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData());
  if (!pWidgetAcc) {
    return;
  }
  pDocView->AddCalculateWidgetAcc(pWidgetAcc);
  pDocView->AddValidateWidget(pWidgetAcc);
}
CXFA_FFDoc* CXFA_FFNotify::GetHDOC() {
  return m_pDoc;
}
IXFA_DocProvider* CXFA_FFNotify::GetDocProvider() {
  return m_pDoc->GetDocProvider();
}
IXFA_AppProvider* CXFA_FFNotify::GetAppProvider() {
  return m_pDoc->GetApp()->GetAppProvider();
}
CXFA_FFWidgetHandler* CXFA_FFNotify::GetWidgetHandler() {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  return pDocView ? pDocView->GetWidgetHandler() : NULL;
}
CXFA_FFWidget* CXFA_FFNotify::GetHWidget(CXFA_LayoutItem* pLayoutItem) {
  return XFA_GetWidgetFromLayoutItem(pLayoutItem);
}
void CXFA_FFNotify::OpenDropDownList(CXFA_FFWidget* hWidget) {
  if (hWidget->GetDataAcc()->GetUIType() != XFA_ELEMENT_ChoiceList) {
    return;
  }
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  pDocView->LockUpdate();
  static_cast<CXFA_FFComboBox*>(hWidget)->OpenDropDownList();
  pDocView->UnlockUpdate();
  pDocView->UpdateDocView();
}
CFX_WideString CXFA_FFNotify::GetCurrentDateTime() {
  CFX_Unitime dataTime;
  dataTime.Now();
  CFX_WideString wsDateTime;
  wsDateTime.Format(L"%d%02d%02dT%02d%02d%02d", dataTime.GetYear(),
                    dataTime.GetMonth(), dataTime.GetDay(), dataTime.GetHour(),
                    dataTime.GetMinute(), dataTime.GetSecond());
  return wsDateTime;
}
void CXFA_FFNotify::ResetData(CXFA_WidgetData* pWidgetData) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  pDocView->ResetWidgetData(static_cast<CXFA_WidgetAcc*>(pWidgetData));
}
int32_t CXFA_FFNotify::GetLayoutStatus() {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  return pDocView ? pDocView->GetLayoutStatus() : 0;
}
void CXFA_FFNotify::RunNodeInitialize(CXFA_Node* pNode) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  pDocView->AddNewFormNode(pNode);
}
void CXFA_FFNotify::RunSubformIndexChange(CXFA_Node* pSubformNode) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  pDocView->AddIndexChangedSubform(pSubformNode);
}
CXFA_Node* CXFA_FFNotify::GetFocusWidgetNode() {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return NULL;
  }
  CXFA_WidgetAcc* pAcc = pDocView->GetFocusWidgetAcc();
  return pAcc ? pAcc->GetNode() : NULL;
}
void CXFA_FFNotify::SetFocusWidgetNode(CXFA_Node* pNode) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  CXFA_WidgetAcc* pAcc =
      pNode ? static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData()) : nullptr;
  pDocView->SetFocusWidgetAcc(pAcc);
}
void CXFA_FFNotify::OnNodeReady(CXFA_Node* pNode) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  XFA_ELEMENT iType = pNode->GetClassID();
  if (XFA_IsCreateWidget(iType)) {
    CXFA_WidgetAcc* pAcc = new CXFA_WidgetAcc(pDocView, pNode);
    pNode->SetObject(XFA_ATTRIBUTE_WidgetData, pAcc, &gs_XFADeleteWidgetAcc);
    return;
  }
  switch (iType) {
    case XFA_ELEMENT_BindItems:
      pDocView->m_bindItems.Add(pNode);
      break;
    case XFA_ELEMENT_Validate: {
      pNode->SetFlag(XFA_NODEFLAG_NeedsInitApp, TRUE, FALSE);
    } break;
    default:
      break;
  }
}
void CXFA_FFNotify::OnValueChanging(CXFA_Node* pSender,
                                    void* pParam,
                                    void* pParam2) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  if (pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End) {
    return;
  }
  uint32_t dwPacket = pSender->GetPacketID();
  if (dwPacket & XFA_XDPPACKET_Datasets) {
  } else if (pSender->IsFormContainer()) {
    XFA_ATTRIBUTE eAttr = (XFA_ATTRIBUTE)(uintptr_t)pParam;
    if (eAttr == XFA_ATTRIBUTE_Presence) {
      CXFA_WidgetAcc* pWidgetAcc =
          static_cast<CXFA_WidgetAcc*>(pSender->GetWidgetData());
      if (!pWidgetAcc) {
        return;
      }
      CXFA_FFWidget* pWidget = NULL;
      while ((pWidget = pWidgetAcc->GetNextWidget(pWidget))) {
        if (pWidget->IsLoaded()) {
          pWidget->AddInvalidateRect();
        }
      }
    }
  }
}
void CXFA_FFNotify::OnValueChanged(CXFA_Node* pSender,
                                   void* pParam,
                                   void* pParam2,
                                   void* pParam3,
                                   void* pParam4) {
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  uint32_t dwPacket = pSender->GetPacketID();
  XFA_ATTRIBUTE eAttr = (XFA_ATTRIBUTE)(uintptr_t)pParam;
  if (dwPacket & XFA_XDPPACKET_Form) {
    CXFA_Node* pParentNode = static_cast<CXFA_Node*>(pParam3);
    CXFA_Node* pWidgetNode = static_cast<CXFA_Node*>(pParam4);
    XFA_ELEMENT ePType = pParentNode->GetClassID();
    FX_BOOL bIsContainerNode = pParentNode->IsContainerNode();
    CXFA_WidgetAcc* pWidgetAcc =
        static_cast<CXFA_WidgetAcc*>(pWidgetNode->GetWidgetData());
    if (!pWidgetAcc) {
      return;
    }
    FX_BOOL bUpdateProperty = FALSE;
    pDocView->SetChangeMark();
    switch (ePType) {
      case XFA_ELEMENT_Caption: {
        CXFA_TextLayout* pCapOut = pWidgetAcc->GetCaptionTextLayout();
        if (!pCapOut) {
          return;
        }
        pCapOut->Unload();
      } break;
      case XFA_ELEMENT_Ui:
      case XFA_ELEMENT_Para:
        bUpdateProperty = TRUE;
        break;
      case XFA_ELEMENT_Font:
      case XFA_ELEMENT_Margin:
      case XFA_ELEMENT_Value:
      case XFA_ELEMENT_Items:
        break;
      default:
        break;
    }
    if (bIsContainerNode && eAttr == XFA_ATTRIBUTE_Access) {
      bUpdateProperty = TRUE;
      FX_BOOL bNotify = pDocView->IsStaticNotify();
      if (bNotify) {
        pWidgetAcc->NotifyEvent(XFA_WIDGETEVENT_AccessChanged, NULL, pParam2,
                                NULL);
      }
    }
    if (eAttr == XFA_ATTRIBUTE_Value) {
      pDocView->AddCalculateNodeNotify(pSender);
      if (ePType == XFA_ELEMENT_Value || bIsContainerNode) {
        FX_BOOL bNotify = pDocView->IsStaticNotify();
        if (bIsContainerNode) {
          pWidgetAcc->UpdateUIDisplay();
          pDocView->AddCalculateWidgetAcc(pWidgetAcc);
          pDocView->AddValidateWidget(pWidgetAcc);
        } else if (pWidgetNode->GetNodeItem(XFA_NODEITEM_Parent)
                       ->GetClassID() == XFA_ELEMENT_ExclGroup) {
          pWidgetAcc->UpdateUIDisplay();
        }
        if (bNotify) {
          pWidgetAcc->NotifyEvent(XFA_WIDGETEVENT_PostContentChanged, NULL,
                                  NULL, NULL);
        }
        return;
      }
    }
    CXFA_FFWidget* pWidget = NULL;
    while ((pWidget = pWidgetAcc->GetNextWidget(pWidget))) {
      if (!pWidget->IsLoaded()) {
        continue;
      }
      if (bUpdateProperty) {
        pWidget->UpdateWidgetProperty();
      }
      pWidget->PerformLayout();
      pWidget->AddInvalidateRect();
    }
  } else {
    if (eAttr == XFA_ATTRIBUTE_Value) {
      pDocView->AddCalculateNodeNotify(pSender);
    }
  }
}
void CXFA_FFNotify::OnChildAdded(CXFA_Node* pSender,
                                 void* pParam,
                                 void* pParam2) {
  if (!pSender->IsFormContainer()) {
    return;
  }
  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
  if (!pDocView) {
    return;
  }
  FX_BOOL bLayoutReady =
      !(pDocView->m_bInLayoutStatus) &&
      (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
  if (bLayoutReady) {
    m_pDoc->GetDocProvider()->SetChangeMark(m_pDoc);
  }
}
void CXFA_FFNotify::OnChildRemoved(CXFA_Node* pSender,
                                   void* pParam,
                                   void* pParam2) {
  if (CXFA_FFDocView* pDocView = m_pDoc->GetDocView()) {
    FX_BOOL bLayoutReady =
        !(pDocView->m_bInLayoutStatus) &&
        (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
    if (bLayoutReady) {
      m_pDoc->GetDocProvider()->SetChangeMark(m_pDoc);
    }
  }
}
void CXFA_FFNotify::OnLayoutItemAdd(CXFA_FFDocView* pDocView,
                                    CXFA_LayoutProcessor* pLayout,
                                    CXFA_LayoutItem* pSender,
                                    void* pParam,
                                    void* pParam2) {
  CXFA_FFWidget* pWidget = static_cast<CXFA_FFWidget*>(pSender);
  int32_t iPageIdx = (int32_t)(uintptr_t)pParam;
  CXFA_FFPageView* pNewPageView = pDocView->GetPageView(iPageIdx);
  uint32_t dwStatus = (uint32_t)(uintptr_t)pParam2;
  uint32_t dwFilter = XFA_WIDGETSTATUS_Visible | XFA_WIDGETSTATUS_Viewable |
                      XFA_WIDGETSTATUS_Printable;
  pWidget->ModifyStatus(dwStatus, dwFilter);
  CXFA_FFPageView* pPrePageView = pWidget->GetPageView();
  if (pPrePageView != pNewPageView ||
      (dwStatus & (XFA_WIDGETSTATUS_Visible | XFA_WIDGETSTATUS_Viewable)) ==
          (XFA_WIDGETSTATUS_Visible | XFA_WIDGETSTATUS_Viewable)) {
    pWidget->SetPageView(pNewPageView);
    m_pDoc->GetDocProvider()->WidgetEvent(pWidget, pWidget->GetDataAcc(),
                                          XFA_WIDGETEVENT_PostAdded,
                                          pNewPageView, pPrePageView);
  }
  if (pDocView->GetLayoutStatus() != XFA_DOCVIEW_LAYOUTSTATUS_End ||
      !(dwStatus & XFA_WIDGETSTATUS_Visible)) {
    return;
  }
  if (pWidget->IsLoaded()) {
    CFX_RectF rtOld;
    pWidget->GetWidgetRect(rtOld);
    if (rtOld != pWidget->ReCacheWidgetRect())
      pWidget->PerformLayout();
  } else {
    pWidget->LoadWidget();
  }
  pWidget->AddInvalidateRect(nullptr);
}
void CXFA_FFNotify::OnLayoutItemRemoving(CXFA_FFDocView* pDocView,
                                         CXFA_LayoutProcessor* pLayout,
                                         CXFA_LayoutItem* pSender,
                                         void* pParam,
                                         void* pParam2) {
  CXFA_FFWidget* pWidget = static_cast<CXFA_FFWidget*>(pSender);
  pDocView->DeleteLayoutItem(pWidget);
  m_pDoc->GetDocProvider()->WidgetEvent(pWidget, pWidget->GetDataAcc(),
                                        XFA_WIDGETEVENT_PreRemoved, nullptr,
                                        pWidget->GetPageView());
  pWidget->AddInvalidateRect(nullptr);
}
void CXFA_FFNotify::OnLayoutItemRectChanged(CXFA_FFDocView* pDocView,
                                            CXFA_LayoutProcessor* pLayout,
                                            CXFA_LayoutItem* pSender,
                                            void* pParam,
                                            void* pParam2) {}
void CXFA_FFNotify::OnLayoutItemStatustChanged(CXFA_FFDocView* pDocView,
                                               CXFA_LayoutProcessor* pLayout,
                                               CXFA_LayoutItem* pSender,
                                               void* pParam,
                                               void* pParam2) {
  CXFA_FFWidget* pWidget = static_cast<CXFA_FFWidget*>(pSender);
  if (!pWidget) {
    return;
  }
  uint32_t dwStatus = (uint32_t)(uintptr_t)pParam;
  if (dwStatus == 0) {
    CXFA_LayoutItem* pPreItem = pSender->GetPrev();
    if (pPreItem) {
      CXFA_FFWidget* pPreWidget = static_cast<CXFA_FFWidget*>(pPreItem);
      if (pPreWidget) {
        dwStatus = pPreWidget->GetStatus();
      }
    }
  }
  uint32_t dwOldStatus = pWidget->GetStatus();
  uint32_t dwFilter = XFA_WIDGETSTATUS_Visible | XFA_WIDGETSTATUS_Viewable |
                      XFA_WIDGETSTATUS_Printable;
  if ((dwOldStatus & dwFilter) == dwStatus) {
    return;
  }
  pWidget->ModifyStatus(dwStatus, dwFilter);
}