1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2003-2020 Apple Inc. All rights reserved.
* Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
* Copyright (C) 2009 Google, Inc. All rights reserved.
* Copyright (C) 2012 Ericsson AB. All rights reserved.
* Copyright (C) 2013 Michael Pruett <michael@68k.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "JSDOMCastThisValue.h"
#include "JSDOMExceptionHandling.h"
#include <JavaScriptCore/Error.h>
namespace WebCore {
template<typename JSClass>
class IDLAttribute {
public:
using Setter = bool(JSC::JSGlobalObject&, JSClass&, JSC::JSValue);
using SetterPassingPropertyName = bool(JSC::JSGlobalObject&, JSClass&, JSC::JSValue, JSC::PropertyName);
using StaticSetter = bool(JSC::JSGlobalObject&, JSC::JSValue);
using Getter = JSC::JSValue(JSC::JSGlobalObject&, JSClass&);
using GetterPassingPropertyName = JSC::JSValue(JSC::JSGlobalObject&, JSClass&, JSC::PropertyName);
using StaticGetter = JSC::JSValue(JSC::JSGlobalObject&);
template<Setter setter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw>
static bool set(JSC::JSGlobalObject& lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName attributeName)
{
auto throwScope = DECLARE_THROW_SCOPE(JSC::getVM(&lexicalGlobalObject));
auto* thisObject = castThisValue<JSClass>(lexicalGlobalObject, JSC::JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
if constexpr (shouldThrow == CastedThisErrorBehavior::Throw)
return JSC::throwVMDOMAttributeSetterTypeError(&lexicalGlobalObject, throwScope, JSClass::info(), attributeName);
else
return false;
}
RELEASE_AND_RETURN(throwScope, (setter(lexicalGlobalObject, *thisObject, JSC::JSValue::decode(encodedValue))));
}
// FIXME: FIXME: This can be merged with `set` if we replace the explicit setter function template parameter with a generic lambda.
template<SetterPassingPropertyName setter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw>
static bool setPassingPropertyName(JSC::JSGlobalObject& lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName attributeName)
{
auto throwScope = DECLARE_THROW_SCOPE(JSC::getVM(&lexicalGlobalObject));
auto* thisObject = castThisValue<JSClass>(lexicalGlobalObject, JSC::JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
if constexpr (shouldThrow == CastedThisErrorBehavior::Throw)
return JSC::throwVMDOMAttributeSetterTypeError(&lexicalGlobalObject, throwScope, JSClass::info(), attributeName);
else
return false;
}
RELEASE_AND_RETURN(throwScope, (setter(lexicalGlobalObject, *thisObject, JSC::JSValue::decode(encodedValue), attributeName)));
}
template<StaticSetter setter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw>
static bool setStatic(JSC::JSGlobalObject& lexicalGlobalObject, JSC::EncodedJSValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName)
{
return setter(lexicalGlobalObject, JSC::JSValue::decode(encodedValue));
}
template<Getter getter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw>
static JSC::EncodedJSValue get(JSC::JSGlobalObject& lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName attributeName)
{
auto throwScope = DECLARE_THROW_SCOPE(JSC::getVM(&lexicalGlobalObject));
if constexpr (shouldThrow == CastedThisErrorBehavior::Assert) {
ASSERT(castThisValue<JSClass>(lexicalGlobalObject, JSC::JSValue::decode(thisValue)));
auto* thisObject = JSC::jsCast<JSClass*>(JSC::JSValue::decode(thisValue));
RELEASE_AND_RETURN(throwScope, (JSC::JSValue::encode(getter(lexicalGlobalObject, *thisObject))));
} else {
auto* thisObject = castThisValue<JSClass>(lexicalGlobalObject, JSC::JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
if constexpr (shouldThrow == CastedThisErrorBehavior::Throw)
return JSC::throwVMDOMAttributeGetterTypeError(&lexicalGlobalObject, throwScope, JSClass::info(), attributeName);
else if constexpr (shouldThrow == CastedThisErrorBehavior::RejectPromise)
RELEASE_AND_RETURN(throwScope, rejectPromiseWithGetterTypeError(lexicalGlobalObject, JSClass::info(), attributeName));
else
return JSC::JSValue::encode(JSC::jsUndefined());
}
RELEASE_AND_RETURN(throwScope, (JSC::JSValue::encode(getter(lexicalGlobalObject, *thisObject))));
}
}
// FIXME: This can be merged with `get` if we replace the explicit setter function template parameter with a generic lambda.
template<GetterPassingPropertyName getter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw>
static JSC::EncodedJSValue getPassingPropertyName(JSC::JSGlobalObject& lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName attributeName)
{
auto throwScope = DECLARE_THROW_SCOPE(JSC::getVM(&lexicalGlobalObject));
if constexpr (shouldThrow == CastedThisErrorBehavior::Assert) {
ASSERT(castThisValue<JSClass>(lexicalGlobalObject, JSC::JSValue::decode(thisValue)));
auto* thisObject = JSC::jsCast<JSClass*>(JSC::JSValue::decode(thisValue));
RELEASE_AND_RETURN(throwScope, (JSC::JSValue::encode(getter(lexicalGlobalObject, *thisObject, attributeName))));
} else {
auto* thisObject = castThisValue<JSClass>(lexicalGlobalObject, JSC::JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
if constexpr (shouldThrow == CastedThisErrorBehavior::Throw)
return JSC::throwVMDOMAttributeGetterTypeError(&lexicalGlobalObject, throwScope, JSClass::info(), attributeName);
else if constexpr (shouldThrow == CastedThisErrorBehavior::RejectPromise)
RELEASE_AND_RETURN(throwScope, rejectPromiseWithGetterTypeError(lexicalGlobalObject, JSClass::info(), attributeName));
else
return JSC::JSValue::encode(JSC::jsUndefined());
}
RELEASE_AND_RETURN(throwScope, (JSC::JSValue::encode(getter(lexicalGlobalObject, *thisObject, attributeName))));
}
}
template<StaticGetter getter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw>
static JSC::EncodedJSValue getStatic(JSC::JSGlobalObject& lexicalGlobalObject, JSC::EncodedJSValue, JSC::PropertyName)
{
return JSC::JSValue::encode(getter(lexicalGlobalObject));
}
};
} // namespace WebCore
|