cc97fd5e1f6234599eb884ca8187fb2cd0857c65
[WebKit-https.git] / Source / WebCore / Modules / applepay / cocoa / PaymentContactCocoa.mm
1 /*
2  * Copyright (C) 2016-2018 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "PaymentContact.h"
28
29 #if ENABLE(APPLE_PAY)
30
31 #import "ApplePayPaymentContact.h"
32 #import <Contacts/Contacts.h>
33 #import <pal/cocoa/PassKitSoftLink.h>
34 #import <wtf/SoftLinking.h>
35 #import <wtf/text/StringBuilder.h>
36
37 SOFT_LINK_FRAMEWORK(Contacts)
38 SOFT_LINK_CLASS(Contacts, CNMutablePostalAddress)
39 SOFT_LINK_CLASS(Contacts, CNPhoneNumber)
40
41 namespace WebCore {
42
43 static NSString *subLocality(CNPostalAddress *address)
44 {
45 #if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101204)
46 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
47     if (![address respondsToSelector:@selector(subLocality)])
48         return nil;
49 #endif
50     return address.subLocality;
51 #else
52     UNUSED_PARAM(address);
53     return nil;
54 #endif
55 }
56
57 static void setSubLocality(CNMutablePostalAddress *address, NSString *subLocality)
58 {
59 #if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101204)
60 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
61     if (![address respondsToSelector:@selector(setSubLocality:)])
62         return;
63 #endif
64     address.subLocality = subLocality;
65 #else
66     UNUSED_PARAM(address);
67     UNUSED_PARAM(subLocality);
68 #endif
69 }
70
71 static NSString *subAdministrativeArea(CNPostalAddress *address)
72 {
73 #if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101204)
74 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
75     if (![address respondsToSelector:@selector(subAdministrativeArea)])
76         return nil;
77 #endif
78     return address.subAdministrativeArea;
79 #else
80     UNUSED_PARAM(address);
81     return nil;
82 #endif
83 }
84
85 static void setSubAdministrativeArea(CNMutablePostalAddress *address, NSString *subAdministrativeArea)
86 {
87 #if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101204)
88 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
89     if (![address respondsToSelector:@selector(setSubAdministrativeArea:)])
90         return;
91 #endif
92     address.subAdministrativeArea = subAdministrativeArea;
93 #else
94     UNUSED_PARAM(address);
95     UNUSED_PARAM(subAdministrativeArea);
96 #endif
97 }
98
99 static RetainPtr<PKContact> convert(unsigned version, const ApplePayPaymentContact& contact)
100 {
101     auto result = adoptNS([PAL::allocPKContactInstance() init]);
102
103     NSString *familyName = nil;
104     NSString *phoneticFamilyName = nil;
105     if (!contact.familyName.isEmpty()) {
106         familyName = contact.familyName;
107         if (version >= 3 && !contact.phoneticFamilyName.isEmpty())
108             phoneticFamilyName = contact.phoneticFamilyName;
109     }
110
111     NSString *givenName = nil;
112     NSString *phoneticGivenName = nil;
113     if (!contact.givenName.isEmpty()) {
114         givenName = contact.givenName;
115         if (version >= 3 && !contact.phoneticGivenName.isEmpty())
116             phoneticGivenName = contact.phoneticGivenName;
117     }
118
119     if (familyName || givenName) {
120         auto name = adoptNS([[NSPersonNameComponents alloc] init]);
121         [name setFamilyName:familyName];
122         [name setGivenName:givenName];
123         if (phoneticFamilyName || phoneticGivenName) {
124             auto phoneticName = adoptNS([[NSPersonNameComponents alloc] init]);
125             [phoneticName setFamilyName:phoneticFamilyName];
126             [phoneticName setGivenName:phoneticGivenName];
127             [name setPhoneticRepresentation:phoneticName.get()];
128         }
129         [result setName:name.get()];
130     }
131
132     if (!contact.emailAddress.isEmpty())
133         [result setEmailAddress:contact.emailAddress];
134
135     if (!contact.phoneNumber.isEmpty())
136         [result setPhoneNumber:adoptNS([allocCNPhoneNumberInstance() initWithStringValue:contact.phoneNumber]).get()];
137
138     if (contact.addressLines && !contact.addressLines->isEmpty()) {
139         auto address = adoptNS([allocCNMutablePostalAddressInstance() init]);
140
141         StringBuilder builder;
142         for (unsigned i = 0; i < contact.addressLines->size(); ++i) {
143             builder.append(contact.addressLines->at(i));
144             if (i != contact.addressLines->size() - 1)
145                 builder.append('\n');
146         }
147
148         // FIXME: StringBuilder should hava a toNSString() function to avoid the extra String allocation.
149         [address setStreet:builder.toString()];
150
151         if (!contact.subLocality.isEmpty())
152             setSubLocality(address.get(), contact.subLocality);
153         if (!contact.locality.isEmpty())
154             [address setCity:contact.locality];
155         if (!contact.postalCode.isEmpty())
156             [address setPostalCode:contact.postalCode];
157         if (!contact.subAdministrativeArea.isEmpty())
158             setSubAdministrativeArea(address.get(), contact.subAdministrativeArea);
159         if (!contact.administrativeArea.isEmpty())
160             [address setState:contact.administrativeArea];
161         if (!contact.country.isEmpty())
162             [address setCountry:contact.country];
163         if (!contact.countryCode.isEmpty())
164             [address setISOCountryCode:contact.countryCode];
165
166         [result setPostalAddress:address.get()];
167     }
168
169     return result;
170 }
171
172 static ApplePayPaymentContact convert(unsigned version, PKContact *contact)
173 {
174     ASSERT(contact);
175
176     ApplePayPaymentContact result;
177
178     result.phoneNumber = contact.phoneNumber.stringValue;
179     result.emailAddress = contact.emailAddress;
180
181     NSPersonNameComponents *name = contact.name;
182     result.givenName = name.givenName;
183     result.familyName = name.familyName;
184     if (name)
185         result.localizedName = [NSPersonNameComponentsFormatter localizedStringFromPersonNameComponents:name style:NSPersonNameComponentsFormatterStyleDefault options:0];
186
187     if (version >= 3) {
188         NSPersonNameComponents *phoneticName = name.phoneticRepresentation;
189         result.phoneticGivenName = phoneticName.givenName;
190         result.phoneticFamilyName = phoneticName.familyName;
191         if (phoneticName)
192             result.localizedPhoneticName = [NSPersonNameComponentsFormatter localizedStringFromPersonNameComponents:name style:NSPersonNameComponentsFormatterStyleDefault options:NSPersonNameComponentsFormatterPhonetic];
193     }
194
195     CNPostalAddress *postalAddress = contact.postalAddress;
196     if (postalAddress.street.length) {
197         Vector<String> addressLines = String(postalAddress.street).split('\n');
198         result.addressLines = WTFMove(addressLines);
199     }
200     result.subLocality = subLocality(postalAddress);
201     result.locality = postalAddress.city;
202     result.postalCode = postalAddress.postalCode;
203     result.subAdministrativeArea = subAdministrativeArea(postalAddress);
204     result.administrativeArea = postalAddress.state;
205     result.country = postalAddress.country;
206     result.countryCode = postalAddress.ISOCountryCode;
207
208     return result;
209 }
210
211 PaymentContact PaymentContact::fromApplePayPaymentContact(unsigned version, const ApplePayPaymentContact& contact)
212 {
213     return PaymentContact(convert(version, contact).get());
214 }
215
216 ApplePayPaymentContact PaymentContact::toApplePayPaymentContact(unsigned version) const
217 {
218     return convert(version, m_pkContact.get());
219 }
220
221 }
222
223 #endif