Make Observers into a templated class

Review-Url: https://codereview.chromium.org/2311343003
diff --git a/core/fxcrt/include/cfx_observable.h b/core/fxcrt/include/cfx_observable.h
new file mode 100644
index 0000000..b669e0d
--- /dev/null
+++ b/core/fxcrt/include/cfx_observable.h
@@ -0,0 +1,66 @@
+// Copyright 2016 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.
+
+#ifndef CORE_FXCRT_INCLUDE_CFX_OBSERVABLE_H_
+#define CORE_FXCRT_INCLUDE_CFX_OBSERVABLE_H_
+
+#include <set>
+
+#include "core/fxcrt/include/fx_system.h"
+#include "third_party/base/stl_util.h"
+
+template <class T>
+class CFX_Observable {
+ public:
+  class Observer {
+   public:
+    Observer() : m_pWatchedPtr(nullptr) {}
+    Observer(T** pWatchedPtr) : m_pWatchedPtr(pWatchedPtr) {
+      if (m_pWatchedPtr)
+        (*m_pWatchedPtr)->AddObserver(this);
+    }
+    Observer(const Observer& that) = delete;
+    ~Observer() {
+      if (m_pWatchedPtr)
+        (*m_pWatchedPtr)->RemoveObserver(this);
+    }
+    void SetWatchedPtr(T** pWatchedPtr) {
+      if (m_pWatchedPtr)
+        (*m_pWatchedPtr)->RemoveObserver(this);
+      m_pWatchedPtr = pWatchedPtr;
+      if (m_pWatchedPtr)
+        (*m_pWatchedPtr)->AddObserver(this);
+    }
+    void OnDestroy() {
+      ASSERT(m_pWatchedPtr);
+      *m_pWatchedPtr = nullptr;
+      m_pWatchedPtr = nullptr;
+    }
+    Observer& operator=(const Observer& that) = delete;
+
+   private:
+    T** m_pWatchedPtr;
+  };
+
+  CFX_Observable() {}
+  CFX_Observable(const CFX_Observable& that) = delete;
+  ~CFX_Observable() {
+    for (auto* pObserver : m_Observers)
+      pObserver->OnDestroy();
+  }
+  void AddObserver(Observer* pObserver) {
+    ASSERT(!pdfium::ContainsKey(m_Observers, pObserver));
+    m_Observers.insert(pObserver);
+  }
+  void RemoveObserver(Observer* pObserver) {
+    ASSERT(pdfium::ContainsKey(m_Observers, pObserver));
+    m_Observers.erase(pObserver);
+  }
+  CFX_Observable& operator=(const CFX_Observable& that) = delete;
+
+ private:
+  std::set<Observer*> m_Observers;
+};
+
+#endif  // CORE_FXCRT_INCLUDE_CFX_OBSERVABLE_H_
diff --git a/fpdfsdk/cpdfsdk_annot.cpp b/fpdfsdk/cpdfsdk_annot.cpp
index 353edaa..738508f 100644
--- a/fpdfsdk/cpdfsdk_annot.cpp
+++ b/fpdfsdk/cpdfsdk_annot.cpp
@@ -22,39 +22,10 @@
 
 }  // 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() {
-  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);
-}
+CPDFSDK_Annot::~CPDFSDK_Annot() {}
 
 #ifdef PDF_ENABLE_XFA
 
diff --git a/fpdfsdk/include/cpdfsdk_annot.h b/fpdfsdk/include/cpdfsdk_annot.h
index a43b877..e7ae2e1 100644
--- a/fpdfsdk/include/cpdfsdk_annot.h
+++ b/fpdfsdk/include/cpdfsdk_annot.h
@@ -10,6 +10,7 @@
 #include "core/fpdfdoc/include/cpdf_aaction.h"
 #include "core/fpdfdoc/include/cpdf_annot.h"
 #include "core/fpdfdoc/include/cpdf_defaultappearance.h"
+#include "core/fxcrt/include/cfx_observable.h"
 #include "core/fxcrt/include/fx_basic.h"
 #include "fpdfsdk/cfx_systemhandler.h"
 #include "fpdfsdk/include/fsdk_common.h"
@@ -21,24 +22,11 @@
 class CPDF_RenderOptions;
 class CPDFSDK_PageView;
 
-class CPDFSDK_Annot {
+class CPDFSDK_Annot : public CFX_Observable<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;
@@ -70,7 +58,6 @@
   void SetSelected(FX_BOOL bSelected);
 
  protected:
-  std::set<Observer*> m_Observers;
   CPDFSDK_PageView* m_pPageView;
   FX_BOOL m_bSelected;
 };
diff --git a/fpdfsdk/javascript/Annot.cpp b/fpdfsdk/javascript/Annot.cpp
index ab84247..d45aa60 100644
--- a/fpdfsdk/javascript/Annot.cpp
+++ b/fpdfsdk/javascript/Annot.cpp
@@ -106,5 +106,5 @@
 
 void Annot::SetSDKAnnot(CPDFSDK_BAAnnot* annot) {
   m_pAnnot = annot;
-  m_pObserver.reset(new CPDFSDK_Annot::Observer(&m_pAnnot));
+  SetWatchedPtr(&m_pAnnot);
 }
diff --git a/fpdfsdk/javascript/Annot.h b/fpdfsdk/javascript/Annot.h
index be85035..c8b0afb 100644
--- a/fpdfsdk/javascript/Annot.h
+++ b/fpdfsdk/javascript/Annot.h
@@ -12,7 +12,7 @@
 #include "fpdfsdk/include/cpdfsdk_baannot.h"
 #include "fpdfsdk/javascript/JS_Define.h"
 
-class Annot : public CJS_EmbedObj {
+class Annot : public CJS_EmbedObj, public CPDFSDK_Annot::Observer {
  public:
   explicit Annot(CJS_Object* pJSObject);
   ~Annot() override;
@@ -25,7 +25,6 @@
 
  private:
   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 64c7735..1f49482 100644
--- a/fpdfsdk/javascript/Field.cpp
+++ b/fpdfsdk/javascript/Field.cpp
@@ -270,12 +270,12 @@
     if (nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_TEXTFIELD) {
       for (CPDFSDK_Annot* pAnnot : widgets) {
         FX_BOOL bFormatted = FALSE;
-        CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
-        CPDFSDK_Widget::Observer observer(&pAnnot);
-        CFX_WideString sValue = pWidget->OnFormat(bFormatted);
+        CPDFSDK_Annot::Observer observer(&pAnnot);
+        CFX_WideString sValue =
+            static_cast<CPDFSDK_Widget*>(pAnnot)->OnFormat(bFormatted);
         if (pAnnot) {
-          pWidget->ResetAppearance(bFormatted ? sValue.c_str() : nullptr,
-                                   FALSE);
+          static_cast<CPDFSDK_Widget*>(pAnnot)->ResetAppearance(
+              bFormatted ? sValue.c_str() : nullptr, FALSE);
         }
       }
     } else {