Changeset 271703 in webkit
- Timestamp:
- Jan 21, 2021 11:37:52 AM (18 months ago)
- Location:
- trunk
- Files:
-
- 8 added
- 7 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/http/tests/inspector/paymentrequest/payment-request-internal-properties.https-expected.txt (modified) (3 diffs)
-
LayoutTests/http/tests/paymentrequest/updateWith-displayItems.https-expected.txt (added)
-
LayoutTests/http/tests/paymentrequest/updateWith-displayItems.https.html (added)
-
LayoutTests/http/tests/paymentrequest/updateWith-modifiers.https-expected.txt (added)
-
LayoutTests/http/tests/paymentrequest/updateWith-modifiers.https.html (added)
-
LayoutTests/http/tests/paymentrequest/updateWith-shippingOptions.https-expected.txt (added)
-
LayoutTests/http/tests/paymentrequest/updateWith-shippingOptions.https.html (added)
-
LayoutTests/http/tests/paymentrequest/updateWith-total.https-expected.txt (added)
-
LayoutTests/http/tests/paymentrequest/updateWith-total.https.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp (modified) (4 diffs)
-
Source/WebCore/Modules/paymentrequest/PaymentDetailsBase.h (modified) (1 diff)
-
Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp (modified) (4 diffs)
-
Source/WebCore/inspector/WebInjectedScriptHost.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r271702 r271703 1 2021-01-21 Devin Rousso <drousso@apple.com> 2 3 Payment Request API - response.shippingOption is always null 4 https://bugs.webkit.org/show_bug.cgi?id=220566 5 <rdar://problem/73204387> 6 7 Reviewed by Andy Estes. 8 9 * http/tests/inspector/paymentrequest/payment-request-internal-properties.https-expected.txt: 10 * http/tests/paymentrequest/updateWith-displayItems.https.html: Added. 11 * http/tests/paymentrequest/updateWith-displayItems.https-expected.txt: Added. 12 * http/tests/paymentrequest/updateWith-modifiers.https.html: Added. 13 * http/tests/paymentrequest/updateWith-modifiers.https-expected.txt: Added. 14 * http/tests/paymentrequest/updateWith-shippingOptions.https.html: Added. 15 * http/tests/paymentrequest/updateWith-shippingOptions.https-expected.txt: Added. 16 * http/tests/paymentrequest/updateWith-total.https.html: Added. 17 * http/tests/paymentrequest/updateWith-total.https-expected.txt: Added. 18 1 19 2021-01-21 Rini Patel <rini_patel@apple.com> 2 20 -
trunk/LayoutTests/http/tests/inspector/paymentrequest/payment-request-internal-properties.https-expected.txt
r232155 r271703 97 97 "pending": false 98 98 }, 99 "displayItems": [],100 "shippingOptions": [],101 99 "modifiers": [] 102 100 } … … 121 119 "pending": false 122 120 }, 123 "displayItems": [],124 "shippingOptions": [],125 121 "modifiers": [] 126 122 } … … 145 141 "pending": false 146 142 }, 147 "displayItems": [],148 "shippingOptions": [],149 143 "modifiers": [] 150 144 } -
trunk/Source/WebCore/ChangeLog
r271701 r271703 1 2021-01-21 Devin Rousso <drousso@apple.com> 2 3 Payment Request API - response.shippingOption is always null 4 https://bugs.webkit.org/show_bug.cgi?id=220566 5 <rdar://problem/73204387> 6 7 Reviewed by Andy Estes. 8 9 The Payment Request API spec indicates that when updating a `PaymentRequest`'s details [1] 10 we should be checking for the existence of `displayItems`, `shippingOptions` (but only if 11 `requestShipping` was specified), and `modifiers` before overriding any corresponding data 12 on the `PaymentRequest` itself. This means that calls to `updateWith` only need to provide 13 the data that needs to be changed (e.g. the `total`) rather than data for the whole payment. 14 15 [1]: https://www.w3.org/TR/payment-request/#dfn-update-a-paymentrequest-s-details-algorithm 16 17 Tests: http/tests/inspector/paymentrequest/payment-request-internal-properties.https.html 18 http/tests/paymentrequest/updateWith-displayItems.https.html 19 http/tests/paymentrequest/updateWith-modifiers.https.html 20 http/tests/paymentrequest/updateWith-shippingOptions.https.html 21 http/tests/paymentrequest/updateWith-total.https.html 22 23 * Modules/paymentrequest/PaymentDetailsBase.h: 24 Make every member `Optional` so we can distinguish between "provided an empty array" and 25 "did not provide the property at all". 26 27 * Modules/paymentrequest/PaymentRequest.cpp: 28 (WebCore::checkAndCanonicalizeDetails): 29 (WebCore::PaymentRequest::create): 30 (WebCore::PaymentRequest::settleDetailsPromise): 31 * Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp: 32 (WebCore::ApplePayPaymentHandler::show): 33 (WebCore::ApplePayPaymentHandler::computeShippingMethods): 34 (WebCore::ApplePayPaymentHandler::computeTotalAndLineItems const): 35 (WebCore::ApplePayPaymentHandler::computeErrors const): 36 Add checks before accessing `displayItems`, `shippingOptions`, and `modifiers`. 37 Match the described behavior of the spec where `shippingOptions` (but only if 38 `requestShipping` was specified) and `modifiers` are set to an empty array if not provided 39 when constructing the `PaymentRequest`. 40 41 * inspector/WebInjectedScriptHost.cpp: 42 (WebCore::objectForPaymentDetails): 43 Don't create internal properties for `displayItems`, `shippingOptions`, and `modifiers` 44 unless they are actually provided for the same reason as above. 45 1 46 2021-01-21 Simon Fraser <simon.fraser@apple.com> 2 47 -
trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp
r268700 r271703 219 219 request.setRequester(ApplePaySessionPaymentRequest::Requester::PaymentRequest); 220 220 221 String expectedCurrency = m_paymentRequest->paymentDetails().total.amount.currency; 221 auto& details = m_paymentRequest->paymentDetails(); 222 223 String expectedCurrency = details.total.amount.currency; 222 224 request.setCurrencyCode(expectedCurrency); 223 225 224 auto total = convertAndValidate( m_paymentRequest->paymentDetails().total, expectedCurrency);226 auto total = convertAndValidate(details.total, expectedCurrency); 225 227 ASSERT(!total.hasException()); 226 228 request.setTotal(total.releaseReturnValue()); 227 229 228 auto convertedLineItems = convertAndValidate(m_paymentRequest->paymentDetails().displayItems, expectedCurrency); 229 if (convertedLineItems.hasException()) 230 return convertedLineItems.releaseException(); 231 request.setLineItems(convertedLineItems.releaseReturnValue()); 230 if (details.displayItems) { 231 auto convertedLineItems = convertAndValidate(*details.displayItems, expectedCurrency); 232 if (convertedLineItems.hasException()) 233 return convertedLineItems.releaseException(); 234 request.setLineItems(convertedLineItems.releaseReturnValue()); 235 } 232 236 233 237 mergePaymentOptions(m_paymentRequest->paymentOptions(), request); … … 261 265 { 262 266 auto& details = m_paymentRequest->paymentDetails(); 263 auto& currency = details.total.amount.currency; 264 auto& shippingOptions = details.shippingOptions; 265 266 Vector<ApplePaySessionPaymentRequest::ShippingMethod> shippingMethods; 267 shippingMethods.reserveInitialCapacity(shippingOptions.size()); 268 269 for (auto& shippingOption : shippingOptions) { 270 auto shippingMethod = convertAndValidate(shippingOption, currency); 271 if (shippingMethod.hasException()) 272 return shippingMethod.releaseException(); 273 shippingMethods.uncheckedAppend(shippingMethod.releaseReturnValue()); 274 } 275 276 return WTFMove(shippingMethods); 267 268 Vector<ApplePaySessionPaymentRequest::ShippingMethod> shippingOptions; 269 if (details.shippingOptions) { 270 auto& currency = details.total.amount.currency; 271 272 shippingOptions.reserveInitialCapacity(details.shippingOptions->size()); 273 for (auto& shippingOption : *details.shippingOptions) { 274 auto shippingMethod = convertAndValidate(shippingOption, currency); 275 if (shippingMethod.hasException()) 276 return shippingMethod.releaseException(); 277 shippingOptions.uncheckedAppend(shippingMethod.releaseReturnValue()); 278 } 279 } 280 281 return WTFMove(shippingOptions); 277 282 } 278 283 … … 287 292 auto total = convertedTotal.releaseReturnValue(); 288 293 289 auto convertedLineItems = convertAndValidate(details.displayItems, currency); 290 if (convertedLineItems.hasException()) 291 return convertedLineItems.releaseException(); 292 auto lineItems = convertedLineItems.releaseReturnValue(); 294 Vector<ApplePaySessionPaymentRequest::LineItem> lineItems; 295 if (details.displayItems) { 296 auto convertedLineItems = convertAndValidate(*details.displayItems, currency); 297 if (convertedLineItems.hasException()) 298 return convertedLineItems.releaseException(); 299 lineItems = convertedLineItems.releaseReturnValue(); 300 } 293 301 294 302 if (!m_selectedPaymentMethodType) 295 303 return ApplePaySessionPaymentRequest::TotalAndLineItems { WTFMove(total), WTFMove(lineItems) }; 296 304 297 auto& modifiers = details.modifiers; 298 auto& serializedModifierData = m_paymentRequest->serializedModifierData(); 299 ASSERT(modifiers.size() == serializedModifierData.size()); 300 for (size_t i = 0; i < modifiers.size(); ++i) { 301 auto convertedIdentifier = convertAndValidatePaymentMethodIdentifier(modifiers[i].supportedMethods); 302 if (!convertedIdentifier || !handlesIdentifier(*convertedIdentifier)) 303 continue; 304 305 if (serializedModifierData[i].isEmpty()) 306 continue; 307 308 auto& lexicalGlobalObject = *document().globalObject(); 309 auto scope = DECLARE_THROW_SCOPE(lexicalGlobalObject.vm()); 310 JSC::JSValue data; 311 { 312 auto lock = JSC::JSLockHolder { &lexicalGlobalObject }; 313 data = JSONParse(&lexicalGlobalObject, serializedModifierData[i]); 305 if (details.modifiers) { 306 auto& serializedModifierData = m_paymentRequest->serializedModifierData(); 307 ASSERT(details.modifiers->size() == serializedModifierData.size()); 308 for (size_t i = 0; i < details.modifiers->size(); ++i) { 309 auto& modifier = details.modifiers->at(i); 310 311 auto convertedIdentifier = convertAndValidatePaymentMethodIdentifier(modifier.supportedMethods); 312 if (!convertedIdentifier || !handlesIdentifier(*convertedIdentifier)) 313 continue; 314 315 if (serializedModifierData[i].isEmpty()) 316 continue; 317 318 auto& lexicalGlobalObject = *document().globalObject(); 319 auto scope = DECLARE_THROW_SCOPE(lexicalGlobalObject.vm()); 320 JSC::JSValue data; 321 { 322 auto lock = JSC::JSLockHolder { &lexicalGlobalObject }; 323 data = JSONParse(&lexicalGlobalObject, serializedModifierData[i]); 324 if (scope.exception()) 325 return Exception { ExistingExceptionError }; 326 } 327 328 auto applePayModifier = convertDictionary<ApplePayModifier>(lexicalGlobalObject, WTFMove(data)); 314 329 if (scope.exception()) 315 330 return Exception { ExistingExceptionError }; 331 332 if (applePayModifier.paymentMethodType != *m_selectedPaymentMethodType) 333 continue; 334 335 if (modifier.total) { 336 auto totalOverride = convertAndValidate(*modifier.total, currency); 337 if (totalOverride.hasException()) 338 return totalOverride.releaseException(); 339 total = totalOverride.releaseReturnValue(); 340 } 341 342 auto additionalDisplayItems = convertAndValidate(modifier.additionalDisplayItems, currency); 343 if (additionalDisplayItems.hasException()) 344 return additionalDisplayItems.releaseException(); 345 lineItems.appendVector(additionalDisplayItems.releaseReturnValue()); 346 break; 316 347 } 317 318 auto applePayModifier = convertDictionary<ApplePayModifier>(lexicalGlobalObject, WTFMove(data));319 if (scope.exception())320 return Exception { ExistingExceptionError };321 322 if (applePayModifier.paymentMethodType != *m_selectedPaymentMethodType)323 continue;324 325 if (modifiers[i].total) {326 auto totalOverride = convertAndValidate(*modifiers[i].total, currency);327 if (totalOverride.hasException())328 return totalOverride.releaseException();329 total = totalOverride.releaseReturnValue();330 }331 332 auto additionalDisplayItems = convertAndValidate(modifiers[i].additionalDisplayItems, currency);333 if (additionalDisplayItems.hasException())334 return additionalDisplayItems.releaseException();335 lineItems.appendVector(additionalDisplayItems.releaseReturnValue());336 break;337 348 } 338 349 … … 350 361 Vector<PaymentError> errors; 351 362 352 if (m_paymentRequest->paymentDetails().shippingOptions.isEmpty()) 363 auto& details = m_paymentRequest->paymentDetails(); 364 365 if (!details.shippingOptions || details.shippingOptions->isEmpty()) 353 366 computeAddressErrors(WTFMove(error), WTFMove(addressErrors), errors); 354 367 -
trunk/Source/WebCore/Modules/paymentrequest/PaymentDetailsBase.h
r220955 r271703 36 36 37 37 struct PaymentDetailsBase { 38 Vector<PaymentItem> displayItems;39 Vector<PaymentShippingOption> shippingOptions;40 Vector<PaymentDetailsModifier> modifiers;38 Optional<Vector<PaymentItem>> displayItems; 39 Optional<Vector<PaymentShippingOption>> shippingOptions; 40 Optional<Vector<PaymentDetailsModifier>> modifiers; 41 41 }; 42 42 -
trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp
r271615 r271703 241 241 } 242 242 243 enum class ShouldValidatePaymentMethodIdentifier{243 enum class IsUpdate { 244 244 No, 245 245 Yes, 246 246 }; 247 247 248 static ExceptionOr<std::tuple<String, Vector<String>>> checkAndCanonicalizeDetails(JSC::JSGlobalObject& execState, PaymentDetailsBase& details, bool requestShipping, ShouldValidatePaymentMethodIdentifier shouldValidatePaymentMethodIdentifier) 249 { 250 for (auto& item : details.displayItems) { 251 auto exception = checkAndCanonicalizeAmount(item.amount); 252 if (exception.hasException()) 253 return exception.releaseException(); 254 } 255 256 String selectedShippingOption; 257 if (requestShipping) { 258 HashSet<String> seenShippingOptionIDs; 259 for (auto& shippingOption : details.shippingOptions) { 260 auto exception = checkAndCanonicalizeAmount(shippingOption.amount); 261 if (exception.hasException()) 262 return exception.releaseException(); 263 264 auto addResult = seenShippingOptionIDs.add(shippingOption.id); 265 if (!addResult.isNewEntry) 266 return Exception { TypeError, "Shipping option IDs must be unique." }; 267 268 if (shippingOption.selected) 269 selectedShippingOption = shippingOption.id; 270 } 271 } 272 273 Vector<String> serializedModifierData; 274 serializedModifierData.reserveInitialCapacity(details.modifiers.size()); 275 for (auto& modifier : details.modifiers) { 276 if (shouldValidatePaymentMethodIdentifier == ShouldValidatePaymentMethodIdentifier::Yes) { 277 auto paymentMethodIdentifier = convertAndValidatePaymentMethodIdentifier(modifier.supportedMethods); 278 if (!paymentMethodIdentifier) 279 return Exception { RangeError, makeString('"', modifier.supportedMethods, "\" is an invalid payment method identifier.") }; 280 } 281 282 if (modifier.total) { 283 auto exception = checkAndCanonicalizeTotal(modifier.total->amount); 284 if (exception.hasException()) 285 return exception.releaseException(); 286 } 287 288 for (auto& item : modifier.additionalDisplayItems) { 248 static ExceptionOr<std::tuple<String, Vector<String>>> checkAndCanonicalizeDetails(JSC::JSGlobalObject& execState, PaymentDetailsBase& details, bool requestShipping, IsUpdate isUpdate) 249 { 250 if (details.displayItems) { 251 for (auto& item : *details.displayItems) { 289 252 auto exception = checkAndCanonicalizeAmount(item.amount); 290 253 if (exception.hasException()) 291 254 return exception.releaseException(); 292 255 } 293 294 String serializedData; 295 if (modifier.data) { 296 auto scope = DECLARE_THROW_SCOPE(execState.vm()); 297 serializedData = JSONStringify(&execState, modifier.data.get(), 0); 298 if (scope.exception()) 299 return Exception { ExistingExceptionError }; 300 modifier.data.clear(); 301 } 302 serializedModifierData.uncheckedAppend(WTFMove(serializedData)); 303 } 256 } 257 258 String selectedShippingOption; 259 if (requestShipping) { 260 if (details.shippingOptions) { 261 HashSet<String> seenShippingOptionIDs; 262 for (auto& shippingOption : *details.shippingOptions) { 263 auto exception = checkAndCanonicalizeAmount(shippingOption.amount); 264 if (exception.hasException()) 265 return exception.releaseException(); 266 267 auto addResult = seenShippingOptionIDs.add(shippingOption.id); 268 if (!addResult.isNewEntry) 269 return Exception { TypeError, "Shipping option IDs must be unique." }; 270 271 if (shippingOption.selected) 272 selectedShippingOption = shippingOption.id; 273 } 274 } else if (isUpdate == IsUpdate::No) 275 details.shippingOptions = { { } }; 276 } 277 278 Vector<String> serializedModifierData; 279 if (details.modifiers) { 280 serializedModifierData.reserveInitialCapacity(details.modifiers->size()); 281 for (auto& modifier : *details.modifiers) { 282 if (isUpdate == IsUpdate::Yes) { 283 auto paymentMethodIdentifier = convertAndValidatePaymentMethodIdentifier(modifier.supportedMethods); 284 if (!paymentMethodIdentifier) 285 return Exception { RangeError, makeString('"', modifier.supportedMethods, "\" is an invalid payment method identifier.") }; 286 } 287 288 if (modifier.total) { 289 auto exception = checkAndCanonicalizeTotal(modifier.total->amount); 290 if (exception.hasException()) 291 return exception.releaseException(); 292 } 293 294 for (auto& item : modifier.additionalDisplayItems) { 295 auto exception = checkAndCanonicalizeAmount(item.amount); 296 if (exception.hasException()) 297 return exception.releaseException(); 298 } 299 300 String serializedData; 301 if (modifier.data) { 302 auto scope = DECLARE_THROW_SCOPE(execState.vm()); 303 serializedData = JSONStringify(&execState, modifier.data.get(), 0); 304 if (scope.exception()) 305 return Exception { ExistingExceptionError }; 306 modifier.data.clear(); 307 } 308 serializedModifierData.uncheckedAppend(WTFMove(serializedData)); 309 } 310 } else if (isUpdate == IsUpdate::No) 311 details.modifiers = { { } }; 304 312 305 313 return std::make_tuple(WTFMove(selectedShippingOption), WTFMove(serializedModifierData)); … … 358 366 return totalResult.releaseException(); 359 367 360 auto detailsResult = checkAndCanonicalizeDetails(*document.globalObject(), details, options.requestShipping, ShouldValidatePaymentMethodIdentifier::No);368 auto detailsResult = checkAndCanonicalizeDetails(*document.globalObject(), details, options.requestShipping, IsUpdate::No); 361 369 if (detailsResult.hasException()) 362 370 return detailsResult.releaseException(); … … 662 670 } 663 671 664 auto detailsResult = checkAndCanonicalizeDetails(*context.globalObject(), detailsUpdate, m_options.requestShipping, ShouldValidatePaymentMethodIdentifier::Yes);672 auto detailsResult = checkAndCanonicalizeDetails(*context.globalObject(), detailsUpdate, m_options.requestShipping, IsUpdate::Yes); 665 673 if (detailsResult.hasException()) { 666 674 abortWithException(detailsResult.releaseException()); … … 670 678 auto shippingOptionAndModifierData = detailsResult.releaseReturnValue(); 671 679 672 m_details.total = detailsUpdate.total ? WTFMove(*detailsUpdate.total) : PaymentItem(); 673 m_details.displayItems = WTFMove(detailsUpdate.displayItems); 674 if (m_options.requestShipping) { 680 if (detailsUpdate.total) 681 m_details.total = WTFMove(*detailsUpdate.total); 682 if (detailsUpdate.displayItems) 683 m_details.displayItems = WTFMove(*detailsUpdate.displayItems); 684 if (detailsUpdate.shippingOptions && m_options.requestShipping) { 675 685 m_details.shippingOptions = WTFMove(detailsUpdate.shippingOptions); 676 686 m_shippingOption = WTFMove(std::get<0>(shippingOptionAndModifierData)); 677 687 } 678 679 m_details.modifiers = WTFMove(detailsUpdate.modifiers); 680 m_serializedModifierData = WTFMove(std::get<1>(shippingOptionAndModifierData)); 688 if (detailsUpdate.modifiers) { 689 m_details.modifiers = WTFMove(*detailsUpdate.modifiers); 690 m_serializedModifierData = WTFMove(std::get<1>(shippingOptionAndModifierData)); 691 } 681 692 682 693 auto result = activePaymentHandler()->detailsUpdated(reason, WTFMove(detailsUpdate.error), WTFMove(detailsUpdate.shippingAddressErrors), WTFMove(detailsUpdate.payerErrors), detailsUpdate.paymentMethodErrors.get()); -
trunk/Source/WebCore/inspector/WebInjectedScriptHost.cpp
r261670 r271703 127 127 static JSObject* objectForPaymentDetails(VM& vm, JSGlobalObject* exec, const PaymentDetailsInit& paymentDetails) 128 128 { 129 auto* displayItems = constructEmptyArray(exec, nullptr);130 for (unsigned i = 0; i < paymentDetails.displayItems.size(); ++i)131 displayItems->putDirectIndex(exec, i, objectForPaymentItem(vm, exec, paymentDetails.displayItems[i]));132 133 auto* shippingOptions = constructEmptyArray(exec, nullptr);134 for (unsigned i = 0; i < paymentDetails.shippingOptions.size(); ++i)135 shippingOptions->putDirectIndex(exec, i, objectForPaymentShippingOption(vm, exec, paymentDetails.shippingOptions[i]));136 137 auto* modifiers = constructEmptyArray(exec, nullptr);138 for (unsigned i = 0; i < paymentDetails.modifiers.size(); ++i)139 modifiers->putDirectIndex(exec, i, objectForPaymentDetailsModifier(vm, exec, paymentDetails.modifiers[i]));140 141 129 auto* object = constructEmptyObject(exec); 142 130 object->putDirect(vm, Identifier::fromString(vm, "id"), jsString(vm, paymentDetails.id)); 143 131 object->putDirect(vm, Identifier::fromString(vm, "total"), objectForPaymentItem(vm, exec, paymentDetails.total)); 144 object->putDirect(vm, Identifier::fromString(vm, "displayItems"), displayItems); 145 object->putDirect(vm, Identifier::fromString(vm, "shippingOptions"), shippingOptions); 146 object->putDirect(vm, Identifier::fromString(vm, "modifiers"), modifiers); 132 if (paymentDetails.displayItems) { 133 auto* displayItems = constructEmptyArray(exec, nullptr); 134 for (unsigned i = 0; i < paymentDetails.displayItems->size(); ++i) 135 displayItems->putDirectIndex(exec, i, objectForPaymentItem(vm, exec, paymentDetails.displayItems->at(i))); 136 object->putDirect(vm, Identifier::fromString(vm, "displayItems"), displayItems); 137 } 138 if (paymentDetails.shippingOptions) { 139 auto* shippingOptions = constructEmptyArray(exec, nullptr); 140 for (unsigned i = 0; i < paymentDetails.shippingOptions->size(); ++i) 141 shippingOptions->putDirectIndex(exec, i, objectForPaymentShippingOption(vm, exec, paymentDetails.shippingOptions->at(i))); 142 object->putDirect(vm, Identifier::fromString(vm, "shippingOptions"), shippingOptions); 143 } 144 if (paymentDetails.modifiers) { 145 auto* modifiers = constructEmptyArray(exec, nullptr); 146 for (unsigned i = 0; i < paymentDetails.modifiers->size(); ++i) 147 modifiers->putDirectIndex(exec, i, objectForPaymentDetailsModifier(vm, exec, paymentDetails.modifiers->at(i))); 148 object->putDirect(vm, Identifier::fromString(vm, "modifiers"), modifiers); 149 } 147 150 return object; 148 151 }
Note: See TracChangeset
for help on using the changeset viewer.