[Mac] Ensure Apple Pay is unavailable when PassKit.framework is missing
[WebKit-https.git] / Source / WebKit / Shared / ApplePay / mac / WebPaymentCoordinatorProxyMac.mm
1 /*
2  * Copyright (C) 2016-2019 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 #import "config.h"
27 #import "WebPaymentCoordinatorProxy.h"
28
29 #if PLATFORM(MAC) && ENABLE(APPLE_PAY)
30
31 #import "PaymentAuthorizationViewController.h"
32 #import "WebPageProxy.h"
33 #import <pal/cocoa/PassKitSoftLink.h>
34 #import <wtf/BlockPtr.h>
35
36 namespace WebKit {
37
38 void WebPaymentCoordinatorProxy::platformShowPaymentUI(const URL& originatingURL, const Vector<URL>& linkIconURLStrings, PAL::SessionID sessionID, const WebCore::ApplePaySessionPaymentRequest& request, CompletionHandler<void(bool)>&& completionHandler)
39 {
40     if (!PAL::isPassKitFrameworkAvailable())
41         return completionHandler(false);
42
43     auto paymentRequest = platformPaymentRequest(originatingURL, linkIconURLStrings, sessionID, request);
44
45     auto showPaymentUIRequestSeed = m_showPaymentUIRequestSeed;
46     auto weakThis = makeWeakPtr(*this);
47     [PAL::getPKPaymentAuthorizationViewControllerClass() requestViewControllerWithPaymentRequest:paymentRequest.get() completion:makeBlockPtr([paymentRequest, showPaymentUIRequestSeed, weakThis, completionHandler = WTFMove(completionHandler)](PKPaymentAuthorizationViewController *viewController, NSError *error) mutable {
48         auto paymentCoordinatorProxy = weakThis.get();
49         if (!paymentCoordinatorProxy)
50             return completionHandler(false);
51
52         if (error) {
53             LOG_ERROR("+[PKPaymentAuthorizationViewController requestViewControllerWithPaymentRequest:completion:] error %@", error);
54
55             completionHandler(false);
56             return;
57         }
58
59         if (showPaymentUIRequestSeed != paymentCoordinatorProxy->m_showPaymentUIRequestSeed) {
60             // We've already been asked to hide the payment UI. Don't attempt to show it.
61             return completionHandler(false);
62         }
63
64         NSWindow *presentingWindow = paymentCoordinatorProxy->m_client.paymentCoordinatorPresentingWindow(*paymentCoordinatorProxy);
65         if (!presentingWindow)
66             return completionHandler(false);
67
68         ASSERT(viewController);
69
70         paymentCoordinatorProxy->m_authorizationPresenter = std::make_unique<PaymentAuthorizationViewController>(*paymentCoordinatorProxy, paymentRequest.get(), viewController);
71
72         ASSERT(!paymentCoordinatorProxy->m_sheetWindow);
73         paymentCoordinatorProxy->m_sheetWindow = [NSWindow windowWithContentViewController:viewController];
74
75         paymentCoordinatorProxy->m_sheetWindowWillCloseObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:paymentCoordinatorProxy->m_sheetWindow.get() queue:nil usingBlock:[paymentCoordinatorProxy](NSNotification *) {
76             paymentCoordinatorProxy->hidePaymentUI();
77             paymentCoordinatorProxy->didReachFinalState();
78         }];
79
80         [presentingWindow beginSheet:paymentCoordinatorProxy->m_sheetWindow.get() completionHandler:nullptr];
81
82         completionHandler(true);
83     }).get()];
84 }
85
86 void WebPaymentCoordinatorProxy::hidePaymentUI()
87 {
88     if (m_state == State::Activating) {
89         ++m_showPaymentUIRequestSeed;
90
91         ASSERT(!m_authorizationPresenter);
92         ASSERT(!m_sheetWindow);
93         return;
94     }
95
96     ASSERT(m_authorizationPresenter);
97     ASSERT(m_sheetWindow);
98
99     [[NSNotificationCenter defaultCenter] removeObserver:m_sheetWindowWillCloseObserver.get()];
100     m_sheetWindowWillCloseObserver = nullptr;
101
102     [[m_sheetWindow sheetParent] endSheet:m_sheetWindow.get()];
103
104     if (m_authorizationPresenter)
105         m_authorizationPresenter->dismiss();
106     m_authorizationPresenter = nullptr;
107
108     m_sheetWindow = nullptr;
109 }
110
111 }
112
113 #endif