/* * Copyright (C) 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GenericCallback_h #define GenericCallback_h #include "APIError.h" #include "APISerializedScriptValue.h" #include "ProcessThrottler.h" #include "ShareableBitmap.h" #include "WKAPICast.h" #include #include #include #include #include namespace WebKit { class CallbackBase : public RefCounted { public: enum class Error { None, Unknown, ProcessExited, OwnerWasInvalidated, }; virtual ~CallbackBase() { } uint64_t callbackID() const { return m_callbackID; } template T* as() { if (T::type() == m_type) return static_cast(this); return nullptr; } virtual void invalidate(Error) = 0; protected: struct TypeTag { }; typedef const TypeTag* Type; explicit CallbackBase(Type type, const ProcessThrottler::BackgroundActivityToken& activityToken) : m_type(type) , m_callbackID(generateCallbackID()) , m_activityToken(activityToken) { } private: static uint64_t generateCallbackID() { ASSERT(RunLoop::isMain()); static uint64_t uniqueCallbackID = 1; return uniqueCallbackID++; } Type m_type; uint64_t m_callbackID; ProcessThrottler::BackgroundActivityToken m_activityToken; }; template class GenericCallback : public CallbackBase { public: typedef std::function CallbackFunction; static PassRefPtr create(CallbackFunction callback, const ProcessThrottler::BackgroundActivityToken& activityToken = nullptr) { return adoptRef(new GenericCallback(callback, activityToken)); } virtual ~GenericCallback() { ASSERT(!m_callback); } void performCallbackWithReturnValue(T... returnValue) { if (!m_callback) return; m_callback(returnValue..., Error::None); m_callback = nullptr; } void performCallback() { performCallbackWithReturnValue(); } virtual void invalidate(Error error = Error::Unknown) override final { if (!m_callback) return; m_callback(typename std::remove_reference::type()..., error); m_callback = nullptr; } private: GenericCallback(CallbackFunction callback, const ProcessThrottler::BackgroundActivityToken& activityToken) : CallbackBase(type(), activityToken) , m_callback(callback) { } friend class CallbackBase; static Type type() { static TypeTag tag; return &tag; } CallbackFunction m_callback; }; template::ImplType*> static typename GenericCallback::CallbackFunction toGenericCallbackFunction(void* context, void (*callback)(APIReturnValueType, WKErrorRef, void*)) { return [context, callback](InternalReturnValueType returnValue, CallbackBase::Error error) { callback(toAPI(returnValue), error != CallbackBase::Error::None ? toAPI(API::Error::create().ptr()) : 0, context); }; } typedef GenericCallback<> VoidCallback; typedef GenericCallback&, double> ComputedPagesCallback; typedef GenericCallback ImageCallback; template void invalidateCallbackMap(HashMap& callbackMap, CallbackBase::Error error) { Vector callbacks; copyValuesToVector(callbackMap, callbacks); for (auto& callback : callbacks) callback->invalidate(error); callbackMap.clear(); } class CallbackMap { public: uint64_t put(PassRefPtr callback) { ASSERT(!m_map.contains(callback->callbackID())); uint64_t callbackID = callback->callbackID(); m_map.set(callbackID, callback); return callbackID; } template struct GenericCallbackType { typedef typename GenericCallbackType::type type; }; template struct GenericCallbackType<1, CallbackBase::Error, U...> { typedef GenericCallback type; }; template uint64_t put(std::function function, const ProcessThrottler::BackgroundActivityToken& activityToken) { auto callback = GenericCallbackType::type::create(WTFMove(function), activityToken); return put(callback); } template RefPtr take(uint64_t callbackID) { RefPtr base = m_map.take(callbackID); if (!base) return nullptr; return adoptRef(base.release().leakRef()->as()); } void invalidate(CallbackBase::Error error) { invalidateCallbackMap(m_map, error); } private: HashMap> m_map; }; } // namespace WebKit #endif // GenericCallback_h