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
|
/*
* 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"
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
|