Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Side by Side Diff: third_party/WebKit/Source/modules/payments/PaymentRequest.cpp

Issue 1753543002: PaymentRequest Mojo bindings. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@interface
Patch Set: Update the links to the spec. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/payments/PaymentRequest.h" 5 #include "modules/payments/PaymentRequest.h"
6 6
7 #include "bindings/core/v8/ExceptionState.h" 7 #include "bindings/core/v8/ExceptionState.h"
8 #include "bindings/core/v8/JSONValuesForV8.h" 8 #include "bindings/core/v8/JSONValuesForV8.h"
9 #include "bindings/core/v8/ScriptPromiseResolver.h"
9 #include "bindings/core/v8/ScriptState.h" 10 #include "bindings/core/v8/ScriptState.h"
11 #include "core/EventTypeNames.h"
10 #include "core/dom/DOMException.h" 12 #include "core/dom/DOMException.h"
11 #include "core/dom/ExceptionCode.h" 13 #include "core/dom/ExceptionCode.h"
14 #include "core/events/Event.h"
15 #include "core/events/EventQueue.h"
12 #include "modules/EventTargetModulesNames.h" 16 #include "modules/EventTargetModulesNames.h"
17 #include "modules/payments/PaymentItem.h"
18 #include "modules/payments/PaymentResponse.h"
19 #include "modules/payments/PaymentsValidators.h"
13 #include "modules/payments/ShippingAddress.h" 20 #include "modules/payments/ShippingAddress.h"
21 #include "modules/payments/ShippingOption.h"
22 #include "mojo/public/cpp/bindings/interface_request.h"
23 #include "public/platform/Platform.h"
24 #include <utility>
14 25
15 namespace blink { 26 namespace blink {
27 namespace {
28
29 template <typename T>
30 bool areValidCurrencyAndAmounts(HeapVector<T> items, ExceptionState& exceptionSt ate)
31 {
32 String errorMessage;
33 for (const auto& item : items) {
34 if (item.hasAmount()) {
35 if (item.amount().hasCurrencyCode() && !isValidCurrencyCodeFormat(it em.amount().currencyCode(), &errorMessage)) {
36 exceptionState.throwTypeError(errorMessage);
37 return false;
38 }
39
40 if (item.amount().hasValue() && !isValidAmountFormat(item.amount().v alue(), &errorMessage)) {
41 exceptionState.throwTypeError(errorMessage);
42 return false;
43 }
44 }
45 }
46
47 return true;
48 }
49
50 template <typename Output, typename Input>
51 void toMojoItem(const Input& input, Output& output)
52 {
53 output->id = input.id();
54 output->label = input.label();
55 output->amount = mojom::blink::CurrencyAmount::New();
56 if (input.hasAmount()) {
57 output->amount->currency_code = input.amount().currencyCode();
58 output->amount->value = input.amount().value();
59 }
60 }
61
62 mojom::blink::PaymentDetailsPtr toMojoPaymentDetails(const PaymentDetails& input )
63 {
64 mojom::blink::PaymentDetailsPtr output = mojom::blink::PaymentDetails::New() ;
65 output->items = mojo::WTFArray<mojom::blink::PaymentItemPtr>::New(input.hasI tems() ? input.items().size() : 0);
66 if (input.hasItems()) {
67 for (size_t i = 0; i < input.items().size(); ++i) {
68 output->items[i] = mojom::blink::PaymentItem::New();
69 toMojoItem(input.items()[i], output->items[i]);
70 }
71 }
72 output->shipping_options = mojo::WTFArray<mojom::blink::ShippingOptionPtr>:: New(input.hasShippingOptions() ? input.shippingOptions().size() : 0);
73 if (input.hasShippingOptions()) {
74 for (size_t i = 0; i < input.shippingOptions().size(); ++i) {
75 output->shipping_options[i] = mojom::blink::ShippingOption::New();
76 toMojoItem(input.shippingOptions()[i], output->shipping_options[i]);
77 }
78 }
79 return output;
80 }
81
82 mojom::blink::PaymentOptionsPtr toMojoPaymentOptions(const PaymentOptions& input )
83 {
84 mojom::blink::PaymentOptionsPtr output = mojom::blink::PaymentOptions::New() ;
85 output->request_shipping = input.requestShipping();
86 return output;
87 }
88
89 } // namespace
16 90
17 // static 91 // static
18 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio nState) 92 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio nState)
19 { 93 {
20 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt ions(), ScriptValue(), exceptionState); 94 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt ions(), ScriptValue(), exceptionState);
21 } 95 }
22 96
23 // static 97 // static
24 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, ExceptionState& exceptionState) 98 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, ExceptionState& exceptionState)
25 { 99 {
26 return new PaymentRequest(scriptState, supportedMethods, details, options, S criptValue(), exceptionState); 100 return new PaymentRequest(scriptState, supportedMethods, details, options, S criptValue(), exceptionState);
27 } 101 }
28 102
29 // static 103 // static
30 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, const ScriptValue& data, ExceptionState& exceptionState) 104 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, const ScriptValue& data, ExceptionState& exceptionState)
31 { 105 {
32 return new PaymentRequest(scriptState, supportedMethods, details, options, d ata, exceptionState); 106 return new PaymentRequest(scriptState, supportedMethods, details, options, d ata, exceptionState);
33 } 107 }
34 108
35 PaymentRequest::~PaymentRequest() 109 PaymentRequest::~PaymentRequest()
36 { 110 {
37 } 111 }
38 112
39 ScriptPromise PaymentRequest::show(ScriptState* scriptState) 113 ScriptPromise PaymentRequest::show(ScriptState* scriptState)
40 { 114 {
41 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::crea te(NotSupportedError, "Not implemented.")); 115 if (m_showResolver)
116 return m_showResolver->promise().rejectWithDOMException(scriptState, DOM Exception::create(InvalidStateError, "Already called show() once"));
117
118 ASSERT(!m_paymentProvider.is_bound());
119 blink::Platform::current()->connectToRemoteService(mojo::GetProxy(&m_payment Provider));
120 if (!m_paymentProvider)
121 return m_showResolver->promise().rejectWithDOMException(scriptState, DOM Exception::create(SyntaxError, "Not implemented on this platform"));
122
123 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind());
124 m_paymentProvider->Show(std::move(m_supportedMethods), toMojoPaymentDetails( m_details), toMojoPaymentOptions(m_options), m_stringifiedData.isNull() ? "" : m _stringifiedData);
125
126 m_showResolver = ScriptPromiseResolver::create(scriptState);
127 return m_showResolver->promise();
42 } 128 }
43 129
44 void PaymentRequest::abort() 130 void PaymentRequest::abort(ExceptionState& exceptionState)
45 { 131 {
132 if (!m_showResolver) {
133 exceptionState.throwDOMException(InvalidStateError, "Never called show() , so nothing to abort");
134 return;
135 }
136
137 m_paymentProvider->Abort();
46 } 138 }
47 139
48 const AtomicString& PaymentRequest::interfaceName() const 140 const AtomicString& PaymentRequest::interfaceName() const
49 { 141 {
50 return EventTargetNames::PaymentRequest; 142 return EventTargetNames::PaymentRequest;
51 } 143 }
52 144
53 ExecutionContext* PaymentRequest::getExecutionContext() const 145 ExecutionContext* PaymentRequest::getExecutionContext() const
54 { 146 {
55 return m_scriptState->getExecutionContext(); 147 return m_scriptState->getExecutionContext();
56 } 148 }
57 149
150 ScriptPromise PaymentRequest::complete(ScriptState* scriptState, bool success)
151 {
152 if (m_completeResolver)
153 return m_completeResolver->promise().rejectWithDOMException(scriptState, DOMException::create(InvalidStateError, "Already called complete() once"));
154
155 m_completeResolver = ScriptPromiseResolver::create(scriptState);
156 m_paymentProvider->Complete(success);
157
158 return m_completeResolver->promise();
159 }
160
58 DEFINE_TRACE(PaymentRequest) 161 DEFINE_TRACE(PaymentRequest)
59 { 162 {
60 visitor->trace(m_details); 163 visitor->trace(m_details);
61 visitor->trace(m_options); 164 visitor->trace(m_options);
62 visitor->trace(m_shippingAddress); 165 visitor->trace(m_shippingAddress);
166 visitor->trace(m_showResolver);
167 visitor->trace(m_completeResolver);
63 RefCountedGarbageCollectedEventTargetWithInlineData<PaymentRequest>::trace(v isitor); 168 RefCountedGarbageCollectedEventTargetWithInlineData<PaymentRequest>::trace(v isitor);
64 } 169 }
65 170
66 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c onst ScriptValue& data, ExceptionState& exceptionState) 171 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c onst ScriptValue& data, ExceptionState& exceptionState)
67 : m_scriptState(scriptState) 172 : m_scriptState(scriptState)
68 , m_supportedMethods(supportedMethods) 173 , m_supportedMethods(supportedMethods)
69 , m_details(details) 174 , m_details(details)
70 , m_options(options) 175 , m_options(options)
176 , m_clientBinding(this)
71 { 177 {
178 // TODO(rouslan): Also check for a top-level browsing context.
179 // https://github.com/w3c/browser-payment-api/issues/2
180 if (!scriptState->getExecutionContext()->isSecureContext()) {
181 exceptionState.throwSecurityError("Must be in a secure context");
182 return;
183 }
184
185 if (supportedMethods.isEmpty()) {
186 exceptionState.throwTypeError("Must specify at least one payment methods identifiers");
187 return;
188 }
189
190 if (!details.hasItems()) {
191 exceptionState.throwTypeError("Must specify items");
192 return;
193 }
194
195 if (details.items().isEmpty()) {
196 exceptionState.throwTypeError("Must specify at least one item");
197 return;
198 }
199
200 if (details.hasItems() && !areValidCurrencyAndAmounts(details.items(), excep tionState))
201 return;
202
203 if (details.hasShippingOptions() && !areValidCurrencyAndAmounts(details.ship pingOptions(), exceptionState))
204 return;
205
72 if (!data.isEmpty()) { 206 if (!data.isEmpty()) {
73 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value()); 207 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value());
74 if (value && value->getType() == JSONValue::TypeObject) 208 if (value && !value->isNull()) {
75 m_stringifiedData = JSONObject::cast(value)->toJSONString(); 209 if (value->getType() != JSONValue::TypeObject) {
210 exceptionState.throwTypeError("Payment method specific data shou ld be a JSON-serializable object");
211 return;
212 }
213
214 RefPtr<JSONObject> jsonData = JSONObject::cast(value);
215 for (const auto& paymentMethodSpecificKeyValue : *jsonData) {
216 if (!supportedMethods.contains(paymentMethodSpecificKeyValue.key )) {
217 exceptionState.throwTypeError("'" + paymentMethodSpecificKey Value.key + "' should match one of the payment method identifiers");
218 return;
219 }
220 if (!paymentMethodSpecificKeyValue.value || paymentMethodSpecifi cKeyValue.value->isNull() || paymentMethodSpecificKeyValue.value->getType() != J SONValue::TypeObject) {
221 exceptionState.throwTypeError("Data for '" + paymentMethodSp ecificKeyValue.key + "' should be a JSON-serializable object");
222 return;
223 }
224 }
225
226 m_stringifiedData = jsonData->toJSONString();
227 }
76 } 228 }
229
230 if (details.hasShippingOptions() && details.shippingOptions().size() == 1 && details.shippingOptions()[0].hasId())
231 m_shippingOption = details.shippingOptions()[0].id();
232 }
233
234 void PaymentRequest::OnShippingAddressChange(mojom::blink::ShippingAddressPtr ad dress)
235 {
236 ASSERT(m_showResolver);
237 ASSERT(!m_completeResolver);
238
239 // TODO(rouslan): Should the merchant website be notified of invalid shippin g address
240 // from the browser or the payment app?
241 String errorMessage;
242 if (!isValidRegionCodeFormat(address->region_code, &errorMessage)) {
243 m_showResolver->reject(DOMException::create(SyntaxError, errorMessage));
244 return;
245 }
246
247 if (!isValidLanguageCodeFormat(address->language_code, &errorMessage)) {
248 m_showResolver->reject(DOMException::create(SyntaxError, errorMessage));
249 return;
250 }
251
252 if (!isValidScriptCodeFormat(address->script_code, &errorMessage)) {
253 m_showResolver->reject(DOMException::create(SyntaxError, errorMessage));
254 return;
255 }
256
257 if (address->language_code.isEmpty() && !address->script_code.isEmpty()) {
258 m_showResolver->reject(DOMException::create(SyntaxError, "If language co de is empty, then script code should also be empty"));
259 return;
260 }
261
262 m_shippingAddress = new ShippingAddress(std::move(address));
263 RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::shippingaddr esschange);
264 event->setTarget(this);
265 getExecutionContext()->getEventQueue()->enqueueEvent(event);
266 }
267
268 void PaymentRequest::OnShippingOptionChange(const String& shippingOptionId)
269 {
270 ASSERT(m_showResolver);
271 ASSERT(!m_completeResolver);
272 m_shippingOption = shippingOptionId;
273 RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::shippingopti onchange);
274 event->setTarget(this);
275 getExecutionContext()->getEventQueue()->enqueueEvent(event);
276 }
277
278 void PaymentRequest::OnPaymentResponse(mojom::blink::PaymentResponsePtr response )
279 {
280 ASSERT(m_showResolver);
281 ASSERT(!m_completeResolver);
282 m_showResolver->resolve(new PaymentResponse(std::move(response), this));
283 }
284
285 void PaymentRequest::OnError()
286 {
287 if (m_completeResolver) {
288 m_completeResolver->reject(DOMException::create(SyntaxError, "Request ca ncelled"));
289 return;
290 }
291 ASSERT(m_showResolver);
292 m_showResolver->reject(DOMException::create(SyntaxError, "Request cancelled" ));
293 m_paymentProvider.reset();
294 }
295
296 void PaymentRequest::OnComplete()
297 {
298 ASSERT(m_completeResolver);
299 m_completeResolver->resolve();
300 m_paymentProvider.reset();
77 } 301 }
78 302
79 } // namespace blink 303 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698