| 1 | /* |
| 2 | * Copyright (C) 2010-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 "InjectedBundle.h" |
| 28 | |
| 29 | #include "ActivateFonts.h" |
| 30 | #include "InjectedBundlePage.h" |
| 31 | #include "StringFunctions.h" |
| 32 | #include "WebCoreTestSupport.h" |
| 33 | #include <JavaScriptCore/Options.h> |
| 34 | #include <WebKit/WKBundle.h> |
| 35 | #include <WebKit/WKBundlePage.h> |
| 36 | #include <WebKit/WKBundlePagePrivate.h> |
| 37 | #include <WebKit/WKBundlePrivate.h> |
| 38 | #include <WebKit/WKRetainPtr.h> |
| 39 | #include <WebKit/WebKit2_C.h> |
| 40 | #include <wtf/text/CString.h> |
| 41 | #include <wtf/text/StringBuilder.h> |
| 42 | #include <wtf/Vector.h> |
| 43 | |
| 44 | namespace WTR { |
| 45 | |
| 46 | static void handleTextDidChangeInTextField(WKBundlePageRef, WKBundleNodeHandleRef, WKBundleFrameRef, const void* context) |
| 47 | { |
| 48 | static_cast<InjectedBundle*>(const_cast<void*>(context))->textDidChangeInTextField(); |
| 49 | } |
| 50 | |
| 51 | static void handleTextFieldDidBeginEditing(WKBundlePageRef, WKBundleNodeHandleRef, WKBundleFrameRef, const void* context) |
| 52 | { |
| 53 | static_cast<InjectedBundle*>(const_cast<void*>(context))->textFieldDidBeginEditing(); |
| 54 | } |
| 55 | |
| 56 | static void handleTextFieldDidEndEditing(WKBundlePageRef, WKBundleNodeHandleRef, WKBundleFrameRef, const void* context) |
| 57 | { |
| 58 | static_cast<InjectedBundle*>(const_cast<void*>(context))->textFieldDidEndEditing(); |
| 59 | } |
| 60 | |
| 61 | InjectedBundle& InjectedBundle::singleton() |
| 62 | { |
| 63 | static InjectedBundle& shared = *new InjectedBundle; |
| 64 | return shared; |
| 65 | } |
| 66 | |
| 67 | void InjectedBundle::didCreatePage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo) |
| 68 | { |
| 69 | static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didCreatePage(page); |
| 70 | } |
| 71 | |
| 72 | void InjectedBundle::willDestroyPage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo) |
| 73 | { |
| 74 | static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->willDestroyPage(page); |
| 75 | } |
| 76 | |
| 77 | void InjectedBundle::didInitializePageGroup(WKBundleRef bundle, WKBundlePageGroupRef pageGroup, const void* clientInfo) |
| 78 | { |
| 79 | static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didInitializePageGroup(pageGroup); |
| 80 | } |
| 81 | |
| 82 | void InjectedBundle::didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo) |
| 83 | { |
| 84 | static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didReceiveMessage(messageName, messageBody); |
| 85 | } |
| 86 | |
| 87 | void InjectedBundle::didReceiveMessageToPage(WKBundleRef bundle, WKBundlePageRef page, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo) |
| 88 | { |
| 89 | static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didReceiveMessageToPage(page, messageName, messageBody); |
| 90 | } |
| 91 | |
| 92 | void InjectedBundle::initialize(WKBundleRef bundle, WKTypeRef initializationUserData) |
| 93 | { |
| 94 | m_bundle = bundle; |
| 95 | |
| 96 | WKBundleClientV1 client = { |
| 97 | { 1, this }, |
| 98 | didCreatePage, |
| 99 | willDestroyPage, |
| 100 | didInitializePageGroup, |
| 101 | didReceiveMessage, |
| 102 | didReceiveMessageToPage |
| 103 | }; |
| 104 | WKBundleSetClient(m_bundle, &client.base); |
| 105 | WKBundleSetServiceWorkerProxyCreationCallback(m_bundle, WebCoreTestSupport::setupNewlyCreatedServiceWorker); |
| 106 | platformInitialize(initializationUserData); |
| 107 | |
| 108 | activateFonts(); |
| 109 | } |
| 110 | |
| 111 | void InjectedBundle::didCreatePage(WKBundlePageRef page) |
| 112 | { |
| 113 | bool isMainPage = m_pages.isEmpty(); |
| 114 | m_pages.append(std::make_unique<InjectedBundlePage>(page)); |
| 115 | |
| 116 | setUpInjectedBundleClients(page); |
| 117 | |
| 118 | if (!isMainPage) |
| 119 | return; |
| 120 | |
| 121 | WKRetainPtr<WKStringRef> messsageName = adoptWK(WKStringCreateWithUTF8CString("Initialization" )); |
| 122 | WKTypeRef result = nullptr; |
| 123 | WKBundlePostSynchronousMessage(m_bundle, messsageName.get(), nullptr, &result); |
| 124 | ASSERT(WKGetTypeID(result) == WKDictionaryGetTypeID()); |
| 125 | WKRetainPtr<WKDictionaryRef> initializationDictionary = adoptWK(static_cast<WKDictionaryRef>(result)); |
| 126 | |
| 127 | WKRetainPtr<WKStringRef> resumeTestingKey = adoptWK(WKStringCreateWithUTF8CString("ResumeTesting" )); |
| 128 | WKTypeRef resumeTestingValue = WKDictionaryGetItemForKey(initializationDictionary.get(), resumeTestingKey.get()); |
| 129 | ASSERT(WKGetTypeID(resumeTestingValue) == WKBooleanGetTypeID()); |
| 130 | if (WKBooleanGetValue(static_cast<WKBooleanRef>(resumeTestingValue))) |
| 131 | beginTesting(initializationDictionary.get(), BegingTestingMode::Resume); |
| 132 | } |
| 133 | |
| 134 | void InjectedBundle::willDestroyPage(WKBundlePageRef page) |
| 135 | { |
| 136 | m_pages.removeFirstMatching([page](auto& current) { |
| 137 | return current->page() == page; |
| 138 | }); |
| 139 | } |
| 140 | |
| 141 | void InjectedBundle::didInitializePageGroup(WKBundlePageGroupRef pageGroup) |
| 142 | { |
| 143 | m_pageGroup = pageGroup; |
| 144 | } |
| 145 | |
| 146 | void InjectedBundle::setUpInjectedBundleClients(WKBundlePageRef page) |
| 147 | { |
| 148 | WKBundlePageFormClientV2 formClient = { |
| 149 | { 2, this }, |
| 150 | handleTextFieldDidBeginEditing, |
| 151 | handleTextFieldDidEndEditing, |
| 152 | handleTextDidChangeInTextField, |
| 153 | 0, // textDidChangeInTextArea |
| 154 | 0, // shouldPerformActionInTextField |
| 155 | 0, // willSubmitForm |
| 156 | 0, // willSendSubmitEvent |
| 157 | 0, // didFocusTextField |
| 158 | 0, // shouldNotifyOnFormChanges |
| 159 | 0, // didAssociateFormControls |
| 160 | }; |
| 161 | WKBundlePageSetFormClient(page, &formClient.base); |
| 162 | } |
| 163 | |
| 164 | InjectedBundlePage* InjectedBundle::page() const |
| 165 | { |
| 166 | // It might be better to have the UI process send over a reference to the main |
| 167 | // page instead of just assuming it's the first one. |
| 168 | return m_pages[0].get(); |
| 169 | } |
| 170 | |
| 171 | void InjectedBundle::resetLocalSettings() |
| 172 | { |
| 173 | setlocale(LC_ALL, "" ); |
| 174 | } |
| 175 | |
| 176 | void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody) |
| 177 | { |
| 178 | WKRetainPtr<WKStringRef> errorMessageName = adoptWK(WKStringCreateWithUTF8CString("Error" )); |
| 179 | WKRetainPtr<WKStringRef> errorMessageBody = adoptWK(WKStringCreateWithUTF8CString("Unknown" )); |
| 180 | WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get()); |
| 181 | } |
| 182 | |
| 183 | static void postGCTask(void* context) |
| 184 | { |
| 185 | WKBundlePageRef page = reinterpret_cast<WKBundlePageRef>(context); |
| 186 | InjectedBundle::singleton().reportLiveDocuments(page); |
| 187 | WKRelease(page); |
| 188 | } |
| 189 | |
| 190 | void InjectedBundle::reportLiveDocuments(WKBundlePageRef page) |
| 191 | { |
| 192 | // Release memory again, after the GC and timer fire. This is necessary to clear entries from CachedResourceLoader's m_documentResources in some scenarios. |
| 193 | WKBundleReleaseMemory(m_bundle); |
| 194 | |
| 195 | const bool excludeDocumentsInPageGroup = true; |
| 196 | auto documentURLs = adoptWK(WKBundleGetLiveDocumentURLs(m_bundle, m_pageGroup, excludeDocumentsInPageGroup)); |
| 197 | auto ackMessageName = adoptWK(WKStringCreateWithUTF8CString("LiveDocuments" )); |
| 198 | WKBundlePagePostMessage(page, ackMessageName.get(), documentURLs.get()); |
| 199 | } |
| 200 | |
| 201 | void InjectedBundle::didReceiveMessageToPage(WKBundlePageRef page, WKStringRef messageName, WKTypeRef messageBody) |
| 202 | { |
| 203 | if (WKStringIsEqualToUTF8CString(messageName, "BeginTest" )) { |
| 204 | ASSERT(messageBody); |
| 205 | ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); |
| 206 | WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); |
| 207 | |
| 208 | WKRetainPtr<WKStringRef> dumpPixelsKey = adoptWK(WKStringCreateWithUTF8CString("DumpPixels" )); |
| 209 | m_dumpPixels = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, dumpPixelsKey.get()))); |
| 210 | |
| 211 | WKRetainPtr<WKStringRef> timeoutKey = adoptWK(WKStringCreateWithUTF8CString("Timeout" )); |
| 212 | m_timeout = Seconds::fromMilliseconds(WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, timeoutKey.get())))); |
| 213 | |
| 214 | WKRetainPtr<WKStringRef> dumpJSConsoleLogInStdErrKey = adoptWK(WKStringCreateWithUTF8CString("DumpJSConsoleLogInStdErr" )); |
| 215 | m_dumpJSConsoleLogInStdErr = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, dumpJSConsoleLogInStdErrKey.get()))); |
| 216 | |
| 217 | WKRetainPtr<WKStringRef> ackMessageName = adoptWK(WKStringCreateWithUTF8CString("Ack" )); |
| 218 | WKRetainPtr<WKStringRef> ackMessageBody = adoptWK(WKStringCreateWithUTF8CString("BeginTest" )); |
| 219 | WKBundlePagePostMessage(page, ackMessageName.get(), ackMessageBody.get()); |
| 220 | |
| 221 | beginTesting(messageBodyDictionary, BegingTestingMode::New); |
| 222 | return; |
| 223 | } |
| 224 | |
| 225 | if (WKStringIsEqualToUTF8CString(messageName, "Reset" )) { |
| 226 | ASSERT(messageBody); |
| 227 | ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID()); |
| 228 | WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); |
| 229 | WKRetainPtr<WKStringRef> jscOptionsKey = adoptWK(WKStringCreateWithUTF8CString("JSCOptions" )); |
| 230 | WKRetainPtr<WKStringRef> jscOptionsString = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, jscOptionsKey.get())); |
| 231 | if (jscOptionsString) { |
| 232 | String options = toWTFString(jscOptionsString); |
| 233 | JSC::Options::setOptions(options.utf8().data()); |
| 234 | } |
| 235 | |
| 236 | WKRetainPtr<WKStringRef> shouldGCKey = adoptWK(WKStringCreateWithUTF8CString("ShouldGC" )); |
| 237 | bool shouldGC = WKBooleanGetValue(static_cast<WKBooleanRef>(WKDictionaryGetItemForKey(messageBodyDictionary, shouldGCKey.get()))); |
| 238 | if (shouldGC) |
| 239 | WKBundleGarbageCollectJavaScriptObjects(m_bundle); |
| 240 | |
| 241 | WKRetainPtr<WKStringRef> allowedHostsKey = adoptWK(WKStringCreateWithUTF8CString("AllowedHosts" )); |
| 242 | WKTypeRef allowedHostsValue = WKDictionaryGetItemForKey(messageBodyDictionary, allowedHostsKey.get()); |
| 243 | if (allowedHostsValue && WKGetTypeID(allowedHostsValue) == WKArrayGetTypeID()) { |
| 244 | m_allowedHosts.clear(); |
| 245 | |
| 246 | WKArrayRef allowedHostsArray = static_cast<WKArrayRef>(allowedHostsValue); |
| 247 | for (size_t i = 0, size = WKArrayGetSize(allowedHostsArray); i < size; ++i) { |
| 248 | WKTypeRef item = WKArrayGetItemAtIndex(allowedHostsArray, i); |
| 249 | if (item && WKGetTypeID(item) == WKStringGetTypeID()) |
| 250 | m_allowedHosts.append(toWTFString(static_cast<WKStringRef>(item))); |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | m_state = Idle; |
| 255 | m_dumpPixels = false; |
| 256 | m_pixelResultIsPending = false; |
| 257 | |
| 258 | resetLocalSettings(); |
| 259 | TestRunner::removeAllWebNotificationPermissions(); |
| 260 | |
| 261 | InjectedBundle::page()->resetAfterTest(); |
| 262 | return; |
| 263 | } |
| 264 | |
| 265 | if (WKStringIsEqualToUTF8CString(messageName, "GetLiveDocuments" )) { |
| 266 | const bool excludeDocumentsInPageGroup = false; |
| 267 | auto documentURLs = adoptWK(WKBundleGetLiveDocumentURLs(m_bundle, m_pageGroup, excludeDocumentsInPageGroup)); |
| 268 | auto ackMessageName = adoptWK(WKStringCreateWithUTF8CString("LiveDocuments" )); |
| 269 | WKBundlePagePostMessage(page, ackMessageName.get(), documentURLs.get()); |
| 270 | return; |
| 271 | } |
| 272 | |
| 273 | if (WKStringIsEqualToUTF8CString(messageName, "CheckForWorldLeaks" )) { |
| 274 | WKBundleReleaseMemory(m_bundle); |
| 275 | |
| 276 | WKRetain(page); // Balanced by the release in postGCTask. |
| 277 | WKBundlePageCallAfterTasksAndTimers(page, postGCTask, (void*)page); |
| 278 | return; |
| 279 | } |
| 280 | |
| 281 | if (WKStringIsEqualToUTF8CString(messageName, "CallAddChromeInputFieldCallback" )) { |
| 282 | m_testRunner->callAddChromeInputFieldCallback(); |
| 283 | return; |
| 284 | } |
| 285 | |
| 286 | if (WKStringIsEqualToUTF8CString(messageName, "CallRemoveChromeInputFieldCallback" )) { |
| 287 | m_testRunner->callRemoveChromeInputFieldCallback(); |
| 288 | return; |
| 289 | } |
| 290 | |
| 291 | if (WKStringIsEqualToUTF8CString(messageName, "CallFocusWebViewCallback" )) { |
| 292 | m_testRunner->callFocusWebViewCallback(); |
| 293 | return; |
| 294 | } |
| 295 | |
| 296 | if (WKStringIsEqualToUTF8CString(messageName, "CallSetBackingScaleFactorCallback" )) { |
| 297 | m_testRunner->callSetBackingScaleFactorCallback(); |
| 298 | return; |
| 299 | } |
| 300 | |
| 301 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidBeginSwipeCallback" )) { |
| 302 | m_testRunner->callDidBeginSwipeCallback(); |
| 303 | return; |
| 304 | } |
| 305 | |
| 306 | if (WKStringIsEqualToUTF8CString(messageName, "CallWillEndSwipeCallback" )) { |
| 307 | m_testRunner->callWillEndSwipeCallback(); |
| 308 | return; |
| 309 | } |
| 310 | |
| 311 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidEndSwipeCallback" )) { |
| 312 | m_testRunner->callDidEndSwipeCallback(); |
| 313 | return; |
| 314 | } |
| 315 | |
| 316 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidRemoveSwipeSnapshotCallback" )) { |
| 317 | m_testRunner->callDidRemoveSwipeSnapshotCallback(); |
| 318 | return; |
| 319 | } |
| 320 | |
| 321 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidClearStatisticsThroughWebsiteDataRemoval" )) { |
| 322 | m_testRunner->statisticsCallClearThroughWebsiteDataRemovalCallback(); |
| 323 | return; |
| 324 | } |
| 325 | |
| 326 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidResetStatisticsToConsistentState" )) { |
| 327 | m_testRunner->statisticsCallDidResetToConsistentStateCallback(); |
| 328 | return; |
| 329 | } |
| 330 | |
| 331 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetBlockCookiesForHost" )) { |
| 332 | m_testRunner->statisticsCallDidSetBlockCookiesForHostCallback(); |
| 333 | return; |
| 334 | } |
| 335 | |
| 336 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetStatisticsDebugMode" )) { |
| 337 | m_testRunner->statisticsCallDidSetDebugModeCallback(); |
| 338 | return; |
| 339 | } |
| 340 | |
| 341 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetPrevalentResourceForDebugMode" )) { |
| 342 | m_testRunner->statisticsCallDidSetPrevalentResourceForDebugModeCallback(); |
| 343 | return; |
| 344 | } |
| 345 | |
| 346 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetLastSeen" )) { |
| 347 | m_testRunner->statisticsCallDidSetLastSeenCallback(); |
| 348 | return; |
| 349 | } |
| 350 | |
| 351 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetPrevalentResource" )) { |
| 352 | m_testRunner->statisticsCallDidSetPrevalentResourceCallback(); |
| 353 | return; |
| 354 | } |
| 355 | |
| 356 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetVeryPrevalentResource" )) { |
| 357 | m_testRunner->statisticsCallDidSetVeryPrevalentResourceCallback(); |
| 358 | return; |
| 359 | } |
| 360 | |
| 361 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidSetHasHadUserInteraction" )) { |
| 362 | m_testRunner->statisticsCallDidSetHasHadUserInteractionCallback(); |
| 363 | return; |
| 364 | } |
| 365 | |
| 366 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidReceiveAllStorageAccessEntries" )) { |
| 367 | ASSERT(messageBody); |
| 368 | ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID()); |
| 369 | |
| 370 | WKArrayRef domainsArray = static_cast<WKArrayRef>(messageBody); |
| 371 | auto size = WKArrayGetSize(domainsArray); |
| 372 | Vector<String> domains; |
| 373 | domains.reserveInitialCapacity(size); |
| 374 | for (size_t i = 0; i < size; ++i) { |
| 375 | WKTypeRef item = WKArrayGetItemAtIndex(domainsArray, i); |
| 376 | if (item && WKGetTypeID(item) == WKStringGetTypeID()) |
| 377 | domains.append(toWTFString(static_cast<WKStringRef>(item))); |
| 378 | } |
| 379 | |
| 380 | m_testRunner->callDidReceiveAllStorageAccessEntriesCallback(domains); |
| 381 | return; |
| 382 | } |
| 383 | |
| 384 | if (WKStringIsEqualToUTF8CString(messageName, "CallDidRemoveAllSessionCredentialsCallback" )) { |
| 385 | m_testRunner->callDidRemoveAllSessionCredentialsCallback(); |
| 386 | return; |
| 387 | } |
| 388 | |
| 389 | if (WKStringIsEqualToUTF8CString(messageName, "NotifyDownloadDone" )) { |
| 390 | if (m_testRunner->shouldFinishAfterDownload()) |
| 391 | m_testRunner->notifyDone(); |
| 392 | return; |
| 393 | } |
| 394 | |
| 395 | if (WKStringIsEqualToUTF8CString(messageName, "CallUISideScriptCallback" )) { |
| 396 | WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); |
| 397 | |
| 398 | WKRetainPtr<WKStringRef> resultKey = adoptWK(WKStringCreateWithUTF8CString("Result" )); |
| 399 | WKRetainPtr<WKStringRef> callbackIDKey = adoptWK(WKStringCreateWithUTF8CString("CallbackID" )); |
| 400 | |
| 401 | unsigned callbackID = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, callbackIDKey.get()))); |
| 402 | |
| 403 | WKStringRef resultString = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, resultKey.get())); |
| 404 | auto resultJSString = toJS(resultString); |
| 405 | |
| 406 | m_testRunner->runUIScriptCallback(callbackID, resultJSString.get()); |
| 407 | return; |
| 408 | } |
| 409 | |
| 410 | if (WKStringIsEqualToUTF8CString(messageName, "WorkQueueProcessedCallback" )) { |
| 411 | if (!topLoadingFrame() && !m_testRunner->shouldWaitUntilDone()) |
| 412 | InjectedBundle::page()->dump(); |
| 413 | return; |
| 414 | } |
| 415 | |
| 416 | if (WKStringIsEqualToUTF8CString(messageName, "WebsiteDataDeletionForRegistrableDomainsFinished" )) { |
| 417 | m_testRunner->statisticsDidModifyDataRecordsCallback(); |
| 418 | return; |
| 419 | } |
| 420 | |
| 421 | if (WKStringIsEqualToUTF8CString(messageName, "WebsiteDataScanForRegistrableDomainsFinished" )) { |
| 422 | m_testRunner->statisticsDidScanDataRecordsCallback(); |
| 423 | return; |
| 424 | } |
| 425 | |
| 426 | if (WKStringIsEqualToUTF8CString(messageName, "ResourceLoadStatisticsTelemetryFinished" )) { |
| 427 | WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody); |
| 428 | |
| 429 | WKRetainPtr<WKStringRef> totalPrevalentResourcesKey = adoptWK(WKStringCreateWithUTF8CString("TotalPrevalentResources" )); |
| 430 | WKRetainPtr<WKStringRef> totalPrevalentResourcesWithUserInteractionKey = adoptWK(WKStringCreateWithUTF8CString("TotalPrevalentResourcesWithUserInteraction" )); |
| 431 | WKRetainPtr<WKStringRef> top3SubframeUnderTopFrameOriginsKey = adoptWK(WKStringCreateWithUTF8CString("Top3SubframeUnderTopFrameOrigins" )); |
| 432 | |
| 433 | unsigned totalPrevalentResources = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, totalPrevalentResourcesKey.get()))); |
| 434 | unsigned totalPrevalentResourcesWithUserInteraction = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, totalPrevalentResourcesWithUserInteractionKey.get()))); |
| 435 | unsigned top3SubframeUnderTopFrameOrigins = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, top3SubframeUnderTopFrameOriginsKey.get()))); |
| 436 | |
| 437 | m_testRunner->statisticsDidRunTelemetryCallback(totalPrevalentResources, totalPrevalentResourcesWithUserInteraction, top3SubframeUnderTopFrameOrigins); |
| 438 | return; |
| 439 | } |
| 440 | |
| 441 | if (WKStringIsEqualToUTF8CString(messageName, "DidGetApplicationManifest" )) { |
| 442 | m_testRunner->didGetApplicationManifest(); |
| 443 | return; |
| 444 | } |
| 445 | |
| 446 | if (WKStringIsEqualToUTF8CString(messageName, "PerformCustomMenuAction" )) { |
| 447 | m_testRunner->performCustomMenuAction(); |
| 448 | return; |
| 449 | } |
| 450 | |
| 451 | WKRetainPtr<WKStringRef> errorMessageName = adoptWK(WKStringCreateWithUTF8CString("Error" )); |
| 452 | WKRetainPtr<WKStringRef> errorMessageBody = adoptWK(WKStringCreateWithUTF8CString("Unknown" )); |
| 453 | WKBundlePagePostMessage(page, errorMessageName.get(), errorMessageBody.get()); |
| 454 | } |
| 455 | |
| 456 | bool InjectedBundle::booleanForKey(WKDictionaryRef dictionary, const char* key) |
| 457 | { |
| 458 | WKRetainPtr<WKStringRef> wkKey = adoptWK(WKStringCreateWithUTF8CString(key)); |
| 459 | WKTypeRef value = WKDictionaryGetItemForKey(dictionary, wkKey.get()); |
| 460 | if (WKGetTypeID(value) != WKBooleanGetTypeID()) { |
| 461 | outputText(makeString("Boolean value for key" , key, " not found in dictionary\n" )); |
| 462 | return false; |
| 463 | } |
| 464 | return WKBooleanGetValue(static_cast<WKBooleanRef>(value)); |
| 465 | } |
| 466 | |
| 467 | String InjectedBundle::stringForKey(WKDictionaryRef dictionary, const char* key) |
| 468 | { |
| 469 | WKRetainPtr<WKStringRef> wkKey = adoptWK(WKStringCreateWithUTF8CString(key)); |
| 470 | WKStringRef value = static_cast<WKStringRef>(WKDictionaryGetItemForKey(dictionary, wkKey.get())); |
| 471 | if (!value) { |
| 472 | outputText(makeString("String value for key" , key, " not found in dictionary\n" )); |
| 473 | return emptyString(); |
| 474 | } |
| 475 | return toWTFString(value); |
| 476 | } |
| 477 | |
| 478 | void InjectedBundle::beginTesting(WKDictionaryRef settings, BegingTestingMode testingMode) |
| 479 | { |
| 480 | m_state = Testing; |
| 481 | |
| 482 | m_pixelResult.clear(); |
| 483 | m_repaintRects.clear(); |
| 484 | |
| 485 | m_testRunner = TestRunner::create(); |
| 486 | m_gcController = GCController::create(); |
| 487 | m_eventSendingController = EventSendingController::create(); |
| 488 | m_textInputController = TextInputController::create(); |
| 489 | #if HAVE(ACCESSIBILITY) |
| 490 | m_accessibilityController = AccessibilityController::create(); |
| 491 | #endif |
| 492 | |
| 493 | // Don't change experimental or internal features here; those should be set in TestController::resetPreferencesToConsistentValues(). |
| 494 | WKBundleSetAllowUniversalAccessFromFileURLs(m_bundle, m_pageGroup, true); |
| 495 | WKBundleSetJavaScriptCanAccessClipboard(m_bundle, m_pageGroup, true); |
| 496 | WKBundleSetPrivateBrowsingEnabled(m_bundle, m_pageGroup, false); |
| 497 | WKBundleSetUseDashboardCompatibilityMode(m_bundle, m_pageGroup, false); |
| 498 | WKBundleSetAuthorAndUserStylesEnabled(m_bundle, m_pageGroup, true); |
| 499 | WKBundleSetFrameFlatteningEnabled(m_bundle, m_pageGroup, false); |
| 500 | WKBundleSetMinimumLogicalFontSize(m_bundle, m_pageGroup, 9); |
| 501 | WKBundleSetSpatialNavigationEnabled(m_bundle, m_pageGroup, false); |
| 502 | WKBundleSetAllowFileAccessFromFileURLs(m_bundle, m_pageGroup, true); |
| 503 | WKBundleSetPopupBlockingEnabled(m_bundle, m_pageGroup, false); |
| 504 | WKBundleSetAllowStorageAccessFromFileURLS(m_bundle, m_pageGroup, false); |
| 505 | |
| 506 | #if PLATFORM(IOS_FAMILY) |
| 507 | WKBundlePageSetUseTestingViewportConfiguration(page()->page(), !booleanForKey(settings, "UseFlexibleViewport" )); |
| 508 | #endif |
| 509 | |
| 510 | #if PLATFORM(COCOA) |
| 511 | WebCoreTestSupport::setAdditionalSupportedImageTypesForTesting(stringForKey(settings, "additionalSupportedImageTypes" )); |
| 512 | #endif |
| 513 | |
| 514 | m_testRunner->setPluginsEnabled(true); |
| 515 | |
| 516 | m_testRunner->setUserStyleSheetEnabled(false); |
| 517 | m_testRunner->setXSSAuditorEnabled(false); |
| 518 | |
| 519 | m_testRunner->setWebGL2Enabled(true); |
| 520 | |
| 521 | m_testRunner->setWritableStreamAPIEnabled(true); |
| 522 | m_testRunner->setReadableByteStreamAPIEnabled(true); |
| 523 | |
| 524 | m_testRunner->setEncryptedMediaAPIEnabled(true); |
| 525 | |
| 526 | m_testRunner->setCloseRemainingWindowsWhenComplete(false); |
| 527 | m_testRunner->setAcceptsEditing(true); |
| 528 | m_testRunner->setTabKeyCyclesThroughElements(true); |
| 529 | m_testRunner->clearTestRunnerCallbacks(); |
| 530 | |
| 531 | if (m_timeout > 0_s) |
| 532 | m_testRunner->setCustomTimeout(m_timeout); |
| 533 | |
| 534 | page()->prepare(); |
| 535 | |
| 536 | if (testingMode != BegingTestingMode::New) |
| 537 | return; |
| 538 | |
| 539 | WKBundleClearAllDatabases(m_bundle); |
| 540 | WKBundlePageClearApplicationCache(page()->page()); |
| 541 | WKBundleResetOriginAccessWhitelists(m_bundle); |
| 542 | WKBundleClearResourceLoadStatistics(m_bundle); |
| 543 | |
| 544 | // [WK2] REGRESSION(r128623): It made layout tests extremely slow |
| 545 | // https://bugs.webkit.org/show_bug.cgi?id=96862 |
| 546 | // WKBundleSetDatabaseQuota(m_bundle, 5 * 1024 * 1024); |
| 547 | } |
| 548 | |
| 549 | void InjectedBundle::done() |
| 550 | { |
| 551 | m_state = Stopping; |
| 552 | |
| 553 | m_useWorkQueue = false; |
| 554 | |
| 555 | page()->stopLoading(); |
| 556 | setTopLoadingFrame(0); |
| 557 | |
| 558 | #if HAVE(ACCESSIBILITY) |
| 559 | m_accessibilityController->resetToConsistentState(); |
| 560 | #endif |
| 561 | |
| 562 | WKRetainPtr<WKStringRef> doneMessageName = adoptWK(WKStringCreateWithUTF8CString("Done" )); |
| 563 | WKRetainPtr<WKMutableDictionaryRef> doneMessageBody = adoptWK(WKMutableDictionaryCreate()); |
| 564 | |
| 565 | WKRetainPtr<WKStringRef> pixelResultIsPendingKey = adoptWK(WKStringCreateWithUTF8CString("PixelResultIsPending" )); |
| 566 | WKRetainPtr<WKBooleanRef> pixelResultIsPending = adoptWK(WKBooleanCreate(m_pixelResultIsPending)); |
| 567 | WKDictionarySetItem(doneMessageBody.get(), pixelResultIsPendingKey.get(), pixelResultIsPending.get()); |
| 568 | |
| 569 | if (!m_pixelResultIsPending) { |
| 570 | WKRetainPtr<WKStringRef> pixelResultKey = adoptWK(WKStringCreateWithUTF8CString("PixelResult" )); |
| 571 | WKDictionarySetItem(doneMessageBody.get(), pixelResultKey.get(), m_pixelResult.get()); |
| 572 | } |
| 573 | |
| 574 | WKRetainPtr<WKStringRef> repaintRectsKey = adoptWK(WKStringCreateWithUTF8CString("RepaintRects" )); |
| 575 | WKDictionarySetItem(doneMessageBody.get(), repaintRectsKey.get(), m_repaintRects.get()); |
| 576 | |
| 577 | WKRetainPtr<WKStringRef> audioResultKey = adoptWK(WKStringCreateWithUTF8CString("AudioResult" )); |
| 578 | WKDictionarySetItem(doneMessageBody.get(), audioResultKey.get(), m_audioResult.get()); |
| 579 | |
| 580 | WKBundlePagePostMessageIgnoringFullySynchronousMode(page()->page(), doneMessageName.get(), doneMessageBody.get()); |
| 581 | |
| 582 | closeOtherPages(); |
| 583 | |
| 584 | m_state = Idle; |
| 585 | } |
| 586 | |
| 587 | void InjectedBundle::closeOtherPages() |
| 588 | { |
| 589 | Vector<WKBundlePageRef> pagesToClose; |
| 590 | size_t size = m_pages.size(); |
| 591 | for (size_t i = 1; i < size; ++i) |
| 592 | pagesToClose.append(m_pages[i]->page()); |
| 593 | size = pagesToClose.size(); |
| 594 | for (size_t i = 0; i < size; ++i) |
| 595 | WKBundlePageClose(pagesToClose[i]); |
| 596 | } |
| 597 | |
| 598 | void InjectedBundle::dumpBackForwardListsForAllPages(StringBuilder& stringBuilder) |
| 599 | { |
| 600 | size_t size = m_pages.size(); |
| 601 | for (size_t i = 0; i < size; ++i) |
| 602 | stringBuilder.append(m_pages[i]->dumpHistory()); |
| 603 | } |
| 604 | |
| 605 | void InjectedBundle::dumpToStdErr(const String& output) |
| 606 | { |
| 607 | if (m_state != Testing) |
| 608 | return; |
| 609 | if (output.isEmpty()) |
| 610 | return; |
| 611 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("DumpToStdErr" )); |
| 612 | WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithUTF8CString(output.utf8().data())); |
| 613 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 614 | } |
| 615 | |
| 616 | void InjectedBundle::outputText(const String& output) |
| 617 | { |
| 618 | if (m_state != Testing) |
| 619 | return; |
| 620 | if (output.isEmpty()) |
| 621 | return; |
| 622 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("TextOutput" )); |
| 623 | WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithUTF8CString(output.utf8().data())); |
| 624 | // We use WKBundlePagePostMessageIgnoringFullySynchronousMode() instead of WKBundlePagePostMessage() to make sure that all text output |
| 625 | // is done via asynchronous IPC, even if the connection is in fully synchronous mode due to a WKBundlePagePostSynchronousMessageForTesting() |
| 626 | // call. Otherwise, messages logged via sync and async IPC may end up out of order and cause flakiness. |
| 627 | WKBundlePagePostMessageIgnoringFullySynchronousMode(page()->page(), messageName.get(), messageBody.get()); |
| 628 | } |
| 629 | |
| 630 | void InjectedBundle::postNewBeforeUnloadReturnValue(bool value) |
| 631 | { |
| 632 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("BeforeUnloadReturnValue" )); |
| 633 | WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(value)); |
| 634 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 635 | } |
| 636 | |
| 637 | void InjectedBundle::postAddChromeInputField() |
| 638 | { |
| 639 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("AddChromeInputField" )); |
| 640 | WKBundlePagePostMessage(page()->page(), messageName.get(), 0); |
| 641 | } |
| 642 | |
| 643 | void InjectedBundle::postRemoveChromeInputField() |
| 644 | { |
| 645 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("RemoveChromeInputField" )); |
| 646 | WKBundlePagePostMessage(page()->page(), messageName.get(), 0); |
| 647 | } |
| 648 | |
| 649 | void InjectedBundle::postFocusWebView() |
| 650 | { |
| 651 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("FocusWebView" )); |
| 652 | WKBundlePagePostMessage(page()->page(), messageName.get(), 0); |
| 653 | } |
| 654 | |
| 655 | void InjectedBundle::postSetBackingScaleFactor(double backingScaleFactor) |
| 656 | { |
| 657 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetBackingScaleFactor" )); |
| 658 | WKRetainPtr<WKDoubleRef> messageBody = adoptWK(WKDoubleCreate(backingScaleFactor)); |
| 659 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 660 | } |
| 661 | |
| 662 | void InjectedBundle::postSetWindowIsKey(bool isKey) |
| 663 | { |
| 664 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetWindowIsKey" )); |
| 665 | WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(isKey)); |
| 666 | WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), 0); |
| 667 | } |
| 668 | |
| 669 | void InjectedBundle::postSetViewSize(double width, double height) |
| 670 | { |
| 671 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetViewSize" )); |
| 672 | |
| 673 | WKRetainPtr<WKStringRef> widthKey = adoptWK(WKStringCreateWithUTF8CString("width" )); |
| 674 | WKRetainPtr<WKStringRef> heightKey = adoptWK(WKStringCreateWithUTF8CString("height" )); |
| 675 | |
| 676 | WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate()); |
| 677 | |
| 678 | WKRetainPtr<WKDoubleRef> widthWK = adoptWK(WKDoubleCreate(width)); |
| 679 | WKDictionarySetItem(messageBody.get(), widthKey.get(), widthWK.get()); |
| 680 | |
| 681 | WKRetainPtr<WKDoubleRef> heightWK = adoptWK(WKDoubleCreate(height)); |
| 682 | WKDictionarySetItem(messageBody.get(), heightKey.get(), heightWK.get()); |
| 683 | |
| 684 | WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), 0); |
| 685 | } |
| 686 | |
| 687 | void InjectedBundle::postSimulateWebNotificationClick(uint64_t notificationID) |
| 688 | { |
| 689 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SimulateWebNotificationClick" )); |
| 690 | WKRetainPtr<WKUInt64Ref> messageBody = adoptWK(WKUInt64Create(notificationID)); |
| 691 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 692 | } |
| 693 | |
| 694 | void InjectedBundle::postSetAddsVisitedLinks(bool addsVisitedLinks) |
| 695 | { |
| 696 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetAddsVisitedLinks" )); |
| 697 | WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(addsVisitedLinks)); |
| 698 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 699 | } |
| 700 | |
| 701 | void InjectedBundle::setGeolocationPermission(bool enabled) |
| 702 | { |
| 703 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetGeolocationPermission" )); |
| 704 | WKRetainPtr<WKBooleanRef> messageBody = adoptWK(WKBooleanCreate(enabled)); |
| 705 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 706 | } |
| 707 | |
| 708 | void InjectedBundle::setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed, bool providesFloorLevel, double floorLevel) |
| 709 | { |
| 710 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGeolocationPosition" )); |
| 711 | |
| 712 | WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate()); |
| 713 | |
| 714 | WKRetainPtr<WKStringRef> latitudeKeyWK = adoptWK(WKStringCreateWithUTF8CString("latitude" )); |
| 715 | WKRetainPtr<WKDoubleRef> latitudeWK = adoptWK(WKDoubleCreate(latitude)); |
| 716 | WKDictionarySetItem(messageBody.get(), latitudeKeyWK.get(), latitudeWK.get()); |
| 717 | |
| 718 | WKRetainPtr<WKStringRef> longitudeKeyWK = adoptWK(WKStringCreateWithUTF8CString("longitude" )); |
| 719 | WKRetainPtr<WKDoubleRef> longitudeWK = adoptWK(WKDoubleCreate(longitude)); |
| 720 | WKDictionarySetItem(messageBody.get(), longitudeKeyWK.get(), longitudeWK.get()); |
| 721 | |
| 722 | WKRetainPtr<WKStringRef> accuracyKeyWK = adoptWK(WKStringCreateWithUTF8CString("accuracy" )); |
| 723 | WKRetainPtr<WKDoubleRef> accuracyWK = adoptWK(WKDoubleCreate(accuracy)); |
| 724 | WKDictionarySetItem(messageBody.get(), accuracyKeyWK.get(), accuracyWK.get()); |
| 725 | |
| 726 | WKRetainPtr<WKStringRef> providesAltitudeKeyWK = adoptWK(WKStringCreateWithUTF8CString("providesAltitude" )); |
| 727 | WKRetainPtr<WKBooleanRef> providesAltitudeWK = adoptWK(WKBooleanCreate(providesAltitude)); |
| 728 | WKDictionarySetItem(messageBody.get(), providesAltitudeKeyWK.get(), providesAltitudeWK.get()); |
| 729 | |
| 730 | WKRetainPtr<WKStringRef> altitudeKeyWK = adoptWK(WKStringCreateWithUTF8CString("altitude" )); |
| 731 | WKRetainPtr<WKDoubleRef> altitudeWK = adoptWK(WKDoubleCreate(altitude)); |
| 732 | WKDictionarySetItem(messageBody.get(), altitudeKeyWK.get(), altitudeWK.get()); |
| 733 | |
| 734 | WKRetainPtr<WKStringRef> providesAltitudeAccuracyKeyWK = adoptWK(WKStringCreateWithUTF8CString("providesAltitudeAccuracy" )); |
| 735 | WKRetainPtr<WKBooleanRef> providesAltitudeAccuracyWK = adoptWK(WKBooleanCreate(providesAltitudeAccuracy)); |
| 736 | WKDictionarySetItem(messageBody.get(), providesAltitudeAccuracyKeyWK.get(), providesAltitudeAccuracyWK.get()); |
| 737 | |
| 738 | WKRetainPtr<WKStringRef> altitudeAccuracyKeyWK = adoptWK(WKStringCreateWithUTF8CString("altitudeAccuracy" )); |
| 739 | WKRetainPtr<WKDoubleRef> altitudeAccuracyWK = adoptWK(WKDoubleCreate(altitudeAccuracy)); |
| 740 | WKDictionarySetItem(messageBody.get(), altitudeAccuracyKeyWK.get(), altitudeAccuracyWK.get()); |
| 741 | |
| 742 | WKRetainPtr<WKStringRef> providesHeadingKeyWK = adoptWK(WKStringCreateWithUTF8CString("providesHeading" )); |
| 743 | WKRetainPtr<WKBooleanRef> providesHeadingWK = adoptWK(WKBooleanCreate(providesHeading)); |
| 744 | WKDictionarySetItem(messageBody.get(), providesHeadingKeyWK.get(), providesHeadingWK.get()); |
| 745 | |
| 746 | WKRetainPtr<WKStringRef> headingKeyWK = adoptWK(WKStringCreateWithUTF8CString("heading" )); |
| 747 | WKRetainPtr<WKDoubleRef> headingWK = adoptWK(WKDoubleCreate(heading)); |
| 748 | WKDictionarySetItem(messageBody.get(), headingKeyWK.get(), headingWK.get()); |
| 749 | |
| 750 | WKRetainPtr<WKStringRef> providesSpeedKeyWK = adoptWK(WKStringCreateWithUTF8CString("providesSpeed" )); |
| 751 | WKRetainPtr<WKBooleanRef> providesSpeedWK = adoptWK(WKBooleanCreate(providesSpeed)); |
| 752 | WKDictionarySetItem(messageBody.get(), providesSpeedKeyWK.get(), providesSpeedWK.get()); |
| 753 | |
| 754 | WKRetainPtr<WKStringRef> speedKeyWK = adoptWK(WKStringCreateWithUTF8CString("speed" )); |
| 755 | WKRetainPtr<WKDoubleRef> speedWK = adoptWK(WKDoubleCreate(speed)); |
| 756 | WKDictionarySetItem(messageBody.get(), speedKeyWK.get(), speedWK.get()); |
| 757 | |
| 758 | WKRetainPtr<WKStringRef> providesFloorLevelKeyWK = adoptWK(WKStringCreateWithUTF8CString("providesFloorLevel" )); |
| 759 | WKRetainPtr<WKBooleanRef> providesFloorLevelWK = adoptWK(WKBooleanCreate(providesFloorLevel)); |
| 760 | WKDictionarySetItem(messageBody.get(), providesFloorLevelKeyWK.get(), providesFloorLevelWK.get()); |
| 761 | |
| 762 | WKRetainPtr<WKStringRef> floorLevelKeyWK = adoptWK(WKStringCreateWithUTF8CString("floorLevel" )); |
| 763 | WKRetainPtr<WKDoubleRef> floorLevelWK = adoptWK(WKDoubleCreate(floorLevel)); |
| 764 | WKDictionarySetItem(messageBody.get(), floorLevelKeyWK.get(), floorLevelWK.get()); |
| 765 | |
| 766 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 767 | } |
| 768 | |
| 769 | void InjectedBundle::setMockGeolocationPositionUnavailableError(WKStringRef errorMessage) |
| 770 | { |
| 771 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetMockGeolocationPositionUnavailableError" )); |
| 772 | WKBundlePagePostMessage(page()->page(), messageName.get(), errorMessage); |
| 773 | } |
| 774 | |
| 775 | bool InjectedBundle::isGeolocationProviderActive() const |
| 776 | { |
| 777 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsGeolocationClientActive" )); |
| 778 | WKTypeRef resultToPass = 0; |
| 779 | WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass); |
| 780 | WKRetainPtr<WKBooleanRef> isActive = adoptWK(static_cast<WKBooleanRef>(resultToPass)); |
| 781 | |
| 782 | return WKBooleanGetValue(isActive.get()); |
| 783 | } |
| 784 | |
| 785 | unsigned InjectedBundle::imageCountInGeneralPasteboard() const |
| 786 | { |
| 787 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ImageCountInGeneralPasteboard" )); |
| 788 | WKTypeRef resultToPass = 0; |
| 789 | WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass); |
| 790 | WKRetainPtr<WKUInt64Ref> imageCount = adoptWK(static_cast<WKUInt64Ref>(resultToPass)); |
| 791 | |
| 792 | return static_cast<unsigned>(WKUInt64GetValue(imageCount.get())); |
| 793 | } |
| 794 | |
| 795 | void InjectedBundle::setUserMediaPermission(bool enabled) |
| 796 | { |
| 797 | auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetUserMediaPermission" )); |
| 798 | auto messageBody = adoptWK(WKBooleanCreate(enabled)); |
| 799 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 800 | } |
| 801 | |
| 802 | void InjectedBundle::resetUserMediaPermission() |
| 803 | { |
| 804 | auto messageName = adoptWK(WKStringCreateWithUTF8CString("ResetUserMediaPermission" )); |
| 805 | WKBundlePagePostMessage(page()->page(), messageName.get(), 0); |
| 806 | } |
| 807 | |
| 808 | void InjectedBundle::setUserMediaPersistentPermissionForOrigin(bool permission, WKStringRef origin, WKStringRef parentOrigin) |
| 809 | { |
| 810 | auto messageName = adoptWK(WKStringCreateWithUTF8CString("SetUserMediaPersistentPermissionForOrigin" )); |
| 811 | WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate()); |
| 812 | |
| 813 | WKRetainPtr<WKStringRef> permissionKeyWK = adoptWK(WKStringCreateWithUTF8CString("permission" )); |
| 814 | WKRetainPtr<WKBooleanRef> permissionWK = adoptWK(WKBooleanCreate(permission)); |
| 815 | WKDictionarySetItem(messageBody.get(), permissionKeyWK.get(), permissionWK.get()); |
| 816 | |
| 817 | WKRetainPtr<WKStringRef> originKeyWK = adoptWK(WKStringCreateWithUTF8CString("origin" )); |
| 818 | WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin); |
| 819 | |
| 820 | WKRetainPtr<WKStringRef> parentOriginKeyWK = adoptWK(WKStringCreateWithUTF8CString("parentOrigin" )); |
| 821 | WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin); |
| 822 | |
| 823 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 824 | } |
| 825 | |
| 826 | unsigned InjectedBundle::userMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin) const |
| 827 | { |
| 828 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("UserMediaPermissionRequestCountForOrigin" )); |
| 829 | WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate()); |
| 830 | |
| 831 | WKRetainPtr<WKStringRef> originKeyWK = adoptWK(WKStringCreateWithUTF8CString("origin" )); |
| 832 | WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin); |
| 833 | |
| 834 | WKRetainPtr<WKStringRef> parentOriginKeyWK = adoptWK(WKStringCreateWithUTF8CString("parentOrigin" )); |
| 835 | WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin); |
| 836 | |
| 837 | WKTypeRef resultToPass = 0; |
| 838 | WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), messageBody.get(), &resultToPass); |
| 839 | WKRetainPtr<WKUInt64Ref> count = adoptWK(static_cast<WKUInt64Ref>(resultToPass)); |
| 840 | |
| 841 | return static_cast<unsigned>(WKUInt64GetValue(count.get())); |
| 842 | } |
| 843 | |
| 844 | void InjectedBundle::resetUserMediaPermissionRequestCountForOrigin(WKStringRef origin, WKStringRef parentOrigin) |
| 845 | { |
| 846 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ResetUserMediaPermissionRequestCountForOrigin" )); |
| 847 | WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate()); |
| 848 | |
| 849 | WKRetainPtr<WKStringRef> originKeyWK = adoptWK(WKStringCreateWithUTF8CString("origin" )); |
| 850 | WKDictionarySetItem(messageBody.get(), originKeyWK.get(), origin); |
| 851 | |
| 852 | WKRetainPtr<WKStringRef> parentOriginKeyWK = adoptWK(WKStringCreateWithUTF8CString("parentOrigin" )); |
| 853 | WKDictionarySetItem(messageBody.get(), parentOriginKeyWK.get(), parentOrigin); |
| 854 | |
| 855 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 856 | } |
| 857 | |
| 858 | void InjectedBundle::setCustomPolicyDelegate(bool enabled, bool permissive) |
| 859 | { |
| 860 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetCustomPolicyDelegate" )); |
| 861 | |
| 862 | WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate()); |
| 863 | |
| 864 | WKRetainPtr<WKStringRef> enabledKeyWK = adoptWK(WKStringCreateWithUTF8CString("enabled" )); |
| 865 | WKRetainPtr<WKBooleanRef> enabledWK = adoptWK(WKBooleanCreate(enabled)); |
| 866 | WKDictionarySetItem(messageBody.get(), enabledKeyWK.get(), enabledWK.get()); |
| 867 | |
| 868 | WKRetainPtr<WKStringRef> permissiveKeyWK = adoptWK(WKStringCreateWithUTF8CString("permissive" )); |
| 869 | WKRetainPtr<WKBooleanRef> permissiveWK = adoptWK(WKBooleanCreate(permissive)); |
| 870 | WKDictionarySetItem(messageBody.get(), permissiveKeyWK.get(), permissiveWK.get()); |
| 871 | |
| 872 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 873 | } |
| 874 | |
| 875 | void InjectedBundle::setHidden(bool hidden) |
| 876 | { |
| 877 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetHidden" )); |
| 878 | WKRetainPtr<WKMutableDictionaryRef> messageBody = adoptWK(WKMutableDictionaryCreate()); |
| 879 | |
| 880 | WKRetainPtr<WKStringRef> isInitialKeyWK = adoptWK(WKStringCreateWithUTF8CString("hidden" )); |
| 881 | WKRetainPtr<WKBooleanRef> isInitialWK = adoptWK(WKBooleanCreate(hidden)); |
| 882 | WKDictionarySetItem(messageBody.get(), isInitialKeyWK.get(), isInitialWK.get()); |
| 883 | |
| 884 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 885 | } |
| 886 | |
| 887 | void InjectedBundle::setCacheModel(int model) |
| 888 | { |
| 889 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("SetCacheModel" )); |
| 890 | WKRetainPtr<WKUInt64Ref> messageBody = adoptWK(WKUInt64Create(model)); |
| 891 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 892 | } |
| 893 | |
| 894 | bool InjectedBundle::shouldProcessWorkQueue() const |
| 895 | { |
| 896 | if (!m_useWorkQueue) |
| 897 | return false; |
| 898 | |
| 899 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("IsWorkQueueEmpty" )); |
| 900 | WKTypeRef resultToPass = 0; |
| 901 | WKBundlePagePostSynchronousMessageForTesting(page()->page(), messageName.get(), 0, &resultToPass); |
| 902 | WKRetainPtr<WKBooleanRef> isEmpty = adoptWK(static_cast<WKBooleanRef>(resultToPass)); |
| 903 | |
| 904 | // The IPC failed. This happens when swapping processes on navigation because the WebPageProxy unregisters itself |
| 905 | // as a MessageReceiver from the old WebProcessProxy and register itself with the new WebProcessProxy instead. |
| 906 | if (!isEmpty) |
| 907 | return false; |
| 908 | |
| 909 | return !WKBooleanGetValue(isEmpty.get()); |
| 910 | } |
| 911 | |
| 912 | void InjectedBundle::processWorkQueue() |
| 913 | { |
| 914 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ProcessWorkQueue" )); |
| 915 | WKBundlePagePostMessage(page()->page(), messageName.get(), 0); |
| 916 | } |
| 917 | |
| 918 | void InjectedBundle::queueBackNavigation(unsigned howFarBackward) |
| 919 | { |
| 920 | m_useWorkQueue = true; |
| 921 | |
| 922 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("QueueBackNavigation" )); |
| 923 | WKRetainPtr<WKUInt64Ref> messageBody = adoptWK(WKUInt64Create(howFarBackward)); |
| 924 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 925 | } |
| 926 | |
| 927 | void InjectedBundle::queueForwardNavigation(unsigned howFarForward) |
| 928 | { |
| 929 | m_useWorkQueue = true; |
| 930 | |
| 931 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("QueueForwardNavigation" )); |
| 932 | WKRetainPtr<WKUInt64Ref> messageBody = adoptWK(WKUInt64Create(howFarForward)); |
| 933 | WKBundlePagePostMessage(page()->page(), messageName.get(), messageBody.get()); |
| 934 | } |
| 935 | |
| 936 | void InjectedBundle::queueLoad(WKStringRef url, WKStringRef target, bool shouldOpenExternalURLs) |
| 937 | { |
| 938 | m_useWorkQueue = true; |
| 939 | |
| 940 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("QueueLoad" )); |
| 941 | |
| 942 | WKRetainPtr<WKMutableDictionaryRef> loadData = adoptWK(WKMutableDictionaryCreate()); |
| 943 | |
| 944 | WKRetainPtr<WKStringRef> urlKey = adoptWK(WKStringCreateWithUTF8CString("url" )); |
| 945 | WKDictionarySetItem(loadData.get(), urlKey.get(), url); |
| 946 | |
| 947 | WKRetainPtr<WKStringRef> targetKey = adoptWK(WKStringCreateWithUTF8CString("target" )); |
| 948 | WKDictionarySetItem(loadData.get(), targetKey.get(), target); |
| 949 | |
| 950 | WKRetainPtr<WKStringRef> shouldOpenExternalURLsKey = adoptWK(WKStringCreateWithUTF8CString("shouldOpenExternalURLs" )); |
| 951 | WKRetainPtr<WKBooleanRef> shouldOpenExternalURLsValue = adoptWK(WKBooleanCreate(shouldOpenExternalURLs)); |
| 952 | WKDictionarySetItem(loadData.get(), shouldOpenExternalURLsKey.get(), shouldOpenExternalURLsValue.get()); |
| 953 | |
| 954 | WKBundlePagePostMessage(page()->page(), messageName.get(), loadData.get()); |
| 955 | } |
| 956 | |
| 957 | void InjectedBundle::queueLoadHTMLString(WKStringRef content, WKStringRef baseURL, WKStringRef unreachableURL) |
| 958 | { |
| 959 | m_useWorkQueue = true; |
| 960 | |
| 961 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("QueueLoadHTMLString" )); |
| 962 | |
| 963 | WKRetainPtr<WKMutableDictionaryRef> loadData = adoptWK(WKMutableDictionaryCreate()); |
| 964 | |
| 965 | WKRetainPtr<WKStringRef> contentKey = adoptWK(WKStringCreateWithUTF8CString("content" )); |
| 966 | WKDictionarySetItem(loadData.get(), contentKey.get(), content); |
| 967 | |
| 968 | if (baseURL) { |
| 969 | WKRetainPtr<WKStringRef> baseURLKey = adoptWK(WKStringCreateWithUTF8CString("baseURL" )); |
| 970 | WKDictionarySetItem(loadData.get(), baseURLKey.get(), baseURL); |
| 971 | } |
| 972 | |
| 973 | if (unreachableURL) { |
| 974 | WKRetainPtr<WKStringRef> unreachableURLKey = adoptWK(WKStringCreateWithUTF8CString("unreachableURL" )); |
| 975 | WKDictionarySetItem(loadData.get(), unreachableURLKey.get(), unreachableURL); |
| 976 | } |
| 977 | |
| 978 | WKBundlePagePostMessage(page()->page(), messageName.get(), loadData.get()); |
| 979 | } |
| 980 | |
| 981 | void InjectedBundle::queueReload() |
| 982 | { |
| 983 | m_useWorkQueue = true; |
| 984 | |
| 985 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("QueueReload" )); |
| 986 | WKBundlePagePostMessage(page()->page(), messageName.get(), 0); |
| 987 | } |
| 988 | |
| 989 | void InjectedBundle::queueLoadingScript(WKStringRef script) |
| 990 | { |
| 991 | m_useWorkQueue = true; |
| 992 | |
| 993 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("QueueLoadingScript" )); |
| 994 | WKBundlePagePostMessage(page()->page(), messageName.get(), script); |
| 995 | } |
| 996 | |
| 997 | void InjectedBundle::queueNonLoadingScript(WKStringRef script) |
| 998 | { |
| 999 | m_useWorkQueue = true; |
| 1000 | |
| 1001 | WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("QueueNonLoadingScript" )); |
| 1002 | WKBundlePagePostMessage(page()->page(), messageName.get(), script); |
| 1003 | } |
| 1004 | |
| 1005 | bool InjectedBundle::isAllowedHost(WKStringRef host) |
| 1006 | { |
| 1007 | if (m_allowedHosts.isEmpty()) |
| 1008 | return false; |
| 1009 | return m_allowedHosts.contains(toWTFString(host)); |
| 1010 | } |
| 1011 | |
| 1012 | void InjectedBundle::setAllowsAnySSLCertificate(bool allowsAnySSLCertificate) |
| 1013 | { |
| 1014 | WebCoreTestSupport::setAllowsAnySSLCertificate(allowsAnySSLCertificate); |
| 1015 | } |
| 1016 | |
| 1017 | void InjectedBundle::statisticsNotifyObserver() |
| 1018 | { |
| 1019 | WKBundleResourceLoadStatisticsNotifyObserver(m_bundle); |
| 1020 | } |
| 1021 | |
| 1022 | void InjectedBundle::textDidChangeInTextField() |
| 1023 | { |
| 1024 | m_testRunner->textDidChangeInTextFieldCallback(); |
| 1025 | } |
| 1026 | |
| 1027 | void InjectedBundle::textFieldDidBeginEditing() |
| 1028 | { |
| 1029 | m_testRunner->textFieldDidBeginEditingCallback(); |
| 1030 | } |
| 1031 | |
| 1032 | void InjectedBundle::textFieldDidEndEditing() |
| 1033 | { |
| 1034 | m_testRunner->textFieldDidEndEditingCallback(); |
| 1035 | } |
| 1036 | |
| 1037 | } // namespace WTR |
| 1038 | |