Bug 1129523 - Implement MediaPromise proxies. r=cpearce,r=mattwoodrow

This commit is contained in:
Bobby Holley 2015-02-04 17:12:51 -08:00
parent 36dcff0baf
commit 1bedd8d3d7

View File

@ -537,6 +537,112 @@ private:
nsRefPtr<typename PromiseType::Consumer> mConsumer;
};
// Proxy Media Calls.
//
// This machinery allows callers to schedule a promise-returning method to be
// invoked asynchronously on a given thread, while at the same time receiving
// a promise upon which to invoke Then() immediately. ProxyMediaCall dispatches
// a task to invoke the method on the proper thread and also chain the resulting
// promise to the one that the caller received, so that resolve/reject values
// are forwarded through.
namespace detail {
template<typename PromiseType>
class MethodCallBase
{
public:
MethodCallBase() { MOZ_COUNT_CTOR(MethodCallBase); }
virtual nsRefPtr<PromiseType> Invoke() = 0;
virtual ~MethodCallBase() { MOZ_COUNT_DTOR(MethodCallBase); };
};
template<typename PromiseType, typename ThisType>
class MethodCallWithNoArgs : public MethodCallBase<PromiseType>
{
public:
typedef nsRefPtr<PromiseType>(ThisType::*Type)();
MethodCallWithNoArgs(ThisType* aThisVal, Type aMethod)
: mThisVal(aThisVal), mMethod(aMethod) {}
nsRefPtr<PromiseType> Invoke() MOZ_OVERRIDE { return ((*mThisVal).*mMethod)(); }
protected:
nsRefPtr<ThisType> mThisVal;
Type mMethod;
};
// NB: MethodCallWithOneArg definition should go here, if/when it is needed.
template<typename PromiseType, typename ThisType, typename Arg1Type, typename Arg2Type>
class MethodCallWithTwoArgs : public MethodCallBase<PromiseType>
{
public:
typedef nsRefPtr<PromiseType>(ThisType::*Type)(Arg1Type, Arg2Type);
MethodCallWithTwoArgs(ThisType* aThisVal, Type aMethod, Arg1Type aArg1, Arg2Type aArg2)
: mThisVal(aThisVal), mMethod(aMethod), mArg1(aArg1), mArg2(aArg2) {}
nsRefPtr<PromiseType> Invoke() MOZ_OVERRIDE { return ((*mThisVal).*mMethod)(mArg1, mArg2); }
protected:
nsRefPtr<ThisType> mThisVal;
Type mMethod;
Arg1Type mArg1;
Arg2Type mArg2;
};
template<typename PromiseType>
class ProxyRunnable : public nsRunnable
{
public:
ProxyRunnable(PromiseType* aProxyPromise, MethodCallBase<PromiseType>* aMethodCall)
: mProxyPromise(aProxyPromise), mMethodCall(aMethodCall) {}
NS_IMETHODIMP Run()
{
nsRefPtr<PromiseType> p = mMethodCall->Invoke();
mMethodCall = nullptr;
p->ChainTo(mProxyPromise.forget(), "<Proxy Promise>");
return NS_OK;
}
private:
nsRefPtr<PromiseType> mProxyPromise;
nsAutoPtr<MethodCallBase<PromiseType>> mMethodCall;
};
template<typename PromiseType, typename TargetType>
static nsRefPtr<PromiseType>
ProxyInternal(TargetType* aTarget, MethodCallBase<PromiseType>* aMethodCall, const char* aCallerName)
{
nsRefPtr<PromiseType> p = new PromiseType(aCallerName);
nsRefPtr<ProxyRunnable<PromiseType>> r = new ProxyRunnable<PromiseType>(p, aMethodCall);
nsresult rv = detail::DispatchMediaPromiseRunnable(aTarget, r);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return p;
}
} // namespace detail
template<typename PromiseType, typename TargetType, typename ThisType>
static nsRefPtr<PromiseType>
ProxyMediaCall(TargetType* aTarget, ThisType* aThisVal, const char* aCallerName,
nsRefPtr<PromiseType>(ThisType::*aMethod)())
{
typedef detail::MethodCallWithNoArgs<PromiseType, ThisType> MethodCallType;
MethodCallType* methodCall = new MethodCallType(aThisVal, aMethod);
return detail::ProxyInternal(aTarget, methodCall, aCallerName);
}
// NB: One-arg overload should go here, if/when it is needed.
template<typename PromiseType, typename TargetType, typename ThisType,
typename Arg1Type, typename Arg2Type>
static nsRefPtr<PromiseType>
ProxyMediaCall(TargetType* aTarget, ThisType* aThisVal, const char* aCallerName,
nsRefPtr<PromiseType>(ThisType::*aMethod)(Arg1Type, Arg2Type), Arg1Type aArg1, Arg2Type aArg2)
{
typedef detail::MethodCallWithTwoArgs<PromiseType, ThisType, Arg1Type, Arg2Type> MethodCallType;
MethodCallType* methodCall = new MethodCallType(aThisVal, aMethod, aArg1, aArg2);
return detail::ProxyInternal(aTarget, methodCall, aCallerName);
}
#undef PROMISE_LOG
} // namespace mozilla