OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
3 * Copyright (C) 2013 Google Inc. All Rights Reserved. | 3 * Copyright (C) 2013 Google Inc. All Rights Reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 24 matching lines...) Expand all Loading... |
35 | 35 |
36 template <typename T, typename Observer> | 36 template <typename T, typename Observer> |
37 class LifecycleNotifier : public virtual GarbageCollectedMixin { | 37 class LifecycleNotifier : public virtual GarbageCollectedMixin { |
38 public: | 38 public: |
39 virtual ~LifecycleNotifier(); | 39 virtual ~LifecycleNotifier(); |
40 | 40 |
41 void addObserver(Observer*); | 41 void addObserver(Observer*); |
42 void removeObserver(Observer*); | 42 void removeObserver(Observer*); |
43 | 43 |
44 // notifyContextDestroyed() should be explicitly dispatched from an | 44 // notifyContextDestroyed() should be explicitly dispatched from an |
45 // observed context to notify observers that contextDestroyed(). | 45 // observed context to detach its observers, and if the observer kind |
| 46 // requires it, notify each observer by invoking contextDestroyed(). |
46 // | 47 // |
47 // When contextDestroyed() is called, the observer's lifecycleContext() | 48 // When contextDestroyed() is called, it is supplied the context as |
48 // is still valid and safe to use during the notification. | 49 // an argument, but the observer's lifecycleContext() is still valid |
| 50 // and safe to use while handling the notification. |
49 virtual void notifyContextDestroyed(); | 51 virtual void notifyContextDestroyed(); |
50 | 52 |
51 DEFINE_INLINE_VIRTUAL_TRACE() { visitor->trace(m_observers); } | 53 DEFINE_INLINE_VIRTUAL_TRACE() { visitor->trace(m_observers); } |
52 | 54 |
53 bool isIteratingOverObservers() const { | 55 bool isIteratingOverObservers() const { |
54 return m_iterationState != NotIterating; | 56 return m_iterationState != NotIterating; |
55 } | 57 } |
56 | 58 |
57 protected: | 59 protected: |
58 LifecycleNotifier() : m_iterationState(NotIterating) {} | 60 LifecycleNotifier() : m_iterationState(NotIterating) {} |
(...skipping 16 matching lines...) Expand all Loading... |
75 ObserverSet m_observers; | 77 ObserverSet m_observers; |
76 }; | 78 }; |
77 | 79 |
78 template <typename T, typename Observer> | 80 template <typename T, typename Observer> |
79 inline LifecycleNotifier<T, Observer>::~LifecycleNotifier() { | 81 inline LifecycleNotifier<T, Observer>::~LifecycleNotifier() { |
80 // FIXME: Enable the following ASSERT. Also see a FIXME in | 82 // FIXME: Enable the following ASSERT. Also see a FIXME in |
81 // Document::detachLayoutTree(). | 83 // Document::detachLayoutTree(). |
82 // ASSERT(!m_observers.size()); | 84 // ASSERT(!m_observers.size()); |
83 } | 85 } |
84 | 86 |
| 87 // Determine if |contextDestroyed(Observer*) is a public method on |
| 88 // class type |Observer|, or any of the class types it derives from. |
| 89 template <typename Observer, typename T> |
| 90 class HasContextDestroyed { |
| 91 using YesType = char; |
| 92 using NoType = int; |
| 93 |
| 94 template <typename V> |
| 95 static YesType checkHasContextDestroyedMethod( |
| 96 V* observer, |
| 97 T* context = nullptr, |
| 98 typename std::enable_if< |
| 99 std::is_same<decltype(observer->contextDestroyed(context)), |
| 100 void>::value>::type* g = nullptr); |
| 101 template <typename V> |
| 102 static NoType checkHasContextDestroyedMethod(...); |
| 103 |
| 104 public: |
| 105 static_assert(sizeof(Observer), "Observer's class declaration not in scope"); |
| 106 static const bool value = |
| 107 sizeof(YesType) == |
| 108 sizeof(checkHasContextDestroyedMethod<Observer>(nullptr)); |
| 109 }; |
| 110 |
| 111 // If |Observer::contextDestroyed()| is present, invoke it. |
| 112 template <typename Observer, |
| 113 typename T, |
| 114 bool = HasContextDestroyed<Observer, T>::value> |
| 115 class NotifyContextDestroyed { |
| 116 STATIC_ONLY(NotifyContextDestroyed); |
| 117 |
| 118 public: |
| 119 static void call(Observer* observer, T* context) { |
| 120 observer->contextDestroyed(context); |
| 121 } |
| 122 }; |
| 123 |
| 124 template <typename Observer, typename T> |
| 125 class NotifyContextDestroyed<Observer, T, false> { |
| 126 STATIC_ONLY(NotifyContextDestroyed); |
| 127 |
| 128 public: |
| 129 static void call(Observer*, T*) {} |
| 130 }; |
| 131 |
85 template <typename T, typename Observer> | 132 template <typename T, typename Observer> |
86 inline void LifecycleNotifier<T, Observer>::notifyContextDestroyed() { | 133 inline void LifecycleNotifier<T, Observer>::notifyContextDestroyed() { |
87 // Observer unregistration is allowed, but effectively a no-op. | 134 // Observer unregistration is allowed, but effectively a no-op. |
88 AutoReset<IterationState> scope(&m_iterationState, AllowingRemoval); | 135 AutoReset<IterationState> scope(&m_iterationState, AllowingRemoval); |
89 ObserverSet observers; | 136 ObserverSet observers; |
90 m_observers.swap(observers); | 137 m_observers.swap(observers); |
91 for (Observer* observer : observers) { | 138 for (Observer* observer : observers) { |
92 DCHECK(observer->lifecycleContext() == context()); | 139 DCHECK(observer->lifecycleContext() == context()); |
93 observer->contextDestroyed(context()); | 140 NotifyContextDestroyed<Observer, T>::call(observer, context()); |
94 observer->clearContext(); | 141 observer->clearContext(); |
95 } | 142 } |
96 } | 143 } |
97 | 144 |
98 template <typename T, typename Observer> | 145 template <typename T, typename Observer> |
99 inline void LifecycleNotifier<T, Observer>::addObserver(Observer* observer) { | 146 inline void LifecycleNotifier<T, Observer>::addObserver(Observer* observer) { |
100 RELEASE_ASSERT(m_iterationState & AllowingAddition); | 147 RELEASE_ASSERT(m_iterationState & AllowingAddition); |
101 m_observers.add(observer); | 148 m_observers.add(observer); |
102 } | 149 } |
103 | 150 |
104 template <typename T, typename Observer> | 151 template <typename T, typename Observer> |
105 inline void LifecycleNotifier<T, Observer>::removeObserver(Observer* observer) { | 152 inline void LifecycleNotifier<T, Observer>::removeObserver(Observer* observer) { |
106 // If immediate removal isn't currently allowed, | 153 // If immediate removal isn't currently allowed, |
107 // |observer| is recorded for pending removal. | 154 // |observer| is recorded for pending removal. |
108 if (m_iterationState & AllowPendingRemoval) { | 155 if (m_iterationState & AllowPendingRemoval) { |
109 m_observers.add(observer); | 156 m_observers.add(observer); |
110 return; | 157 return; |
111 } | 158 } |
112 RELEASE_ASSERT(m_iterationState & AllowingRemoval); | 159 RELEASE_ASSERT(m_iterationState & AllowingRemoval); |
113 m_observers.remove(observer); | 160 m_observers.remove(observer); |
114 } | 161 } |
115 | 162 |
116 } // namespace blink | 163 } // namespace blink |
117 | 164 |
118 #endif // LifecycleNotifier_h | 165 #endif // LifecycleNotifier_h |
OLD | NEW |