Changeset 205953 in webkit


Ignore:
Timestamp:
Sep 15, 2016 12:21:18 AM (8 years ago)
Author:
commit-queue@webkit.org
Message:

callPromiseFunction should be made usable for custom binding code
https://bugs.webkit.org/show_bug.cgi?id=161961

Patch by Youenn Fablet <youenn@apple.com> on 2016-09-15
Reviewed by Darin Adler.

Source/WebCore:

Covered by updated test.

  • bindings/js/JSDOMBinding.h:

(WebCore::castThisValue): Utility function to cast this value to a specific type.

  • bindings/js/JSDOMPromise.h:

(WebCore::callPromiseFunction): Updated to take real promise function as a template parameter
for improved efficiency. Added workerMode template parameter.
(WebCore::bindingPromiseFunctionAdapter): Function signature adaptor.

  • bindings/js/JSMediaDevicesCustom.cpp:

(WebCore::JSMediaDevicesGetUserMediaPromiseFunction):
(WebCore::JSMediaDevices::getUserMedia): Making use of callPromiseFunction to properly handle exceptions.

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateImplementation): Updated to use template parameter.

  • bindings/scripts/test/JS/JSTestNode.cpp:

(WebCore::jsTestNodePrototypeFunctionTestWorkerPromise):
(WebCore::jsTestNodePrototypeFunctionTestWorkerPromisePromise):

  • bindings/scripts/test/JS/JSTestObj.cpp:

(WebCore::jsTestObjPrototypeFunctionTestPromiseFunction):
(WebCore::jsTestObjPrototypeFunctionTestPromiseFunctionWithFloatArgument):
(WebCore::jsTestObjPrototypeFunctionTestPromiseFunctionWithException):
(WebCore::jsTestObjPrototypeFunctionTestPromiseFunctionWithOptionalIntArgument):
(WebCore::jsTestObjPrototypeFunctionTestPromiseOverloadedFunction1):
(WebCore::jsTestObjPrototypeFunctionTestPromiseOverloadedFunction2):
(WebCore::jsTestObjConstructorFunctionTestStaticPromiseFunction):
(WebCore::jsTestObjConstructorFunctionTestStaticPromiseFunctionWithException):

  • bindings/scripts/test/TestNode.idl: Adding Worker promise binding test.

LayoutTests:

  • fast/mediastream/MediaDevices-getUserMedia-expected.txt:
  • fast/mediastream/MediaDevices-getUserMedia.html: Updated to expect a rejected promise in lieu of an exception.
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r205945 r205953  
     12016-09-15  Youenn Fablet  <youenn@apple.com>
     2
     3        callPromiseFunction should be made usable for custom binding code
     4        https://bugs.webkit.org/show_bug.cgi?id=161961
     5
     6        Reviewed by Darin Adler.
     7
     8        * fast/mediastream/MediaDevices-getUserMedia-expected.txt:
     9        * fast/mediastream/MediaDevices-getUserMedia.html: Updated to expect a rejected promise in lieu of an exception.
     10
    1112016-09-14  Jiewen Tan  <jiewen_tan@apple.com>
    212
  • trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia-expected.txt

    r204516 r205953  
    44
    55
    6 PASS navigator.mediaDevices.getUserMedia().then(invalidGotStream); threw exception TypeError: Not enough arguments.
    76PASS typeof navigator.mediaDevices.webkitGetUserMedia is 'undefined'
    87PASS navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream1); did not throw exception.
    9 PASS  navigator.mediaDevices.getUserMedia({}) rejected with error: TypeError: Type error
     8PASS navigator.mediaDevices.getUserMedia() rejected with error: TypeError: Not enough arguments
     9PASS navigator.mediaDevices.getUserMedia({}) rejected with error: TypeError: Type error
    1010PASS Stream generated.
    1111PASS stream.getAudioTracks().length is 1
  • trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia.html

    r204516 r205953  
    137137            }
    138138
    139             shouldThrow("navigator.mediaDevices.getUserMedia().then(invalidGotStream);");
     139            navigator.mediaDevices.getUserMedia().then(invalidGotStream, function(error) {
     140                testPassed("navigator.mediaDevices.getUserMedia() rejected with error: " + error);
     141            });
    140142            navigator.mediaDevices.getUserMedia({}).then(invalidGotStream, function(error) {
    141                 testPassed(" navigator.mediaDevices.getUserMedia({}) rejected with error: " + error);
     143                testPassed("navigator.mediaDevices.getUserMedia({}) rejected with error: " + error);
    142144            });
    143145            shouldBe("typeof navigator.mediaDevices.webkitGetUserMedia", "'undefined'");
  • trunk/Source/WebCore/ChangeLog

    r205941 r205953  
     12016-09-15  Youenn Fablet  <youenn@apple.com>
     2
     3        callPromiseFunction should be made usable for custom binding code
     4        https://bugs.webkit.org/show_bug.cgi?id=161961
     5
     6        Reviewed by Darin Adler.
     7
     8        Covered by updated test.
     9
     10        * bindings/js/JSDOMBinding.h:
     11        (WebCore::castThisValue): Utility function to cast this value to a specific type.
     12        * bindings/js/JSDOMPromise.h:
     13        (WebCore::callPromiseFunction): Updated to take real promise function as a template parameter
     14        for improved efficiency. Added workerMode template parameter.
     15        (WebCore::bindingPromiseFunctionAdapter): Function signature adaptor.
     16        * bindings/js/JSMediaDevicesCustom.cpp:
     17        (WebCore::JSMediaDevicesGetUserMediaPromiseFunction):
     18        (WebCore::JSMediaDevices::getUserMedia): Making use of callPromiseFunction to properly handle exceptions.
     19        * bindings/scripts/CodeGeneratorJS.pm:
     20        (GenerateImplementation): Updated to use template parameter.
     21        * bindings/scripts/test/JS/JSTestNode.cpp:
     22        (WebCore::jsTestNodePrototypeFunctionTestWorkerPromise):
     23        (WebCore::jsTestNodePrototypeFunctionTestWorkerPromisePromise):
     24        * bindings/scripts/test/JS/JSTestObj.cpp:
     25        (WebCore::jsTestObjPrototypeFunctionTestPromiseFunction):
     26        (WebCore::jsTestObjPrototypeFunctionTestPromiseFunctionWithFloatArgument):
     27        (WebCore::jsTestObjPrototypeFunctionTestPromiseFunctionWithException):
     28        (WebCore::jsTestObjPrototypeFunctionTestPromiseFunctionWithOptionalIntArgument):
     29        (WebCore::jsTestObjPrototypeFunctionTestPromiseOverloadedFunction1):
     30        (WebCore::jsTestObjPrototypeFunctionTestPromiseOverloadedFunction2):
     31        (WebCore::jsTestObjConstructorFunctionTestStaticPromiseFunction):
     32        (WebCore::jsTestObjConstructorFunctionTestStaticPromiseFunctionWithException):
     33        * bindings/scripts/test/TestNode.idl: Adding Worker promise binding test.
     34
    1352016-09-14  Jiewen Tan  <jiewen_tan@apple.com>
    236
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.h

    r205744 r205953  
    174174template<typename DOMClass> JSC::JSValue wrap(JSC::ExecState*, JSDOMGlobalObject*, DOMClass&);
    175175
     176template<typename JSClass> JSClass& castThisValue(JSC::ExecState&);
     177
    176178void addImpureProperty(const AtomicString&);
    177179
     
    528530        return wrapper;
    529531    return toJSNewlyCreated(state, globalObject, Ref<DOMClass>(domObject));
     532}
     533
     534template<typename JSClass> inline JSClass& castThisValue(JSC::ExecState& state)
     535{
     536    auto thisValue = state.thisValue();
     537    auto castedThis = JSC::jsDynamicCast<JSClass*>(thisValue);
     538    ASSERT(castedThis);
     539    return *castedThis;
    530540}
    531541
  • trunk/Source/WebCore/bindings/js/JSDOMPromise.h

    r205729 r205953  
    158158void rejectPromiseWithExceptionIfAny(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSPromiseDeferred&);
    159159
    160 inline JSC::JSValue callPromiseFunction(JSC::ExecState& state, JSC::EncodedJSValue promiseFunction(JSC::ExecState*, Ref<DeferredWrapper>&&))
     160using PromiseFunction = void(JSC::ExecState&, Ref<DeferredWrapper>&&);
     161
     162enum class PromiseExecutionScope { WindowOnly, WindowOrWorker };
     163
     164template<PromiseFunction promiseFunction, PromiseExecutionScope executionScope>
     165inline JSC::JSValue callPromiseFunction(JSC::ExecState& state)
    161166{
    162167    JSC::VM& vm = state.vm();
     
    167172
    168173    // promiseDeferred can be null when terminating a Worker abruptly.
    169     if (!promiseDeferred)
     174    if (executionScope == PromiseExecutionScope::WindowOrWorker && !promiseDeferred)
    170175        return JSC::jsUndefined();
    171176
    172     promiseFunction(&state, DeferredWrapper::create(&state, &globalObject, promiseDeferred));
     177    promiseFunction(state, DeferredWrapper::create(&state, &globalObject, promiseDeferred));
    173178
    174179    rejectPromiseWithExceptionIfAny(state, globalObject, *promiseDeferred);
    175180    ASSERT_UNUSED(scope, !scope.exception());
    176181    return promiseDeferred->promise();
     182}
     183
     184using BindingPromiseFunction = JSC::EncodedJSValue(JSC::ExecState*, Ref<DeferredWrapper>&&);
     185template<BindingPromiseFunction bindingFunction>
     186inline void bindingPromiseFunctionAdapter(JSC::ExecState& state, Ref<DeferredWrapper>&& promise)
     187{
     188    bindingFunction(&state, WTFMove(promise));
     189}
     190
     191template<BindingPromiseFunction bindingPromiseFunction, PromiseExecutionScope executionScope>
     192inline JSC::JSValue callPromiseFunction(JSC::ExecState& state)
     193{
     194    return callPromiseFunction<bindingPromiseFunctionAdapter<bindingPromiseFunction>, executionScope>(state);
    177195}
    178196
  • trunk/Source/WebCore/bindings/js/JSMediaDevicesCustom.cpp

    r205348 r205953  
    341341}
    342342
    343 JSValue JSMediaDevices::getUserMedia(ExecState& state)
     343static void JSMediaDevicesGetUserMediaPromiseFunction(ExecState& state, Ref<DeferredWrapper>&& promise)
    344344{
    345345    VM& vm = state.vm();
    346346    auto scope = DECLARE_THROW_SCOPE(vm);
    347347
    348     if (UNLIKELY(state.argumentCount() < 1))
    349         return JSValue::decode(throwVMError(&state, scope, createNotEnoughArgumentsError(&state)));
     348    if (UNLIKELY(state.argumentCount() < 1)) {
     349        throwVMError(&state, scope, createNotEnoughArgumentsError(&state));
     350        return;
     351    }
     352
    350353    ExceptionCode ec = 0;
    351354    auto constraintsDictionary = Dictionary(&state, state.uncheckedArgument(0));
     
    375378    auto audioConstraints = MediaConstraintsImpl::create(WTFMove(mandatoryAudioConstraints), WTFMove(advancedAudioConstraints), areAudioConstraintsValid);
    376379    auto videoConstraints = MediaConstraintsImpl::create(WTFMove(mandatoryVideoConstraints), WTFMove(advancedVideoConstraints), areVideoConstraintsValid);
    377     JSC::JSPromiseDeferred* promiseDeferred = JSC::JSPromiseDeferred::create(&state, globalObject());
    378     wrapped().getUserMedia(WTFMove(audioConstraints), WTFMove(videoConstraints), DeferredWrapper::create(&state, globalObject(), promiseDeferred), ec);
     380    castThisValue<JSMediaDevices>(state).wrapped().getUserMedia(WTFMove(audioConstraints), WTFMove(videoConstraints), WTFMove(promise), ec);
    379381    setDOMException(&state, ec);
    380     return promiseDeferred->promise();
     382}
     383
     384JSValue JSMediaDevices::getUserMedia(ExecState& state)
     385{
     386    return callPromiseFunction<JSMediaDevicesGetUserMediaPromiseFunction, PromiseExecutionScope::WindowOnly>(state);
    381387}
    382388
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r205913 r205953  
    34223422                AddToImplIncludes("JSDOMPromise.h");
    34233423
     3424                my $scope = $interface->extendedAttributes->{"Exposed"} ? "WindowOrWorker" : "WindowOnly";
    34243425                push(@implContent, <<END);
    34253426static EncodedJSValue ${functionName}Promise(ExecState*, Ref<DeferredWrapper>&&);
     3427
    34263428${functionReturn} ${functionName}(ExecState* state)
    34273429{
    3428     return JSValue::encode(callPromiseFunction(*state, ${functionName}Promise));
    3429 }
    3430 
    3431 static inline EncodedJSValue ${functionName}Promise(ExecState* state, Ref<DeferredWrapper>&&  deferredWrapper)
     3430    ASSERT(state);
     3431    return JSValue::encode(callPromiseFunction<${functionName}Promise, PromiseExecutionScope::${scope}>(*state));
     3432}
     3433
     3434static inline EncodedJSValue ${functionName}Promise(ExecState* state, Ref<DeferredWrapper>&& deferredWrapper)
    34323435END
    34333436            }
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp

    r205569 r205953  
    2626#include "JSDOMConstructor.h"
    2727#include "JSDOMIterator.h"
     28#include "JSDOMPromise.h"
    2829#include "RuntimeEnabledFeatures.h"
    2930#include "URL.h"
     
    3839// Functions
    3940
     41JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionTestWorkerPromise(JSC::ExecState*);
    4042JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionSymbolIterator(JSC::ExecState*);
    4143JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionEntries(JSC::ExecState*);
     
    109111    { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestNodeConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestNodeConstructor) } },
    110112    { "name", CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestNodeName), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestNodeName) } },
     113    { "testWorkerPromise", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestNodePrototypeFunctionTestWorkerPromise), (intptr_t) (0) } },
    111114    { "entries", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestNodePrototypeFunctionEntries), (intptr_t) (0) } },
    112115    { "keys", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestNodePrototypeFunctionKeys), (intptr_t) (0) } },
     
    227230{
    228231    return getDOMConstructor<JSTestNodeConstructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
     232}
     233
     234static EncodedJSValue jsTestNodePrototypeFunctionTestWorkerPromisePromise(ExecState*, Ref<DeferredWrapper>&&);
     235EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionTestWorkerPromise(ExecState* state)
     236{
     237    ASSERT(state);
     238    return JSValue::encode(callPromiseFunction<jsTestNodePrototypeFunctionTestWorkerPromisePromise, true>(*state));
     239}
     240
     241static inline EncodedJSValue jsTestNodePrototypeFunctionTestWorkerPromisePromise(ExecState* state, Ref<DeferredWrapper>&&  deferredWrapper)
     242{
     243    VM& vm = state->vm();
     244    auto throwScope = DECLARE_THROW_SCOPE(vm);
     245    UNUSED_PARAM(throwScope);
     246    JSValue thisValue = state->thisValue();
     247    auto castedThis = jsDynamicCast<JSTestNode*>(thisValue);
     248    if (UNLIKELY(!castedThis))
     249        return throwThisTypeError(*state, throwScope, "TestNode", "testWorkerPromise");
     250    ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestNode::info());
     251    auto& impl = castedThis->wrapped();
     252    impl.testWorkerPromise(WTFMove(deferredWrapper));
     253    return JSValue::encode(jsUndefined());
    229254}
    230255
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp

    r205897 r205953  
    71617161EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunction(ExecState* state)
    71627162{
    7163     return JSValue::encode(callPromiseFunction(*state, jsTestObjPrototypeFunctionTestPromiseFunctionPromise));
     7163    ASSERT(state);
     7164    return JSValue::encode(callPromiseFunction<jsTestObjPrototypeFunctionTestPromiseFunctionPromise, false>(*state));
    71647165}
    71657166
     
    71827183EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunctionWithFloatArgument(ExecState* state)
    71837184{
    7184     return JSValue::encode(callPromiseFunction(*state, jsTestObjPrototypeFunctionTestPromiseFunctionWithFloatArgumentPromise));
     7185    ASSERT(state);
     7186    return JSValue::encode(callPromiseFunction<jsTestObjPrototypeFunctionTestPromiseFunctionWithFloatArgumentPromise, false>(*state));
    71857187}
    71867188
     
    72087210EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunctionWithException(ExecState* state)
    72097211{
    7210     return JSValue::encode(callPromiseFunction(*state, jsTestObjPrototypeFunctionTestPromiseFunctionWithExceptionPromise));
     7212    ASSERT(state);
     7213    return JSValue::encode(callPromiseFunction<jsTestObjPrototypeFunctionTestPromiseFunctionWithExceptionPromise, false>(*state));
    72117214}
    72127215
     
    72317234EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionTestPromiseFunctionWithOptionalIntArgument(ExecState* state)
    72327235{
    7233     return JSValue::encode(callPromiseFunction(*state, jsTestObjPrototypeFunctionTestPromiseFunctionWithOptionalIntArgumentPromise));
     7236    ASSERT(state);
     7237    return JSValue::encode(callPromiseFunction<jsTestObjPrototypeFunctionTestPromiseFunctionWithOptionalIntArgumentPromise, false>(*state));
    72347238}
    72357239
     
    72557259static inline EncodedJSValue jsTestObjPrototypeFunctionTestPromiseOverloadedFunction1(ExecState* state)
    72567260{
    7257     return JSValue::encode(callPromiseFunction(*state, jsTestObjPrototypeFunctionTestPromiseOverloadedFunction1Promise));
     7261    ASSERT(state);
     7262    return JSValue::encode(callPromiseFunction<jsTestObjPrototypeFunctionTestPromiseOverloadedFunction1Promise, false>(*state));
    72587263}
    72597264
     
    72817286static inline EncodedJSValue jsTestObjPrototypeFunctionTestPromiseOverloadedFunction2(ExecState* state)
    72827287{
    7283     return JSValue::encode(callPromiseFunction(*state, jsTestObjPrototypeFunctionTestPromiseOverloadedFunction2Promise));
     7288    ASSERT(state);
     7289    return JSValue::encode(callPromiseFunction<jsTestObjPrototypeFunctionTestPromiseOverloadedFunction2Promise, false>(*state));
    72847290}
    72857291
     
    73247330EncodedJSValue JSC_HOST_CALL jsTestObjConstructorFunctionTestStaticPromiseFunction(ExecState* state)
    73257331{
    7326     return JSValue::encode(callPromiseFunction(*state, jsTestObjConstructorFunctionTestStaticPromiseFunctionPromise));
     7332    ASSERT(state);
     7333    return JSValue::encode(callPromiseFunction<jsTestObjConstructorFunctionTestStaticPromiseFunctionPromise, false>(*state));
    73277334}
    73287335
     
    73397346EncodedJSValue JSC_HOST_CALL jsTestObjConstructorFunctionTestStaticPromiseFunctionWithException(ExecState* state)
    73407347{
    7341     return JSValue::encode(callPromiseFunction(*state, jsTestObjConstructorFunctionTestStaticPromiseFunctionWithExceptionPromise));
     7348    ASSERT(state);
     7349    return JSValue::encode(callPromiseFunction<jsTestObjConstructorFunctionTestStaticPromiseFunctionWithExceptionPromise, false>(*state));
    73427350}
    73437351
  • trunk/Source/WebCore/bindings/scripts/test/TestNode.idl

    r202728 r205953  
    2222    Constructor,
    2323    ExportMacro=WEBCORE_TESTSUPPORT_EXPORT,
     24    Exposed=(Window,Worker)
    2425] interface TestNode : Node {
    2526    attribute DOMString name;
    2627
    2728    [EnabledAtRuntime=DOMIterator] iterable<TestNode>;
     29    Promise testWorkerPromise();
    2830};
    29 
Note: See TracChangeset for help on using the changeset viewer.