[Merge to 54] Add observer for BAAnnots from Javascript

This Cl moves the observer code from the CPDFSDK_Widget up into the
CPDFSDK_Annot base class and then adds a second observer for CPDFSDK_BAAnnot
objects.

This allows us to attach an observer to the Annot javascript class which will
update its internal pointer to the BAAnnot if the BAAnnot is destroyed by
the CPDFSDK_PageView being destroyed.

BUG=chromium:642307
R=tsepez@chromium.org

Review URL: https://codereview.chromium.org/2333383002 .

Review-Url: https://codereview.chromium.org/2306663002
diff --git a/fpdfsdk/cpdfsdk_annot.cpp b/fpdfsdk/cpdfsdk_annot.cpp
index 36bec15..9f8cf25 100644
--- a/fpdfsdk/cpdfsdk_annot.cpp
+++ b/fpdfsdk/cpdfsdk_annot.cpp
@@ -9,6 +9,7 @@
 #include <algorithm>
 
 #include "fpdfsdk/include/fsdk_mgr.h"
+#include "third_party/base/stl_util.h"
 
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/fpdfxfa/include/fpdfxfa_doc.h"
@@ -21,10 +22,39 @@
 
 }  // namespace
 
+CPDFSDK_Annot::Observer::Observer(CPDFSDK_Annot** pWatchedPtr)
+    : m_pWatchedPtr(pWatchedPtr) {
+  (*m_pWatchedPtr)->AddObserver(this);
+}
+
+CPDFSDK_Annot::Observer::~Observer() {
+  if (m_pWatchedPtr)
+    (*m_pWatchedPtr)->RemoveObserver(this);
+}
+
+void CPDFSDK_Annot::Observer::OnAnnotDestroyed() {
+  ASSERT(m_pWatchedPtr);
+  *m_pWatchedPtr = nullptr;
+  m_pWatchedPtr = nullptr;
+}
+
 CPDFSDK_Annot::CPDFSDK_Annot(CPDFSDK_PageView* pPageView)
     : m_pPageView(pPageView), m_bSelected(FALSE) {}
 
-CPDFSDK_Annot::~CPDFSDK_Annot() {}
+CPDFSDK_Annot::~CPDFSDK_Annot() {
+  for (auto* pObserver : m_Observers)
+    pObserver->OnAnnotDestroyed();
+}
+
+void CPDFSDK_Annot::AddObserver(Observer* pObserver) {
+  ASSERT(!pdfium::ContainsKey(m_Observers, pObserver));
+  m_Observers.insert(pObserver);
+}
+
+void CPDFSDK_Annot::RemoveObserver(Observer* pObserver) {
+  ASSERT(pdfium::ContainsKey(m_Observers, pObserver));
+  m_Observers.erase(pObserver);
+}
 
 #ifdef PDF_ENABLE_XFA
 
diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp
index dcccf0c..4cd9391 100644
--- a/fpdfsdk/cpdfsdk_widget.cpp
+++ b/fpdfsdk/cpdfsdk_widget.cpp
@@ -26,7 +26,6 @@
 #include "fpdfsdk/include/fsdk_mgr.h"
 #include "fpdfsdk/pdfwindow/PWL_Edit.h"
 #include "fpdfsdk/pdfwindow/PWL_Utils.h"
-#include "third_party/base/stl_util.h"
 
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/fpdfxfa/include/fpdfxfa_doc.h"
@@ -37,22 +36,6 @@
 #include "xfa/fxfa/include/xfa_ffwidgethandler.h"
 #endif  // PDF_ENABLE_XFA
 
-CPDFSDK_Widget::Observer::Observer(CPDFSDK_Widget** pWatchedPtr)
-    : m_pWatchedPtr(pWatchedPtr) {
-  (*m_pWatchedPtr)->AddObserver(this);
-}
-
-CPDFSDK_Widget::Observer::~Observer() {
-  if (m_pWatchedPtr)
-    (*m_pWatchedPtr)->RemoveObserver(this);
-}
-
-void CPDFSDK_Widget::Observer::OnWidgetDestroyed() {
-  ASSERT(m_pWatchedPtr);
-  *m_pWatchedPtr = nullptr;
-  m_pWatchedPtr = nullptr;
-}
-
 CPDFSDK_Widget::CPDFSDK_Widget(CPDF_Annot* pAnnot,
                                CPDFSDK_PageView* pPageView,
                                CPDFSDK_InterForm* pInterForm)
@@ -68,20 +51,7 @@
 {
 }
 
-CPDFSDK_Widget::~CPDFSDK_Widget() {
-  for (auto* pObserver : m_Observers)
-    pObserver->OnWidgetDestroyed();
-}
-
-void CPDFSDK_Widget::AddObserver(Observer* pObserver) {
-  ASSERT(!pdfium::ContainsKey(m_Observers, pObserver));
-  m_Observers.insert(pObserver);
-}
-
-void CPDFSDK_Widget::RemoveObserver(Observer* pObserver) {
-  ASSERT(pdfium::ContainsKey(m_Observers, pObserver));
-  m_Observers.erase(pObserver);
-}
+CPDFSDK_Widget::~CPDFSDK_Widget() {}
 
 #ifdef PDF_ENABLE_XFA
 CXFA_FFWidget* CPDFSDK_Widget::GetMixXFAWidget() const {
diff --git a/fpdfsdk/include/cpdfsdk_annot.h b/fpdfsdk/include/cpdfsdk_annot.h
index 0fbee9e..15f662c 100644
--- a/fpdfsdk/include/cpdfsdk_annot.h
+++ b/fpdfsdk/include/cpdfsdk_annot.h
@@ -23,9 +23,22 @@
 
 class CPDFSDK_Annot {
  public:
+  class Observer {
+   public:
+    explicit Observer(CPDFSDK_Annot** pWatchedPtr);
+    ~Observer();
+    void OnAnnotDestroyed();
+
+   private:
+    CPDFSDK_Annot** m_pWatchedPtr;
+  };
+
   explicit CPDFSDK_Annot(CPDFSDK_PageView* pPageView);
   virtual ~CPDFSDK_Annot();
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
 #ifdef PDF_ENABLE_XFA
   virtual FX_BOOL IsXFAField();
   virtual CXFA_FFWidget* GetXFAWidget() const;
@@ -57,6 +70,7 @@
   void SetSelected(FX_BOOL bSelected);
 
  protected:
+  std::set<Observer*> m_Observers;
   CPDFSDK_PageView* m_pPageView;
   FX_BOOL m_bSelected;
 };
diff --git a/fpdfsdk/include/cpdfsdk_widget.h b/fpdfsdk/include/cpdfsdk_widget.h
index 7f5e345..201de2d 100644
--- a/fpdfsdk/include/cpdfsdk_widget.h
+++ b/fpdfsdk/include/cpdfsdk_widget.h
@@ -35,17 +35,6 @@
 
 class CPDFSDK_Widget : public CPDFSDK_BAAnnot {
  public:
-  class Observer {
-   public:
-    explicit Observer(CPDFSDK_Widget** pWatchedPtr);
-    ~Observer();
-
-    void OnWidgetDestroyed();
-
-   private:
-    CPDFSDK_Widget** m_pWatchedPtr;
-  };
-
 #ifdef PDF_ENABLE_XFA
   CXFA_FFWidget* GetMixXFAWidget() const;
   CXFA_FFWidget* GetGroupMixXFAWidget();
@@ -75,9 +64,6 @@
                  CPDFSDK_InterForm* pInterForm);
   ~CPDFSDK_Widget() override;
 
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-
   CFX_ByteString GetSubType() const override;
   CPDF_Action GetAAction(CPDF_AAction::AActionType eAAT) override;
   FX_BOOL IsAppearanceValid() override;
@@ -180,7 +166,6 @@
   FX_BOOL m_bAppModified;
   int32_t m_nAppAge;
   int32_t m_nValueAge;
-  std::set<Observer*> m_Observers;
 
 #ifdef PDF_ENABLE_XFA
   mutable CXFA_FFWidget* m_hMixXFAWidget;
diff --git a/fpdfsdk/javascript/Annot.cpp b/fpdfsdk/javascript/Annot.cpp
index df12327..95a428a 100644
--- a/fpdfsdk/javascript/Annot.cpp
+++ b/fpdfsdk/javascript/Annot.cpp
@@ -11,6 +11,14 @@
 #include "fpdfsdk/javascript/JS_Value.h"
 #include "fpdfsdk/javascript/cjs_context.h"
 
+namespace {
+
+CPDFSDK_BAAnnot* ToBAAnnot(CPDFSDK_Annot* annot) {
+  return static_cast<CPDFSDK_BAAnnot*>(annot);
+}
+
+}  // namespace
+
 BEGIN_JS_STATIC_CONST(CJS_Annot)
 END_JS_STATIC_CONST()
 
@@ -32,8 +40,12 @@
 FX_BOOL Annot::hidden(IJS_Context* cc,
                       CJS_PropValue& vp,
                       CFX_WideString& sError) {
+  CPDFSDK_BAAnnot* baAnnot = ToBAAnnot(m_pAnnot);
+  if (!baAnnot)
+    return FALSE;
+
   if (vp.IsGetting()) {
-    CPDF_Annot* pPDFAnnot = m_BAAnnot->GetPDFAnnot();
+    CPDF_Annot* pPDFAnnot = baAnnot->GetPDFAnnot();
     vp << CPDF_Annot::IsAnnotationHidden(pPDFAnnot->GetAnnotDict());
     return TRUE;
   }
@@ -41,7 +53,7 @@
   bool bHidden;
   vp >> bHidden;
 
-  uint32_t flags = m_BAAnnot->GetFlags();
+  uint32_t flags = baAnnot->GetFlags();
   if (bHidden) {
     flags |= ANNOTFLAG_HIDDEN;
     flags |= ANNOTFLAG_INVISIBLE;
@@ -53,21 +65,25 @@
     flags &= ~ANNOTFLAG_NOVIEW;
     flags |= ANNOTFLAG_PRINT;
   }
-  m_BAAnnot->SetFlags(flags);
+  baAnnot->SetFlags(flags);
   return TRUE;
 }
 
 FX_BOOL Annot::name(IJS_Context* cc,
                     CJS_PropValue& vp,
                     CFX_WideString& sError) {
+  CPDFSDK_BAAnnot* baAnnot = ToBAAnnot(m_pAnnot);
+  if (!baAnnot)
+    return FALSE;
+
   if (vp.IsGetting()) {
-    vp << m_BAAnnot->GetAnnotName();
+    vp << baAnnot->GetAnnotName();
     return TRUE;
   }
 
   CFX_WideString annotName;
   vp >> annotName;
-  m_BAAnnot->SetAnnotName(annotName);
+  baAnnot->SetAnnotName(annotName);
   return TRUE;
 }
 
@@ -80,10 +96,15 @@
     return FALSE;
   }
 
-  vp << m_BAAnnot->GetType();
+  CPDFSDK_BAAnnot* baAnnot = ToBAAnnot(m_pAnnot);
+  if (!baAnnot)
+    return FALSE;
+
+  vp << baAnnot->GetType();
   return TRUE;
 }
 
 void Annot::SetSDKAnnot(CPDFSDK_BAAnnot* annot) {
-  m_BAAnnot = annot;
+  m_pAnnot = annot;
+  m_pObserver.reset(new CPDFSDK_Annot::Observer(&m_pAnnot));
 }
diff --git a/fpdfsdk/javascript/Annot.h b/fpdfsdk/javascript/Annot.h
index b3ea292..be85035 100644
--- a/fpdfsdk/javascript/Annot.h
+++ b/fpdfsdk/javascript/Annot.h
@@ -7,6 +7,8 @@
 #ifndef FPDFSDK_JAVASCRIPT_ANNOT_H_
 #define FPDFSDK_JAVASCRIPT_ANNOT_H_
 
+#include <memory>
+
 #include "fpdfsdk/include/cpdfsdk_baannot.h"
 #include "fpdfsdk/javascript/JS_Define.h"
 
@@ -22,7 +24,8 @@
   void SetSDKAnnot(CPDFSDK_BAAnnot* annot);
 
  private:
-  CPDFSDK_BAAnnot* m_BAAnnot = nullptr;
+  CPDFSDK_Annot* m_pAnnot = nullptr;
+  std::unique_ptr<CPDFSDK_Annot::Observer> m_pObserver;
 };
 
 class CJS_Annot : public CJS_Object {
diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp
index 0a184d8..64c7735 100644
--- a/fpdfsdk/javascript/Field.cpp
+++ b/fpdfsdk/javascript/Field.cpp
@@ -268,11 +268,12 @@
 
     int nFieldType = pFormField->GetFieldType();
     if (nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_TEXTFIELD) {
-      for (CPDFSDK_Widget* pWidget : widgets) {
+      for (CPDFSDK_Annot* pAnnot : widgets) {
         FX_BOOL bFormatted = FALSE;
-        CPDFSDK_Widget::Observer observer(&pWidget);
+        CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
+        CPDFSDK_Widget::Observer observer(&pAnnot);
         CFX_WideString sValue = pWidget->OnFormat(bFormatted);
-        if (pWidget) {
+        if (pAnnot) {
           pWidget->ResetAppearance(bFormatted ? sValue.c_str() : nullptr,
                                    FALSE);
         }