1 | /* |
2 | * Copyright (C) 2012 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 "WebNotificationProvider.h" |
28 | |
29 | #include <WebKit/WKMutableArray.h> |
30 | #include <WebKit/WKNotification.h> |
31 | #include <WebKit/WKNotificationManager.h> |
32 | #include <WebKit/WKNumber.h> |
33 | #include <WebKit/WKSecurityOriginRef.h> |
34 | #include <wtf/Assertions.h> |
35 | |
36 | namespace WTR { |
37 | |
38 | static void showWebNotification(WKPageRef page, WKNotificationRef notification, const void* clientInfo) |
39 | { |
40 | static_cast<WebNotificationProvider*>(const_cast<void*>(clientInfo))->showWebNotification(page, notification); |
41 | } |
42 | |
43 | static void closeWebNotification(WKNotificationRef notification, const void* clientInfo) |
44 | { |
45 | static_cast<WebNotificationProvider*>(const_cast<void*>(clientInfo))->closeWebNotification(notification); |
46 | } |
47 | |
48 | static void addNotificationManager(WKNotificationManagerRef manager, const void* clientInfo) |
49 | { |
50 | static_cast<WebNotificationProvider*>(const_cast<void*>(clientInfo))->addNotificationManager(manager); |
51 | } |
52 | |
53 | static void removeNotificationManager(WKNotificationManagerRef manager, const void* clientInfo) |
54 | { |
55 | static_cast<WebNotificationProvider*>(const_cast<void*>(clientInfo))->removeNotificationManager(manager); |
56 | } |
57 | |
58 | static WKDictionaryRef notificationPermissions(const void* clientInfo) |
59 | { |
60 | return static_cast<WebNotificationProvider*>(const_cast<void*>(clientInfo))->notificationPermissions(); |
61 | } |
62 | |
63 | WebNotificationProvider::WebNotificationProvider() |
64 | { |
65 | } |
66 | |
67 | WebNotificationProvider::~WebNotificationProvider() |
68 | { |
69 | for (auto& manager : m_ownedNotifications) |
70 | WKNotificationManagerSetProvider(manager.key.get(), nullptr); |
71 | } |
72 | |
73 | WKNotificationProviderV0 WebNotificationProvider::provider() |
74 | { |
75 | WKNotificationProviderV0 notificationProvider = { |
76 | { 0, this }, |
77 | WTR::showWebNotification, |
78 | WTR::closeWebNotification, |
79 | 0, // didDestroyNotification |
80 | WTR::addNotificationManager, |
81 | WTR::removeNotificationManager, |
82 | WTR::notificationPermissions, |
83 | 0, // clearNotifications |
84 | }; |
85 | return notificationProvider; |
86 | } |
87 | |
88 | void WebNotificationProvider::showWebNotification(WKPageRef page, WKNotificationRef notification) |
89 | { |
90 | auto context = WKPageGetContext(page); |
91 | auto notificationManager = WKContextGetNotificationManager(context); |
92 | uint64_t id = WKNotificationGetID(notification); |
93 | |
94 | ASSERT(m_ownedNotifications.contains(notificationManager)); |
95 | auto addResult = m_ownedNotifications.find(notificationManager)->value.add(id); |
96 | ASSERT_UNUSED(addResult, addResult.isNewEntry); |
97 | auto addResult2 = m_owningManager.set(id, notificationManager); |
98 | ASSERT_UNUSED(addResult2, addResult2.isNewEntry); |
99 | auto addResult3 = m_localToGlobalNotificationIDMap.add(std::make_pair(page, WKNotificationManagerGetLocalIDForTesting(notificationManager, notification)), id); |
100 | ASSERT_UNUSED(addResult3, addResult3.isNewEntry); |
101 | |
102 | WKNotificationManagerProviderDidShowNotification(notificationManager, id); |
103 | } |
104 | |
105 | static void removeGlobalIDFromIDMap(HashMap<std::pair<WKPageRef, uint64_t>, uint64_t>& map, uint64_t id) |
106 | { |
107 | for (auto iter = map.begin(); iter != map.end(); ++iter) { |
108 | if (iter->value == id) { |
109 | map.remove(iter); |
110 | return; |
111 | } |
112 | } |
113 | ASSERT_NOT_REACHED(); |
114 | } |
115 | |
116 | void WebNotificationProvider::closeWebNotification(WKNotificationRef notification) |
117 | { |
118 | uint64_t id = WKNotificationGetID(notification); |
119 | ASSERT(m_owningManager.contains(id)); |
120 | auto notificationManager = m_owningManager.get(id); |
121 | |
122 | ASSERT(m_ownedNotifications.contains(notificationManager)); |
123 | bool success = m_ownedNotifications.find(notificationManager)->value.remove(id); |
124 | ASSERT_UNUSED(success, success); |
125 | m_owningManager.remove(id); |
126 | |
127 | removeGlobalIDFromIDMap(m_localToGlobalNotificationIDMap, id); |
128 | |
129 | WKRetainPtr<WKUInt64Ref> wkID = adoptWK(WKUInt64Create(id)); |
130 | WKRetainPtr<WKMutableArrayRef> array = adoptWK(WKMutableArrayCreate()); |
131 | WKArrayAppendItem(array.get(), wkID.get()); |
132 | WKNotificationManagerProviderDidCloseNotifications(notificationManager, array.get()); |
133 | } |
134 | |
135 | void WebNotificationProvider::addNotificationManager(WKNotificationManagerRef manager) |
136 | { |
137 | m_ownedNotifications.add(manager, HashSet<uint64_t>()); |
138 | } |
139 | |
140 | void WebNotificationProvider::removeNotificationManager(WKNotificationManagerRef manager) |
141 | { |
142 | auto iterator = m_ownedNotifications.find(manager); |
143 | ASSERT(iterator != m_ownedNotifications.end()); |
144 | auto toRemove = iterator->value; |
145 | WKRetainPtr<WKNotificationManagerRef> guard(manager); |
146 | m_ownedNotifications.remove(iterator); |
147 | WKRetainPtr<WKMutableArrayRef> array = adoptWK(WKMutableArrayCreate()); |
148 | for (uint64_t notificationID : toRemove) { |
149 | bool success = m_owningManager.remove(notificationID); |
150 | ASSERT_UNUSED(success, success); |
151 | removeGlobalIDFromIDMap(m_localToGlobalNotificationIDMap, notificationID); |
152 | WKArrayAppendItem(array.get(), adoptWK(WKUInt64Create(notificationID)).get()); |
153 | } |
154 | WKNotificationManagerProviderDidCloseNotifications(manager, array.get()); |
155 | } |
156 | |
157 | WKDictionaryRef WebNotificationProvider::notificationPermissions() |
158 | { |
159 | // Initial permissions are always empty. |
160 | return WKMutableDictionaryCreate(); |
161 | } |
162 | |
163 | void WebNotificationProvider::simulateWebNotificationClick(WKPageRef page, uint64_t notificationID) |
164 | { |
165 | ASSERT(m_localToGlobalNotificationIDMap.contains(std::make_pair(page, notificationID))); |
166 | auto globalID = m_localToGlobalNotificationIDMap.get(std::make_pair(page, notificationID)); |
167 | ASSERT(m_owningManager.contains(globalID)); |
168 | WKNotificationManagerProviderDidClickNotification(m_owningManager.get(globalID), globalID); |
169 | } |
170 | |
171 | void WebNotificationProvider::reset() |
172 | { |
173 | for (auto& notificationPair : m_ownedNotifications) { |
174 | if (notificationPair.value.isEmpty()) |
175 | continue; |
176 | WKRetainPtr<WKMutableArrayRef> array = adoptWK(WKMutableArrayCreate()); |
177 | for (uint64_t notificationID : notificationPair.value) |
178 | WKArrayAppendItem(array.get(), adoptWK(WKUInt64Create(notificationID)).get()); |
179 | |
180 | notificationPair.value.clear(); |
181 | WKNotificationManagerProviderDidCloseNotifications(notificationPair.key.get(), array.get()); |
182 | } |
183 | m_owningManager.clear(); |
184 | m_localToGlobalNotificationIDMap.clear(); |
185 | } |
186 | |
187 | } // namespace WTR |
188 | |