| // Copyright 2016 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef COBALT_H5VCC_H5VCC_EVENT_LISTENER_CONTAINER_H_ |
| #define COBALT_H5VCC_H5VCC_EVENT_LISTENER_CONTAINER_H_ |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/location.h" |
| #include "base/message_loop_proxy.h" |
| #include "base/synchronization/lock.h" |
| #include "cobalt/script/callback_function.h" |
| #include "cobalt/script/script_value.h" |
| #include "cobalt/script/wrappable.h" |
| |
| namespace cobalt { |
| namespace h5vcc { |
| |
| // Template class to implement a container of event listeners where the |
| // listener callback can take an argument of any type, including none (void). |
| // Callback type must be specified in addition to callback argument type, |
| // as we cannot typedef a callback taking a void argument. |
| template <class CallbackArgType, class CallbackType> |
| class H5vccEventListenerContainer { |
| public: |
| typedef script::ScriptValue<CallbackType> CallbackHolderType; |
| |
| // Type for a callback that returns the value of the argument to be passed |
| // to the callback for each listener. |
| typedef base::Callback<CallbackArgType()> GetArgumentCallback; |
| |
| // Type for a listener. |
| // We store the message loop from which the listener was registered, |
| // so we can run the callback on the same loop. |
| struct Listener { |
| Listener(script::Wrappable* owner, const CallbackHolderType& cb) |
| : callback(owner, cb), |
| message_loop(base::MessageLoopProxy::current()) {} |
| |
| // Notifies listener. Must be called on the same message loop the |
| // listener registered its callback from. |
| void Notify(GetArgumentCallback on_notify) { |
| DCHECK_EQ(base::MessageLoopProxy::current(), message_loop); |
| CallbackArgType arg = on_notify.Run(); |
| callback.value().Run(arg); |
| } |
| |
| typename CallbackHolderType::Reference callback; |
| scoped_refptr<base::MessageLoopProxy> message_loop; |
| }; |
| |
| explicit H5vccEventListenerContainer(script::Wrappable* owner) |
| : owner_(owner) {} |
| |
| ~H5vccEventListenerContainer() { |
| // Delete all registered listeners. |
| for (typename ListenerVector::const_iterator it = listeners_.begin(); |
| it != listeners_.end(); ++it) { |
| delete *it; |
| } |
| } |
| |
| // Called from JavaScript to register an event listener. May be called from |
| // any thread, and event notification will be called on the same thread. |
| void AddListener(const CallbackHolderType& callback_holder) { |
| base::AutoLock auto_lock(lock_); |
| listeners_.push_back(new Listener(owner_, callback_holder)); |
| } |
| |
| // Dispatches an event to the registered listeners. May be called from any |
| // thread, and the callbacks will be invoked on the same thread each listener |
| // was registered on. |get_argument_callback| must be a function that |
| // returns the argument value for this event. |
| void DispatchEvent(GetArgumentCallback get_argument_callback) { |
| base::AutoLock auto_lock(lock_); |
| for (typename ListenerVector::iterator it = listeners_.begin(); |
| it != listeners_.end(); ++it) { |
| Listener* listener = *it; |
| listener->message_loop->PostTask( |
| FROM_HERE, base::Bind(&Listener::Notify, base::Unretained(listener), |
| get_argument_callback)); |
| } |
| } |
| |
| private: |
| typedef std::vector<Listener*> ListenerVector; |
| |
| script::Wrappable* owner_; |
| ListenerVector listeners_; |
| base::Lock lock_; |
| }; |
| |
| // Explicit template specialization for the no callback argument case, where |
| // we don't need to call the |GetArgumentCallback| callback. |
| template <> |
| inline void |
| H5vccEventListenerContainer<void, script::CallbackFunction<void()> >:: |
| Listener::Notify(GetArgumentCallback) { |
| DCHECK_EQ(base::MessageLoopProxy::current(), message_loop); |
| callback.value().Run(); |
| } |
| |
| } // namespace h5vcc |
| } // namespace cobalt |
| |
| #endif // COBALT_H5VCC_H5VCC_EVENT_LISTENER_CONTAINER_H_ |