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

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: Fix linking error 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 areValidItems(HeapVector<T> items, ExceptionState& exceptionState)
Marijn Kruisselbrink 2016/03/25 17:13:31 Maybe add a comment explaining why this is a templ
please use gerrit instead 2016/03/25 19:26:37 Done.
31 {
32 String errorMessage;
33 for (const auto& item : items) {
34 if (!item.hasId()) {
35 exceptionState.throwTypeError("Item id required");
36 return false;
37 }
38
39 if (!item.hasLabel()) {
40 exceptionState.throwTypeError("Item label required");
41 return false;
42 }
43
44 if (!item.hasAmount()) {
45 exceptionState.throwTypeError("Currency amount required");
46 return false;
47 }
48
49 if (!item.amount().hasCurrencyCode()) {
50 exceptionState.throwTypeError("Currency code required");
51 return false;
52 }
53
54 if (!item.amount().hasValue()) {
55 exceptionState.throwTypeError("Currency value required");
56 return false;
57 }
58
59 if (!isValidCurrencyCodeFormat(item.amount().currencyCode(), &errorMessa ge)) {
60 exceptionState.throwTypeError(errorMessage);
61 return false;
62 }
63
64 if (!isValidAmountFormat(item.amount().value(), &errorMessage)) {
65 exceptionState.throwTypeError(errorMessage);
66 return false;
67 }
68 }
69
70 return true;
71 }
72
73 template <typename Output, typename Input>
Marijn Kruisselbrink 2016/03/25 17:13:30 Same here, without already knowing the rest of the
please use gerrit instead 2016/03/25 19:26:37 Done.
74 void toMojoItem(const Input& input, Output& output)
75 {
76 output->id = input.id();
77 output->label = input.label();
78 output->amount = mojom::wtf::CurrencyAmount::New();
79 output->amount->currency_code = input.amount().currencyCode();
80 output->amount->value = input.amount().value();
81 }
82
83 mojom::wtf::PaymentDetailsPtr toMojoPaymentDetails(const PaymentDetails& input)
Marijn Kruisselbrink 2016/03/25 17:13:30 All these "toMojo*" methods should probably be spe
please use gerrit instead 2016/03/25 19:26:37 Done.
84 {
85 mojom::wtf::PaymentDetailsPtr output = mojom::wtf::PaymentDetails::New();
86 output->items = mojo::WTFArray<mojom::wtf::PaymentItemPtr>::New(input.items( ).size());
87 for (size_t i = 0; i < input.items().size(); ++i) {
88 output->items[i] = mojom::wtf::PaymentItem::New();
89 toMojoItem(input.items()[i], output->items[i]);
90 }
91
92 output->shipping_options = mojo::WTFArray<mojom::wtf::ShippingOptionPtr>::Ne w(input.hasShippingOptions() ? input.shippingOptions().size() : 0);
93 if (input.hasShippingOptions()) {
94 for (size_t i = 0; i < input.shippingOptions().size(); ++i) {
95 output->shipping_options[i] = mojom::wtf::ShippingOption::New();
96 toMojoItem(input.shippingOptions()[i], output->shipping_options[i]);
97 }
98 }
99 return output;
100 }
101
102 mojom::wtf::PaymentOptionsPtr toMojoPaymentOptions(const PaymentOptions& input)
103 {
104 mojom::wtf::PaymentOptionsPtr output = mojom::wtf::PaymentOptions::New();
105 output->request_shipping = input.requestShipping();
106 return output;
107 }
108
109 } // namespace
16 110
17 // static 111 // static
18 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio nState) 112 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio nState)
19 { 113 {
20 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt ions(), ScriptValue(), exceptionState); 114 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt ions(), ScriptValue(), exceptionState);
21 } 115 }
22 116
23 // static 117 // static
24 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, ExceptionState& exceptionState) 118 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, ExceptionState& exceptionState)
25 { 119 {
26 return new PaymentRequest(scriptState, supportedMethods, details, options, S criptValue(), exceptionState); 120 return new PaymentRequest(scriptState, supportedMethods, details, options, S criptValue(), exceptionState);
27 } 121 }
28 122
29 // static 123 // static
30 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, const ScriptValue& data, ExceptionState& exceptionState) 124 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, const ScriptValue& data, ExceptionState& exceptionState)
31 { 125 {
32 return new PaymentRequest(scriptState, supportedMethods, details, options, d ata, exceptionState); 126 return new PaymentRequest(scriptState, supportedMethods, details, options, d ata, exceptionState);
33 } 127 }
34 128
35 PaymentRequest::~PaymentRequest() 129 PaymentRequest::~PaymentRequest()
36 { 130 {
37 } 131 }
38 132
39 ScriptPromise PaymentRequest::show(ScriptState* scriptState) 133 ScriptPromise PaymentRequest::show(ScriptState* scriptState)
40 { 134 {
41 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::crea te(NotSupportedError, "Not implemented.")); 135 if (m_showResolver)
136 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Already called show() once"));
137
138 ASSERT(!m_paymentProvider.is_bound());
Marijn Kruisselbrink 2016/03/25 17:13:31 DCHECK?
please use gerrit instead 2016/03/25 19:26:37 Done.
139 blink::Platform::current()->connectToRemoteService(mojo::GetProxy(&m_payment Provider));
Marijn Kruisselbrink 2016/03/25 17:13:30 Maybe add a TODO to handle errors for the two mojo
please use gerrit instead 2016/03/25 19:26:37 Done.
140 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind());
141 m_paymentProvider->Show(std::move(m_supportedMethods), toMojoPaymentDetails( m_details), toMojoPaymentOptions(m_options), m_stringifiedData.isNull() ? "" : m _stringifiedData);
142
143 m_showResolver = ScriptPromiseResolver::create(scriptState);
144 return m_showResolver->promise();
42 } 145 }
43 146
44 void PaymentRequest::abort() 147 void PaymentRequest::abort(ExceptionState& exceptionState)
45 { 148 {
149 if (!m_showResolver) {
150 exceptionState.throwDOMException(InvalidStateError, "Never called show() , so nothing to abort");
151 return;
152 }
153
154 m_paymentProvider->Abort();
46 } 155 }
47 156
48 const AtomicString& PaymentRequest::interfaceName() const 157 const AtomicString& PaymentRequest::interfaceName() const
49 { 158 {
50 return EventTargetNames::PaymentRequest; 159 return EventTargetNames::PaymentRequest;
51 } 160 }
52 161
53 ExecutionContext* PaymentRequest::getExecutionContext() const 162 ExecutionContext* PaymentRequest::getExecutionContext() const
54 { 163 {
55 return m_scriptState->getExecutionContext(); 164 return m_scriptState->getExecutionContext();
56 } 165 }
57 166
167 ScriptPromise PaymentRequest::complete(ScriptState* scriptState, bool success)
168 {
169 if (m_completeResolver)
170 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Already called complete() once"));
171
172 m_completeResolver = ScriptPromiseResolver::create(scriptState);
173 m_paymentProvider->Complete(success);
174
175 return m_completeResolver->promise();
176 }
177
58 DEFINE_TRACE(PaymentRequest) 178 DEFINE_TRACE(PaymentRequest)
59 { 179 {
60 visitor->trace(m_details); 180 visitor->trace(m_details);
61 visitor->trace(m_options); 181 visitor->trace(m_options);
62 visitor->trace(m_shippingAddress); 182 visitor->trace(m_shippingAddress);
183 visitor->trace(m_showResolver);
184 visitor->trace(m_completeResolver);
63 RefCountedGarbageCollectedEventTargetWithInlineData<PaymentRequest>::trace(v isitor); 185 RefCountedGarbageCollectedEventTargetWithInlineData<PaymentRequest>::trace(v isitor);
64 } 186 }
65 187
66 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c onst ScriptValue& data, ExceptionState& exceptionState) 188 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) 189 : m_scriptState(scriptState)
68 , m_supportedMethods(supportedMethods) 190 , m_supportedMethods(supportedMethods)
69 , m_details(details) 191 , m_details(details)
70 , m_options(options) 192 , m_options(options)
193 , m_clientBinding(this)
71 { 194 {
195 // TODO(rouslan): Also check for a top-level browsing context.
196 // https://github.com/w3c/browser-payment-api/issues/2
197 if (!scriptState->getExecutionContext()->isSecureContext()) {
198 exceptionState.throwSecurityError("Must be in a secure context");
199 return;
200 }
201
202 if (supportedMethods.isEmpty()) {
203 exceptionState.throwTypeError("Must specify at least one payment methods identifiers");
Marijn Kruisselbrink 2016/03/25 17:13:30 "one payment methods identifiers" doesn't seem lik
please use gerrit instead 2016/03/25 19:26:37 Done.
204 return;
205 }
206
207 if (!details.hasItems()) {
208 exceptionState.throwTypeError("Must specify items");
209 return;
210 }
211
212 if (details.items().isEmpty()) {
213 exceptionState.throwTypeError("Must specify at least one item");
214 return;
215 }
216
217 if (!areValidItems(details.items(), exceptionState))
218 return;
219
220 if (details.hasShippingOptions() && !areValidItems(details.shippingOptions() , exceptionState))
221 return;
222
72 if (!data.isEmpty()) { 223 if (!data.isEmpty()) {
73 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value()); 224 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value());
74 if (value && value->getType() == JSONValue::TypeObject) 225 if (value && !value->isNull()) {
75 m_stringifiedData = JSONObject::cast(value)->toJSONString(); 226 if (value->getType() != JSONValue::TypeObject) {
227 exceptionState.throwTypeError("Payment method specific data shou ld be a JSON-serializable object");
228 return;
229 }
230
231 RefPtr<JSONObject> jsonData = JSONObject::cast(value);
232 for (const auto& paymentMethodSpecificKeyValue : *jsonData) {
233 if (!supportedMethods.contains(paymentMethodSpecificKeyValue.key )) {
234 exceptionState.throwTypeError("'" + paymentMethodSpecificKey Value.key + "' should match one of the payment method identifiers");
235 return;
236 }
237 if (!paymentMethodSpecificKeyValue.value || paymentMethodSpecifi cKeyValue.value->isNull() || paymentMethodSpecificKeyValue.value->getType() != J SONValue::TypeObject) {
238 exceptionState.throwTypeError("Data for '" + paymentMethodSp ecificKeyValue.key + "' should be a JSON-serializable object");
239 return;
240 }
241 }
242
243 m_stringifiedData = jsonData->toJSONString();
244 }
76 } 245 }
246
247 if (details.hasShippingOptions() && details.shippingOptions().size() == 1)
248 m_shippingOption = details.shippingOptions()[0].id();
249 }
250
251 void PaymentRequest::OnShippingAddressChange(mojom::wtf::ShippingAddressPtr addr ess)
252 {
253 ASSERT(m_showResolver);
254 ASSERT(!m_completeResolver);
255
256 // TODO(rouslan): Should the merchant website be notified of invalid shippin g address
257 // from the browser or the payment app?
258 String errorMessage;
259 if (!isValidRegionCodeFormat(address->region_code, &errorMessage)) {
260 m_showResolver->reject(DOMException::create(SyntaxError, errorMessage));
261 return;
262 }
263
264 if (!isValidLanguageCodeFormat(address->language_code, &errorMessage)) {
265 m_showResolver->reject(DOMException::create(SyntaxError, errorMessage));
266 return;
267 }
268
269 if (!isValidScriptCodeFormat(address->script_code, &errorMessage)) {
270 m_showResolver->reject(DOMException::create(SyntaxError, errorMessage));
271 return;
272 }
273
274 if (address->language_code.isEmpty() && !address->script_code.isEmpty()) {
275 m_showResolver->reject(DOMException::create(SyntaxError, "If language co de is empty, then script code should also be empty"));
276 return;
277 }
278
279 m_shippingAddress = new ShippingAddress(std::move(address));
280 RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::shippingaddr esschange);
281 event->setTarget(this);
282 getExecutionContext()->getEventQueue()->enqueueEvent(event);
283 }
284
285 void PaymentRequest::OnShippingOptionChange(const String& shippingOptionId)
286 {
287 ASSERT(m_showResolver);
288 ASSERT(!m_completeResolver);
289 m_shippingOption = shippingOptionId;
290 RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::shippingopti onchange);
291 event->setTarget(this);
292 getExecutionContext()->getEventQueue()->enqueueEvent(event);
293 }
294
295 void PaymentRequest::OnPaymentResponse(mojom::wtf::PaymentResponsePtr response)
296 {
297 ASSERT(m_showResolver);
298 ASSERT(!m_completeResolver);
299 m_showResolver->resolve(new PaymentResponse(std::move(response), this));
300 }
301
302 void PaymentRequest::OnError()
303 {
304 if (m_completeResolver) {
305 m_completeResolver->reject(DOMException::create(SyntaxError, "Request ca ncelled"));
306 return;
307 }
308 ASSERT(m_showResolver);
309 m_showResolver->reject(DOMException::create(SyntaxError, "Request cancelled" ));
310 m_paymentProvider.reset();
Marijn Kruisselbrink 2016/03/25 17:13:30 I wonder if wherever the connection to the payment
please use gerrit instead 2016/03/25 19:26:37 Done.
311 }
312
313 void PaymentRequest::OnComplete()
314 {
315 ASSERT(m_completeResolver);
316 m_completeResolver->resolve();
317 m_paymentProvider.reset();
77 } 318 }
78 319
79 } // namespace blink 320 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698