Trigger page view event when re-layout is finished

BUG=pdfium:401
R=tsepez@chromium.org

Review URL: https://codereview.chromium.org/1758553003 .
diff --git a/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp b/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp
index 6e0edf6..d13bbec 100644
--- a/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp
+++ b/fpdfsdk/fpdfxfa/fpdfxfa_doc.cpp
@@ -44,9 +44,13 @@
       m_pXFADoc(nullptr),
       m_pXFADocView(nullptr),
       m_pApp(pProvider),
-      m_pJSContext(nullptr) {}
+      m_pJSContext(nullptr),
+      m_nLoadStatus(FXFA_LOADSTATUS_PRELOAD),
+      m_nPageCount(0) {}
 
 CPDFXFA_Document::~CPDFXFA_Document() {
+  m_nLoadStatus = FXFA_LOADSTATUS_CLOSING;
+
   if (m_pXFADoc) {
     IXFA_App* pApp = m_pApp->GetXFAApp();
     if (pApp) {
@@ -67,9 +71,13 @@
     else
       delete m_pPDFDoc;
   }
+
+  m_nLoadStatus = FXFA_LOADSTATUS_CLOSED;
 }
 
 FX_BOOL CPDFXFA_Document::LoadXFADoc() {
+  m_nLoadStatus = FXFA_LOADSTATUS_LOADING;
+
   if (!m_pPDFDoc)
     return FALSE;
 
@@ -115,6 +123,8 @@
 
   m_pXFADocView->DoLayout(NULL);
   m_pXFADocView->StopLayout();
+  m_nLoadStatus = FXFA_LOADSTATUS_LOADED;
+
   return TRUE;
 }
 
@@ -147,7 +157,8 @@
     if (pPage)
       pPage->AddRef();
   } else {
-    m_XFAPageList.SetSize(GetPageCount());
+    m_nPageCount = GetPageCount();
+    m_XFAPageList.SetSize(m_nPageCount);
   }
   if (pPage)
     return pPage;
@@ -480,25 +491,38 @@
 
 void CPDFXFA_Document::PageViewEvent(IXFA_PageView* pPageView,
                                      FX_DWORD dwFlags) {
-  if (!pPageView || (dwFlags != XFA_PAGEVIEWEVENT_PostAdded &&
-                     dwFlags != XFA_PAGEVIEWEVENT_PostRemoved)) {
-    return;
-  }
-  CPDFXFA_Page* pPage = nullptr;
   CPDFDoc_Environment* pEnv = m_pSDKDoc->GetEnv();
-  if (dwFlags == XFA_PAGEVIEWEVENT_PostAdded) {
-    int nPageIndex = pPageView->GetPageViewIndex();
-    pPage = GetPage(nPageIndex);
-    if (pPage)
-      pPage->SetXFAPageView(pPageView);
-    pEnv->FFI_PageEvent(nPageIndex, dwFlags);
+  if (!pEnv)
     return;
+
+  if (m_nLoadStatus != FXFA_LOADSTATUS_LOADING &&
+      m_nLoadStatus != FXFA_LOADSTATUS_CLOSING &&
+      XFA_PAGEVIEWEVENT_StopLayout == dwFlags) {
+    int nNewCount = GetPageCount();
+    if (nNewCount == m_nPageCount)
+      return;
+
+    IXFA_DocView* pXFADocView = GetXFADocView();
+    if (!pXFADocView)
+      return;
+    for (int iPageIter = 0; iPageIter < m_nPageCount; iPageIter++) {
+      CPDFXFA_Page* pPage = m_XFAPageList.GetAt(iPageIter);
+      if (!pPage)
+        continue;
+      m_pSDKDoc->RemovePageView(pPage);
+      IXFA_PageView* pXFAPageView = pXFADocView->GetPageView(iPageIter);
+      pPage->SetXFAPageView(pXFAPageView);
+      if (pXFAPageView)
+        pXFAPageView->LoadPageView(nullptr);
+    }
+
+    int flag = (nNewCount < m_nPageCount) ? FXFA_PAGEVIEWEVENT_POSTREMOVED
+                                          : FXFA_PAGEVIEWEVENT_POSTADDED;
+    int count = FXSYS_abs(nNewCount - m_nPageCount);
+    m_nPageCount = nNewCount;
+    m_XFAPageList.SetSize(nNewCount);
+    pEnv->FFI_PageEvent(count, flag);
   }
-  pPage = GetPage(pPageView);
-  if (!pPage)
-    return;
-  pEnv->FFI_PageEvent(pPage->GetPageIndex(), dwFlags);
-  pPage->Release();
 }
 
 void CPDFXFA_Document::WidgetEvent(IXFA_Widget* hWidget,
diff --git a/fpdfsdk/fsdk_mgr.cpp b/fpdfsdk/fsdk_mgr.cpp
index 423bb82..1ff1ca7 100644
--- a/fpdfsdk/fsdk_mgr.cpp
+++ b/fpdfsdk/fsdk_mgr.cpp
@@ -858,6 +858,13 @@
                  pPage->GetDocument()->GetDocType() != DOCTYPE_DYNAMIC_XFA))
     return FALSE;
 
+  if (GetFocusAnnot() == pAnnot)
+    KillFocusAnnot();
+  CPDFDoc_Environment* pEnv = m_pSDKDoc->GetEnv();
+  CPDFSDK_AnnotHandlerMgr* pAnnotHandler = pEnv->GetAnnotHandlerMgr();
+  if (pAnnotHandler)
+    pAnnotHandler->ReleaseAnnot(pAnnot);
+
   auto it = std::find(m_fxAnnotArray.begin(), m_fxAnnotArray.end(), pAnnot);
   if (it != m_fxAnnotArray.end())
     m_fxAnnotArray.erase(it);
diff --git a/fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h b/fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h
index 55310e5..5186fe5 100644
--- a/fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h
+++ b/fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h
@@ -204,6 +204,13 @@
   void _ClearChangeMark();
 
  private:
+  enum LoadStatus {
+    FXFA_LOADSTATUS_PRELOAD = 0,
+    FXFA_LOADSTATUS_LOADING,
+    FXFA_LOADSTATUS_LOADED,
+    FXFA_LOADSTATUS_CLOSING,
+    FXFA_LOADSTATUS_CLOSED
+  };
   void CloseXFADoc(IXFA_DocHandler* pDoc) {
     if (pDoc) {
       pDoc->CloseDoc(m_pXFADoc);
@@ -221,6 +228,8 @@
   CPDFXFA_App* m_pApp;
   IJS_Context* m_pJSContext;
   CFX_ArrayTemplate<CPDFXFA_Page*> m_XFAPageList;
+  LoadStatus m_nLoadStatus;
+  int m_nPageCount;
 };
 
 #endif  // FPDFSDK_INCLUDE_FPDFXFA_FPDFXFA_DOC_H_
diff --git a/fpdfsdk/include/fsdk_mgr.h b/fpdfsdk/include/fsdk_mgr.h
index 88b539f..b80e797 100644
--- a/fpdfsdk/include/fsdk_mgr.h
+++ b/fpdfsdk/include/fsdk_mgr.h
@@ -398,9 +398,9 @@
     return L"";
   }
 
-  void FFI_PageEvent(int iPageIndex, FX_DWORD dwEventType) const {
+  void FFI_PageEvent(int iPageCount, FX_DWORD dwEventType) const {
     if (m_pInfo && m_pInfo->FFI_PageEvent)
-      m_pInfo->FFI_PageEvent(m_pInfo, iPageIndex, dwEventType);
+      m_pInfo->FFI_PageEvent(m_pInfo, iPageCount, dwEventType);
   }
 #endif  // PDF_ENABLE_XFA
 
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h
index 81d6b69..90d6663 100644
--- a/public/fpdf_formfill.h
+++ b/public/fpdf_formfill.h
@@ -823,20 +823,29 @@
 
   /**
   * Method: FFI_PageEvent
-  *     This method fires when pages have been added or deleted.
+  *     This method fires when pages have been added to or deleted from the XFA
+  *     document.
   * Interface Version:
   *     2
   * Implementation Required:
   *     yes
   * Parameters:
   *     pThis       -   Pointer to the interface structure itself.
-  *     page_index  -   0-based page number.
+  *     page_count  -   The number of pages to be added to or deleted from the
+  *                     document.
   *     event_type  -   See FXFA_PAGEVIEWEVENT_* above.
   * Return value:
   *       None.
+  * Comments:
+  *           The pages to be added or deleted always start from the last page
+  *           of document. This means that if parameter page_count is 2 and
+  *           event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been
+  *           appended to the tail of document; If page_count is 2 and
+  *           event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages
+  *           have been deleted.
   **/
   void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis,
-                        int page_index,
+                        int page_count,
                         FPDF_DWORD event_type);
 
   /**
diff --git a/xfa/fxfa/app/xfa_ffdocview.cpp b/xfa/fxfa/app/xfa_ffdocview.cpp
index 082ca2b..64d4b23 100644
--- a/xfa/fxfa/app/xfa_ffdocview.cpp
+++ b/xfa/fxfa/app/xfa_ffdocview.cpp
@@ -599,9 +599,13 @@
     m_pXFADocLayout->DoLayout();
     UnlockUpdate();
     m_bInLayoutStatus = FALSE;
+    m_pDoc->GetDocProvider()->PageViewEvent(nullptr,
+                                            XFA_PAGEVIEWEVENT_StopLayout);
     return TRUE;
   }
   m_bInLayoutStatus = FALSE;
+  m_pDoc->GetDocProvider()->PageViewEvent(nullptr,
+                                          XFA_PAGEVIEWEVENT_StopLayout);
   UnlockUpdate();
   return FALSE;
 }
diff --git a/xfa/include/fxfa/fxfa.h b/xfa/include/fxfa/fxfa.h
index 191056c..5e9dd0d 100644
--- a/xfa/include/fxfa/fxfa.h
+++ b/xfa/include/fxfa/fxfa.h
@@ -354,6 +354,7 @@
 #define XFA_PRINTOPT_PrintAnnot 0x00000020
 #define XFA_PAGEVIEWEVENT_PostAdded 1
 #define XFA_PAGEVIEWEVENT_PostRemoved 3
+#define XFA_PAGEVIEWEVENT_StopLayout 4
 #define XFA_WIDGETEVENT_PostAdded 2
 #define XFA_WIDGETEVENT_PreRemoved 3
 #define XFA_WIDGETEVENT_PostContentChanged 6