1/*
2 * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebInjectedScriptHost.h"
28
29#include "DOMException.h"
30#include "JSDOMException.h"
31#include "JSHTMLAllCollection.h"
32#include "JSHTMLCollection.h"
33#include "JSNode.h"
34#include "JSNodeList.h"
35
36#if ENABLE(PAYMENT_REQUEST)
37#include "JSPaymentRequest.h"
38#include "JSPaymentShippingType.h"
39#include "PaymentOptions.h"
40#include "PaymentRequest.h"
41#endif
42
43namespace WebCore {
44
45using namespace JSC;
46
47JSValue WebInjectedScriptHost::subtype(ExecState* exec, JSValue value)
48{
49 VM& vm = exec->vm();
50 if (value.inherits<JSNode>(vm))
51 return jsNontrivialString(exec, "node"_s);
52 if (value.inherits<JSNodeList>(vm))
53 return jsNontrivialString(exec, "array"_s);
54 if (value.inherits<JSHTMLCollection>(vm))
55 return jsNontrivialString(exec, "array"_s);
56 if (value.inherits<JSDOMException>(vm))
57 return jsNontrivialString(exec, "error"_s);
58
59 return jsUndefined();
60}
61
62#if ENABLE(PAYMENT_REQUEST)
63static JSObject* constructInternalProperty(VM& vm, ExecState* exec, const String& name, JSValue value)
64{
65 auto* object = constructEmptyObject(exec);
66 object->putDirect(vm, Identifier::fromString(exec, "name"), jsString(exec, name));
67 object->putDirect(vm, Identifier::fromString(exec, "value"), value);
68 return object;
69}
70
71static JSObject* objectForPaymentOptions(VM& vm, ExecState* exec, const PaymentOptions& paymentOptions)
72{
73 auto* object = constructEmptyObject(exec);
74 object->putDirect(vm, Identifier::fromString(exec, "requestPayerName"), jsBoolean(paymentOptions.requestPayerName));
75 object->putDirect(vm, Identifier::fromString(exec, "requestPayerEmail"), jsBoolean(paymentOptions.requestPayerEmail));
76 object->putDirect(vm, Identifier::fromString(exec, "requestPayerPhone"), jsBoolean(paymentOptions.requestPayerPhone));
77 object->putDirect(vm, Identifier::fromString(exec, "requestShipping"), jsBoolean(paymentOptions.requestShipping));
78 object->putDirect(vm, Identifier::fromString(exec, "shippingType"), jsNontrivialString(exec, convertEnumerationToString(paymentOptions.shippingType)));
79 return object;
80}
81
82static JSObject* objectForPaymentCurrencyAmount(VM& vm, ExecState* exec, const PaymentCurrencyAmount& paymentCurrencyAmount)
83{
84 auto* object = constructEmptyObject(exec);
85 object->putDirect(vm, Identifier::fromString(exec, "currency"), jsString(exec, paymentCurrencyAmount.currency));
86 object->putDirect(vm, Identifier::fromString(exec, "value"), jsString(exec, paymentCurrencyAmount.value));
87 return object;
88}
89
90static JSObject* objectForPaymentItem(VM& vm, ExecState* exec, const PaymentItem& paymentItem)
91{
92 auto* object = constructEmptyObject(exec);
93 object->putDirect(vm, Identifier::fromString(exec, "label"), jsString(exec, paymentItem.label));
94 object->putDirect(vm, Identifier::fromString(exec, "amount"), objectForPaymentCurrencyAmount(vm, exec, paymentItem.amount));
95 object->putDirect(vm, Identifier::fromString(exec, "pending"), jsBoolean(paymentItem.pending));
96 return object;
97}
98
99static JSObject* objectForPaymentShippingOption(VM& vm, ExecState* exec, const PaymentShippingOption& paymentShippingOption)
100{
101 auto* object = constructEmptyObject(exec);
102 object->putDirect(vm, Identifier::fromString(exec, "id"), jsString(exec, paymentShippingOption.id));
103 object->putDirect(vm, Identifier::fromString(exec, "label"), jsString(exec, paymentShippingOption.label));
104 object->putDirect(vm, Identifier::fromString(exec, "amount"), objectForPaymentCurrencyAmount(vm, exec, paymentShippingOption.amount));
105 object->putDirect(vm, Identifier::fromString(exec, "selected"), jsBoolean(paymentShippingOption.selected));
106 return object;
107}
108
109static JSObject* objectForPaymentDetailsModifier(VM& vm, ExecState* exec, const PaymentDetailsModifier& modifier)
110{
111 auto* additionalDisplayItems = constructEmptyArray(exec, nullptr);
112 for (unsigned i = 0; i < modifier.additionalDisplayItems.size(); ++i)
113 additionalDisplayItems->putDirectIndex(exec, i, objectForPaymentItem(vm, exec, modifier.additionalDisplayItems[i]));
114
115 auto* object = constructEmptyObject(exec);
116 object->putDirect(vm, Identifier::fromString(exec, "supportedMethods"), jsString(exec, modifier.supportedMethods));
117 object->putDirect(vm, Identifier::fromString(exec, "total"), !modifier.total ? jsNull() : objectForPaymentItem(vm, exec, *modifier.total));
118 object->putDirect(vm, Identifier::fromString(exec, "additionalDisplayItems"), additionalDisplayItems);
119 object->putDirect(vm, Identifier::fromString(exec, "data"), !modifier.data ? jsNull() : modifier.data.get());
120 return object;
121}
122
123static JSObject* objectForPaymentDetails(VM& vm, ExecState* exec, const PaymentDetailsInit& paymentDetails)
124{
125 auto* displayItems = constructEmptyArray(exec, nullptr);
126 for (unsigned i = 0; i < paymentDetails.displayItems.size(); ++i)
127 displayItems->putDirectIndex(exec, i, objectForPaymentItem(vm, exec, paymentDetails.displayItems[i]));
128
129 auto* shippingOptions = constructEmptyArray(exec, nullptr);
130 for (unsigned i = 0; i < paymentDetails.shippingOptions.size(); ++i)
131 shippingOptions->putDirectIndex(exec, i, objectForPaymentShippingOption(vm, exec, paymentDetails.shippingOptions[i]));
132
133 auto* modifiers = constructEmptyArray(exec, nullptr);
134 for (unsigned i = 0; i < paymentDetails.modifiers.size(); ++i)
135 modifiers->putDirectIndex(exec, i, objectForPaymentDetailsModifier(vm, exec, paymentDetails.modifiers[i]));
136
137 auto* object = constructEmptyObject(exec);
138 object->putDirect(vm, Identifier::fromString(exec, "id"), jsString(exec, paymentDetails.id));
139 object->putDirect(vm, Identifier::fromString(exec, "total"), objectForPaymentItem(vm, exec, paymentDetails.total));
140 object->putDirect(vm, Identifier::fromString(exec, "displayItems"), displayItems);
141 object->putDirect(vm, Identifier::fromString(exec, "shippingOptions"), shippingOptions);
142 object->putDirect(vm, Identifier::fromString(exec, "modifiers"), modifiers);
143 return object;
144}
145
146static JSString* jsStringForPaymentRequestState(VM& vm, ExecState* exec, PaymentRequest::State state)
147{
148 switch (state) {
149 case PaymentRequest::State::Created:
150 return jsNontrivialString(exec, "created"_s);
151 case PaymentRequest::State::Interactive:
152 return jsNontrivialString(exec, "interactive"_s);
153 case PaymentRequest::State::Closed:
154 return jsNontrivialString(exec, "closed"_s);
155 }
156
157 ASSERT_NOT_REACHED();
158 return jsEmptyString(&vm);
159}
160#endif
161
162JSValue WebInjectedScriptHost::getInternalProperties(VM& vm, ExecState* exec, JSC::JSValue value)
163{
164#if ENABLE(PAYMENT_REQUEST)
165 auto scope = DECLARE_THROW_SCOPE(vm);
166
167 if (PaymentRequest* paymentRequest = JSPaymentRequest::toWrapped(vm, value)) {
168 unsigned index = 0;
169 auto* array = constructEmptyArray(exec, nullptr);
170 array->putDirectIndex(exec, index++, constructInternalProperty(vm, exec, "options"_s, objectForPaymentOptions(vm, exec, paymentRequest->paymentOptions())));
171 array->putDirectIndex(exec, index++, constructInternalProperty(vm, exec, "details"_s, objectForPaymentDetails(vm, exec, paymentRequest->paymentDetails())));
172 array->putDirectIndex(exec, index++, constructInternalProperty(vm, exec, "state"_s, jsStringForPaymentRequestState(vm, exec, paymentRequest->state())));
173 RETURN_IF_EXCEPTION(scope, { });
174 return array;
175 }
176#else
177 UNUSED_PARAM(vm);
178 UNUSED_PARAM(exec);
179 UNUSED_PARAM(value);
180#endif
181
182 return { };
183}
184
185bool WebInjectedScriptHost::isHTMLAllCollection(JSC::VM& vm, JSC::JSValue value)
186{
187 return value.inherits<JSHTMLAllCollection>(vm);
188}
189
190} // namespace WebCore
191